aboutsummaryrefslogtreecommitdiffstats
path: root/docs/MESHBAY_NODE_PROTOCOL.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/MESHBAY_NODE_PROTOCOL.md')
-rw-r--r--docs/MESHBAY_NODE_PROTOCOL.md41
1 files changed, 28 insertions, 13 deletions
diff --git a/docs/MESHBAY_NODE_PROTOCOL.md b/docs/MESHBAY_NODE_PROTOCOL.md
index 207d640..04860cd 100644
--- a/docs/MESHBAY_NODE_PROTOCOL.md
+++ b/docs/MESHBAY_NODE_PROTOCOL.md
@@ -625,20 +625,21 @@ operator's real choice (I8).
## 7. The pre-proof window
Between `handshake_challenge` and a valid `handshake_response` the peer is
-*authorized* but not *authenticated*. Three message families are served there, each
+*authorized* but not *authenticated*. Four message families are served there, each
because the peer provably cannot compute a proof without it. **Everything else is
answered `Handshake required`**: the dispatcher's authenticated branch begins
-immediately after these three, so the table below is the window, exhaustively.
+immediately after these four, so the table below is the window, exhaustively.
| Message | Why it must precede the proof | Bound |
|---|---|---|
| `keypair_bundle_fetch` | the client's own identity keys for this node live in an encrypted bundle stored on it | counts against `MAX_PRE_PROOF_FETCHES` = 4; audited |
| `gek_bundle_fetch` | the wrapped group key is what the proof is computed with | same counter |
| `join_request` | a first-time member holds no group key at all. Accepted after the proof as well — an operator pairing a browser is already connected — because its authority comes from the pairing code and the signature, never from the session state | 5 attempts per connection; wrong codes: 5 per account and 20 node-wide per 600 s, consulted only when a code is tried |
+| `device_add_request` | a new device of a known account holds no identity this node pinned, so the node wraps it no group key (§9). Inert: it admits nothing until a pinned device countersigns. Filed for the account the token names. Accepted after the proof as well | the device budget, 5 attempts per connection; 10 pending requests per account, the oldest dropped; audited |
-Device linking (§9) is **not** in this window. `device_add_request` and every message
-after it are answered only on an authenticated session, and the device budget of 5
-attempts per connection applies there.
+The rest of device linking (§9) is **not** in this window: `device_lookup`,
+`device_add`, `device_list`, `device_revoke` and `device_hello` are answered only on
+an authenticated session, by the device budget of 5 attempts per connection.
Exceeding the fetch budget is audited as `pre-proof fetch flood` and answered
`Too many requests`. Every fetch in this window is written to the audit log with the
@@ -960,9 +961,12 @@ two keys on the same node. A second device is admitted by **a key the node alrea
pinned** — never by the hub, which stores no user keys and therefore cannot countersign
anything.
-Every message in this section is answered on an **authenticated** session only (§7):
-both the device filing a request and the device approving it have completed a handshake
-on their own connection.
+The new device files its request in the **pre-proof window** (§7): it holds no
+identity the node pinned, so it cannot complete a handshake until the request is
+approved. Every other message in this section is answered on an **authenticated**
+session only — the approving device has completed a handshake on its own connection.
+Once approved, the new device's next `join_request`, with no code, is recognised and
+answered with the group key, like any pinned device's.
### 9.1 Exchange
@@ -990,6 +994,7 @@ on their own connection.
| | A recomputes sha256(code||keys)
| | for each candidate and keeps the match.
| | No match -> refuse before signing.
+ | | More than one -> refuse: approve none.
| | |
| |<--- device_add --------------|
| | {pk_ed25519, pk_x25519, |
@@ -1002,6 +1007,12 @@ on their own connection.
| | {pk_ed25519} |
```
+A request is filed with the account's token alone, before any proof (§7). So
+anyone holding the passphrase who has seen a code on D's screen can file a second
+request with that code and keys of their own, and both hashes verify. That is why
+A approves only a code that matches **exactly one** pending request; D then shows
+a new code.
+
### 9.2 Transcripts
```
@@ -1891,22 +1902,22 @@ read, and receivers include devices that were not connected when it was sent.
| |
|-- chat_msg {v, format: 1, epoch, device, |
| nonce, ct, sig, sender_name, |
- | [thread_id], [iteration]} -------------------->|
+ | [iteration]} --------------------------------->|
| | envelope checks (below)
| | persist to THIS group's store
| | broadcast ------------------->|
| | {chat_msg, sender_id,
| | sender_name, format, epoch,
| | device, nonce, ct, sig,
- | | thread_id, timestamp}
+ | | timestamp}
| | notify the hub: group id and
| | sender id only
|<- ack {v} -----------------------------------------|
|
|-- chat_hist {v, [before], [limit <= 200]} -------->|
|<- chat_hist_resp {v, has_more, messages: [{id, |
- | sender_id, sender_name, timestamp, thread_id, |
- | format, epoch, device, nonce, ct, sig}]} ------|
+ | sender_id, sender_name, timestamp, format, |
+ | epoch, device, nonce, ct, sig}]} --------------|
|
|<= chat_epoch_ack {v, epoch} =======================| pushed: a new epoch is open
```
@@ -2187,7 +2198,7 @@ message:
## 13. Versioning and compatibility
-MNP versions independently of the package version. Current: **`6.2`**; oldest peer
+MNP versions independently of the package version. Current: **`6.3`**; oldest peer
accepted: **`4.0`**.
4.0 is the floor: a member presents a short-lived node-audience token bound to one node
@@ -2217,6 +2228,10 @@ answer, as for any unknown type, and nothing else changes.
the roots table, additively: a 6.1 node gives no answer to either message, and a client
that ignores `paused` shows a paused root as an ordinary one.
+6.3 serves `device_add_request` in the pre-proof window (§7, §9), additively: a 6.2
+node answers it `Handshake required` there, which a client reads as "this node cannot
+link a new device", and nothing else changes.
+
The two numbers are separate on purpose. `MNP_VERSION` says what this build speaks;
`MNP_MIN_SUPPORTED` says what it will talk to, and moving the second is a decision about
whether an older peer can still do anything useful: