Destroy Group
This page states Destroy Group in the Developer Preview as trueseal-sync ADR-0029 decides it, with the API names of ADR-0028.
Public wording
Use this wording when describing Destroy Group to users, and claim nothing beyond it.
Destroy Group ends the group for every device that receives it. Each device that receives it passes the Destroy on to the members it knows about, deletes all group state, and starts over with a new identity. After that, no device that received it sends anything to any old device address, the stolen one included. To use TrueSeal together again, pair your devices from scratch.
What it does not do:
- It can’t recover or erase anything the stolen device already received or stored.
- It can’t force the stolen device to wipe itself.
- It doesn’t reach a device that stays offline longer than the relay’s message lifetime (30 days by default). That device keeps its old group until the user destroys or leaves it there too.
- It doesn’t complete while your device can’t reach the relay. Your device shows “destroying” until it can.
- Any current or former member can trigger it. That includes a stolen device, which can end your group, though that cuts it off from the group as well.
Authority
- Any current member may call
destroyGroup(), including a stolen device. - A receiver honours a
Revokewhose author appears in any Group Manifest it has held for this group, current or past. - A
Revokefrom a device that never appeared in a held manifest is ignored. - A hostile former member can therefore end the group. That affects availability only.
- Receivers keep the signing keys of every manifest they have held for the group until the group is wiped.
Initiator
destroyGroup()persistsdestroyingand, in the same transaction, queues oneRevokeper member of the current view in the outbox.- It drops pending
Syncsends and Pending Membership Changes without reporting them. - In
destroyingthe device sends noSync, runs no message handler and stays connected until the relay has accepted everyRevokepush. There is no timeout. - It wipes the namespace’s group state, outbox and dedup table, generates a fresh identity as the last step, and raises
statusChanged(notJoined, destroyed).
Receiver
- A valid
Revokemoves amemberorleavingdevice todestroying. - It queues a
Revoketo every member of its own view except the author, by the same rules as the initiator. - It acks the
Revoketo the relay afterdestroyingcommits (ADR-0026). - It waits and wipes as the initiator does.
Forwarding reaches members admitted concurrently and missing from the initiator’s view. Each device forwards at most once, because a device in destroying or notJoined ignores further Revokes. The worst case is about maxGroupSize × (maxGroupSize − 1) Revoke Blobs.
States
| From | Trigger | To |
|---|---|---|
member | destroyGroup() | destroying |
leaving | destroyGroup() | destroying. The leave is abandoned. |
pendingJoin | destroyGroup() | Unchanged. Fails with notMember{status}. |
destroying | destroyGroup() | Unchanged. Does nothing. |
notJoined | destroyGroup() | Unchanged. Fails with notMember{status}. |
member, leaving | A valid Revoke | destroying. Forwards the Revoke to every member of its own view except the author. |
pendingJoin | A valid Revoke | Unchanged. Ignored. There is no manifest to check the author against. |
destroying, notJoined | A valid Revoke | Unchanged. Ignored. |
destroying | The relay has accepted every queued Revoke | notJoined. The device wipes, makes a fresh identity and raises statusChanged(notJoined, destroyed). |
Crash points
- Before the
destroyingtransaction commits. No change. On a receiver, the relay redelivers the unackedRevoke. - After the commit, during the pushes.
destroyingresumes on the next start. The outbox replays theRevokes the relay hasn’t accepted. - During the wipe. The wipe restarts. It never runs against a fresh identity, because the identity is replaced last.
After the wipe
- There is no key rotation inside the session. Every surviving device is
notJoinedwith a fresh identity. - The same
TrueSealobject stays usable (ADR-0028). The user rebuilds the group by pairing again. - The stolen device can send a join request like any other device. It is admitted only if a member calls
accept(request)for it. - Replaying a
Revokefor a group that is already destroyed changes nothing, because every device has a fresh identity (ADR-0034).
Choosing Destroy Group over removal
remove(memberId) relies on the removed device cooperating. Use destroyGroup() for a lost, stolen, compromised or hostile device. See Membership.
What stays the app’s job
- Showing
destroyingwhile it lasts, and never reporting the group as gone beforestatusChanged(notJoined, destroyed). - Deleting the app’s own data after
statusChanged(notJoined, destroyed), if it should. - Telling the user to destroy or leave the group on any device that was offline past the relay TTL.
- Guiding the user through pairing again.