aboutsummaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
diff options
context:
space:
mode:
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md33
1 files changed, 31 insertions, 2 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index 0292a82..4a4175f 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -72,7 +72,12 @@ dans le bon `pyproject.toml`.
- All three packages share the same version number (released together)
### Protocol versions (independent)
-- MNP: `0.4` → bumped independently of package version
+- MNP: `1.0` → bumped independently of package version. **`handshake.py`'s
+ `MNP_MIN_SUPPORTED` is the other half**: both peers declare `v` and `v_min` on
+ the handshake and refuse each other with a code (`version_too_old` /
+ `version_too_new` / `version_unreadable`), so a mismatch is a refusal rather
+ than a field that turns up missing. Shipped with 1.0 because that flag day was
+ already being paid for; the next breaking change now costs a refusal message
- 0.2 added `PING`/`PONG` and backward chat paging (`before` / `has_more`).
Additive, so an 0.1 peer still works: it sends no `before` and is answered
with the newest page, which is what it wanted
@@ -685,7 +690,29 @@ anything that assumes one key per person.
`GroupSenderKeyStore.add_sender` currently does `self._states[dist.sender_id] = ...`,
so a second device under the same `sender_id` silently overwrites the first. Revoking a
device must rotate, like revoking a member. See `docs/devel-phases-next.md` §15.0b
-- Chat is plaintext on the wire and at rest; the index is plaintext on the WebRTC path
+- ~~Chat is plaintext on the wire and at rest; the index is plaintext on the WebRTC
+ path.~~ **The index half changed 2026-09-03 (MNP 1.0).** `index_sync`,
+ `index_delta` and the `handshake_ack` configuration payload are sealed under a
+ GEK-derived subkey (`meshbay_common/groupbox.py`, mirrored by `sealGroup`/
+ `openGroup` in `crypto.js`); only `type`, `v`, `group_id` and the ack's own
+ `node_pk`/`proof`/`sig` stay in clear, because a receiver must route and
+ **authenticate** before it would trust a decryption. Chat is unchanged and out of
+ scope by decision. Read `MESHBAY_NODE_PROTOCOL.md` §11.1a before touching either
+ message. Three things to keep straight:
+ - **The ack line is integrity, not confidentiality.** `handshake_transcript`
+ names no ack field, so `is_node_admin`, `enabled_apps`, `video_root` and the
+ rest were authenticated by the DTLS channel alone. The AEAD tag comes from a
+ key the hub does not hold
+ - **The index line is defence in depth against our own next bug**, of a class
+ already shipped twice: C1 (node HTTP API served the index on `0.0.0.0`
+ unauthenticated) and C6 (TCP accepted a bare JWT with no GEK proof). It buys
+ nothing against an observer, the hub, or a member. That is the whole claim
+ - **A payload that does not open ends the session**, never a default: an
+ unopenable `enabled_apps` reads as "the operator disabled every app" and an
+ unopenable index as "the group is empty", both indistinguishable from
+ legitimate states. `index_progress` is deliberately *not* sealed (counters
+ only, every 2 s) — the reason lives next to the code, re-read it before
+ changing it
## Known calibration TODOs
@@ -731,6 +758,8 @@ SFR residential Fedora 44 → meshbay.org OVH VPS:
| Need | Module | File |
|---|---|---|
| Chunk encryption (prod) | `meshbay_common.crypto` | `crypto.py` |
+| Sealing a payload under the GEK | `meshbay_common.groupbox` | `groupbox.py` + `sealGroup`/`openGroup` in `static/crypto.js`. `index_sync`, `index_delta`, `handshake_ack` — one envelope, purpose-separated subkeys, AAD = `"<msg_type>\|<group_id>"`. **Never reuse `chunk_key_aes` with a pseudo-file for this** |
+| MNP version range | `meshbay_common.handshake` | `MNP_MIN_SUPPORTED`, `check_version` — read by both servers and both clients |
| Key derivation from password | `meshbay_common.keyderive` | `keyderive.py` |
| Key bundle (web) | `meshbay_common.keyderive` | `keyderive.py` + `static/keyderive.js` |
| GEK wrap/unwrap (ECIES) | `meshbay_common.crypto` | `crypto.py` |