aboutsummaryrefslogtreecommitdiffstats
path: root/docs/MESHBAY_DESIGN.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/MESHBAY_DESIGN.md')
-rw-r--r--docs/MESHBAY_DESIGN.md24
1 files changed, 17 insertions, 7 deletions
diff --git a/docs/MESHBAY_DESIGN.md b/docs/MESHBAY_DESIGN.md
index 6daa778..07aef05 100644
--- a/docs/MESHBAY_DESIGN.md
+++ b/docs/MESHBAY_DESIGN.md
@@ -16,7 +16,7 @@
> them — it names the invariant that holds today, not the incident that produced
> it. §13 is the register of those labels.
>
-> Wire versions at the time of writing: **MNP 4.0** (oldest peer accepted 4.0),
+> Wire versions at the time of writing: **MNP 5.0** (oldest peer accepted 4.0),
> **MHP 0.1**, packages **0.16.0**. The normative source for the wire format is
> `MESHBAY_NODE_PROTOCOL.md`; this document states the design the protocol
> serves, not its byte layout.
@@ -99,7 +99,7 @@ opens them.
│ └─────────┘
MHP 0.1 │ signalling (SDP/ICE, <1 KB), presence, revocation push MHP
│
- ┌────┴────┐ MNP 4.0 ┌──────────┐
+ ┌────┴────┐ MNP 5.0 ┌──────────┐
│ node │◄──────── WebRTC DataChannel / QUIC ──────────►│ client │
└─────────┘ index, file chunks, streams, chat, admin └──────────┘
holds the files browser SPA or desktop
@@ -1070,7 +1070,15 @@ TTL 120 s. **The client reconstructs the transcript from announced fields and
refuses to sign if the operation or subject is not what the user asked for**
(**H5**) — a challenge of opaque random bytes signed blind is an unbound signing
oracle. The transcript's subject names the *outcome*, not the operation: what the
-operator is shown before signing has to be what happens.
+operator is shown before signing has to be what happens. **Every value the node acts
+on is in the subject**: the signature covers nothing else of the request, so an
+operation whose effect is several values signs all of them as canonical JSON — a
+root's path *and* whether every member may write there, a group's name *and* the
+directory it exposes — and a secret by its SHA-256, since the subject is audited.
+
+What waits for a signature is bounded: anyone authenticated can ask for a challenge,
+so a connection holds at most eight pending, each at most 64 KiB, expired ones
+dropped (**AV31**).
Verification is against `roster.operator_pks()`, rebuilt from node state, **never**
from anything in the response.
@@ -1285,10 +1293,11 @@ checks the version its peer declared and **branches on none of it**.
> which point it silently takes the other. **A field kept "just in case" is how
> the branches come back.**
-**The floor is not necessarily the current version, and MINOR additions are why.**
-It is `MNP_MIN_SUPPORTED` in `handshake.py` and it equals the last MAJOR. Today the
-two coincide at 4.0, but 3.1, 3.2, 3.3 and 3.4 were each added above the 3.0 floor
-without moving it, and the next MINOR will be added above 4.0 the same way. So a
+**The floor is not necessarily the current version, and what is added above it is why.**
+It is `MNP_MIN_SUPPORTED` in `handshake.py`, and it is the last MAJOR that had to
+refuse at the handshake: 3.1–3.4 were added above the 3.0 floor without moving it,
+and 5.0, a MAJOR confined to four signed operations that a peer across the break
+refuses to sign, sits above the 4.0 floor. So a
peer can be reachable and still not do something the current version can, and the
client has to cope with that — **by reading the peer's own answer, never by comparing
version numbers**.
@@ -3270,6 +3279,7 @@ had already been asked.
| **AV29** | **An invitation link is bounded on both halves and its mail on the sender** (§3.4, §7.3). Twenty outstanding per group on the node (bearer codes) and on the hub (tickets); and because a link mail reaches an address the hub has no relationship with, at the request of anyone who owns a group, it is counted **per sending account per day** (`mail.invite_link_daily_cap`, 10), under the recipient and instance bounds and outside the recovery reserve (`invite_link` is not a recovery purpose) |
| **AV28** | **How many node keys one account may announce is bounded** (§7.2). Each is a row plus an IP-log row under a one-year retention, so an account in a loop writes a year of storage on the operator's disk having paid only for signatures. Proof of possession (**M8**) settles whose key it is and not how many. Counted only where a row is added: re-announcing a key already held keeps working at the ceiling, or a node that reached it could never refresh its address again |
| **AV30** | **What one member's offers cost a node is bounded per account and per node, and the bound admits the heaviest ordinary account** (§7.2). Each offer makes the node allocate a peer connection. A budget of 120 per node refilled at two a second bounds a member there without touching their other nodes, and it is counted by account because a mobile carrier shares one IPv4 address among many subscribers. Pending offers are capped at 32 per account. Both refusals carry `Retry-After` and the client retries them, because a refused offer otherwise reads as a node that is down |
+| **AV31** | **What waits for a signature is bounded** (§5.4). Any authenticated member can ask for an admin challenge, since the signature is checked afterwards, and a pending challenge kept its whole request until answered — measured, 200 requests of 1 MiB held 400 MiB for the life of one connection. At most eight pending per connection, 64 KiB each, expired ones dropped |
### 13.6 Chat design findings