aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-common/src/meshbay_common/protocol.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-common/src/meshbay_common/protocol.py')
-rw-r--r--packages/meshbay-common/src/meshbay_common/protocol.py29
1 files changed, 28 insertions, 1 deletions
diff --git a/packages/meshbay-common/src/meshbay_common/protocol.py b/packages/meshbay-common/src/meshbay_common/protocol.py
index 689adbf..dfb5d56 100644
--- a/packages/meshbay-common/src/meshbay_common/protocol.py
+++ b/packages/meshbay-common/src/meshbay_common/protocol.py
@@ -38,7 +38,12 @@ class MNP:
FILE_REQUEST = "file_req" # request chunk(s)
FILE_CHUNK = "file_chunk" # encrypted chunk response
STREAM_SEGMENT = "stream_seg" # HLS/DASH segment
- CHAT_MESSAGE = "chat_msg" # Double Ratchet message
+ # Not a Double Ratchet message, and never was — `first-review.md` C1
+ # rejected exactly that for groups. Plaintext until a group turns
+ # encryption on, then AES-256-GCM under a per-device subkey of the group's
+ # chat epoch key, signed with the sending device's pinned Ed25519 key
+ # (`chatbox.py`, docs/chat-sender-keys.md).
+ CHAT_MESSAGE = "chat_msg" # one chat message, plain or sealed
CHAT_ATTACHMENT = "chat_attach" # attachment metadata
CHAT_HISTORY = "chat_hist" # request message history (newest, or before a cursor)
CHAT_HISTORY_RESPONSE = "chat_hist_resp" # history response with messages
@@ -153,6 +158,14 @@ class MNP:
DEVICE_LIST = "device_list" # anyone → node: my devices
DEVICE_LIST_RESULT = "device_list_result"
DEVICE_REVOKE = "device_revoke" # a device retires another
+ # "Which of this account's devices am I?" — signed, on an
+ # already-authenticated connection. The handshake proves the account and the
+ # group; it never proved the device, so the node attributed uploads to the
+ # account's oldest key and could not tell one device's chat from another's.
+ # Additive (MNP 1.2): a client that stays silent leaves the node exactly
+ # where it was.
+ DEVICE_HELLO = "device_hello" # device → node: this is me
+ DEVICE_HELLO_ACK = "device_hello_ack"
# Rotation is the half of revocation that revocation cannot do: the node
# generates a fresh key itself, so no key material crosses the wire.
GEK_ROTATE = "gek_rotate" # operator → node: new group key
@@ -176,6 +189,20 @@ class MNP:
CHAT_DIRECTORY_ACK = "chat_directory_ack"
CHAT_LINK_PREVIEW = "chat_link_preview"
CHAT_LINK_PREVIEW_ACK = "chat_link_preview_ack"
+ # The keys a group's chat archive is encrypted under, on their way to a
+ # member. Sealed under a group-derived subkey, so the payload carries an
+ # authentication tag from a key the hub does not hold — and a member who has
+ # not completed the handshake is served a ciphertext rather than the keys.
+ # Requested rather than pushed on the ack: a group with no chat should not
+ # pay for this on every connection.
+ CHAT_KEYS_REQ = "chat_keys_req"
+ CHAT_KEYS_RESP = "chat_keys_resp"
+ # Node → this group: a new chat epoch was opened, because somebody was
+ # removed. Not a setting — there is no switch; chat is always encrypted
+ # (MNP 2.0). Pushed so a connected client stops sealing under the retired
+ # key without having to reconnect.
+ CHAT_EPOCH = "chat_epoch"
+ CHAT_EPOCH_ACK = "chat_epoch_ack"
ROOT_UPDATE = "root_update" # operator → node: change writable/removable on a root
ROOT_UPDATE_ACK = "root_update_ack"
ROOT_EJECT = "root_eject" # operator → node: mark removable root as ejected