diff options
Diffstat (limited to 'packages/meshbay-common')
| -rw-r--r-- | packages/meshbay-common/src/meshbay_common/groupbox.py | 5 | ||||
| -rw-r--r-- | packages/meshbay-common/src/meshbay_common/protocol.py | 8 |
2 files changed, 13 insertions, 0 deletions
diff --git a/packages/meshbay-common/src/meshbay_common/groupbox.py b/packages/meshbay-common/src/meshbay_common/groupbox.py index e020ed8..3b45dba 100644 --- a/packages/meshbay-common/src/meshbay_common/groupbox.py +++ b/packages/meshbay-common/src/meshbay_common/groupbox.py @@ -54,6 +54,10 @@ PURPOSE_UPLOAD = "upload" # the chat archive is encrypted under; this is only how they travel, which is # why rotating the group key costs a re-wrap and not a re-encryption. PURPOSE_CHAT_KEYS = "chat_keys" +# The group's roster of members and their device keys, on its way to a member. +# Sealed for the same reason the index is: it is the group's membership, and a +# peer that has not completed the handshake has no business reading it. +PURPOSE_ROSTER = "roster" # `salt=None` here and `salt: new Uint8Array(0)` in crypto.js agree — RFC 5869 # extracts with a zero key either way. Already proven in production by @@ -63,6 +67,7 @@ _INFO = { PURPOSE_ACK: b"meshbay:ack:v1", PURPOSE_UPLOAD: b"meshbay:upload:v1", PURPOSE_CHAT_KEYS: b"meshbay:chat_keys:v1", + PURPOSE_ROSTER: b"meshbay:roster:v1", } # One subkey per purpose, and `seal` draws a fresh 96-bit nonce per message, so diff --git a/packages/meshbay-common/src/meshbay_common/protocol.py b/packages/meshbay-common/src/meshbay_common/protocol.py index cc5324a..e092353 100644 --- a/packages/meshbay-common/src/meshbay_common/protocol.py +++ b/packages/meshbay-common/src/meshbay_common/protocol.py @@ -241,6 +241,14 @@ class MNP: ROOT_EJECT_ACK = "root_eject_ack" ROOT_PLUG = "root_plug" # operator → node: re-enable an ejected root ROOT_PLUG_ACK = "root_plug_ack" + # Member → node: who is in this group and which device keys they hold, with + # the countersignature that admitted each one. Distinct from ROSTER_READ + # below, which is the operator's view of the whole node: this is scoped to + # one group and answers any member of it, because the point is that a member + # verifies another member's device *for themselves* rather than trusting the + # node's `sender_id` (Tier 2, docs/desktop-client-v1.md §4.8). + GROUP_ROSTER_REQ = "group_roster_req" + GROUP_ROSTER_RESP = "group_roster_resp" ROSTER_READ = "roster_read" # operator → node: list pinned identities + members ROSTER_READ_ACK = "roster_read_ack" DENYLIST_READ = "denylist_read" # operator → node: show denylist entries |