diff options
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/transport/wire.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/transport/wire.py | 54 |
1 files changed, 45 insertions, 9 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/transport/wire.py b/packages/meshbay-node/src/meshbay_node/transport/wire.py index 4e09167..c683204 100644 --- a/packages/meshbay-node/src/meshbay_node/transport/wire.py +++ b/packages/meshbay-node/src/meshbay_node/transport/wire.py @@ -14,12 +14,22 @@ consumer each and nothing asserting they matched. Same failure mode as the two `GroupIndex.serialize()`/`deserialize()` are unchanged and still tested — they remain a correct signed index envelope — but they no longer describe any MNP message. Read -them as an at-rest/interchange format, not as a wire contract. +them as an at-rest/interchange format, not as a wire contract. It is also not a +candidate for reuse below: it compresses with zstd, which no browser can decompress +(`DecompressionStream` offers gzip and deflate only). + +Since MNP 1.0 both messages carry their payload **sealed under a GEK-derived subkey** +(`meshbay_common.groupbox`). Only the routing fields — `type`, `v`, `group_id` — stay +in clear: a receiver must route and version-check before it can decrypt, and +`group_id` is the AAD and selects the key besides. `version`/`base_version` moved +*inside* the payload; there is no reason to act on a version number carried by a +message we have not yet authenticated. """ from __future__ import annotations from meshbay_common import MNP_VERSION +from meshbay_common.groupbox import PURPOSE_INDEX, seal from meshbay_common.protocol import MNP, index_entry_wire from meshbay_node.roots import RootSet @@ -60,17 +70,43 @@ def index_sync_message(index, roots: RootSet | None) -> dict: """ The full `index_sync` message for one group. - `dirs` and `roots` are here because directories are not index entries: without - them a folder someone just created, or one they emptied, does not exist as far as - a client is concerned, and a member cannot tell "the drive is unplugged" from "it - is all still there". + `dirs` and `roots` are in the payload because directories are not index entries: + without them a folder someone just created, or one they emptied, does not exist as + far as a client is concerned, and a member cannot tell "the drive is unplugged" + from "it is all still there". """ - return { - "type": MNP.INDEX_SYNC, - "v": MNP_VERSION, - "group_id": index.group_id, + payload = { "version": index.version, "entries": [index_entry_wire(e) for e in index.entries], "dirs": list_dirs(roots), "roots": roots.describe() if roots else [], } + return { + "type": MNP.INDEX_SYNC, + "v": MNP_VERSION, + "group_id": index.group_id, + **seal(index.gek, PURPOSE_INDEX, MNP.INDEX_SYNC, index.group_id, payload), + } + + +def index_delta_message(index, delta) -> dict: + """ + One `index_delta` — what changed since the last thing this node broadcast. + + Built here rather than inline in the daemon, which is where it lived and which + made it the third place an index message was constructed: precisely the drift + that produced two `index_sync` encodings and two `file_chunk` encodings before it. + """ + payload = { + "base_version": delta.base_version, + "version": delta.version, + "additions": [index_entry_wire(e) for e in delta.additions], + "deletions": list(delta.deletions), + "updates": [index_entry_wire(e) for e in delta.updates], + } + return { + "type": MNP.INDEX_DELTA, + "v": MNP_VERSION, + "group_id": index.group_id, + **seal(index.gek, PURPOSE_INDEX, MNP.INDEX_DELTA, index.group_id, payload), + } |