summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/MESHBAY_DESIGN.md19
1 files changed, 19 insertions, 0 deletions
diff --git a/docs/MESHBAY_DESIGN.md b/docs/MESHBAY_DESIGN.md
index 4147fe7..68b9fa9 100644
--- a/docs/MESHBAY_DESIGN.md
+++ b/docs/MESHBAY_DESIGN.md
@@ -1601,6 +1601,15 @@ share an active group with the target node**. Otherwise any authenticated user
could make a third party's machine allocate peer connections on demand (**H6**).
The address in a NAT-punch request must match the caller's source address.
+**A node registered for no group shares one with nobody**, and is refused rather
+than exempted. Written as "check membership if the node claims any group", the
+rule skipped itself — membership, group status and the public-group gate
+together — for precisely the node that AV1 made commonplace: the unconfigured
+one, hosting nothing, which is also the one least able to absorb the work. No
+legitimate connection is lost, because such a node refuses the handshake anyway
+(`group_id` is mandatory, **M1**, and a node holding no group key refuses,
+**NS8**); the refusal simply stops happening at the operator's expense.
+
`X-Forwarded-For` is honoured **only from a trusted proxy, rightmost hop** (**M7**),
through one helper so the behaviour is defined in one place — including for the
rate limiter, whose keying otherwise collapses to a single global bucket behind a
@@ -1624,6 +1633,14 @@ staff exempt. Public groups are the ones that cost other people something: they
appear in the directory and are brokered to strangers. The check is at creation
only, which is correct because the update endpoint refuses to change visibility.
+**Which nodes host a group is answered to its members.** For a public group that
+is everyone, which is what public means; for a private one it is the membership
+row and nothing else. Answering any authenticated account — as it did while only
+the public case was checked — hands whoever knows the group id the identities of
+the machines hosting it, and an ex-member knows that id for ever. Nothing needs
+it before joining: an open join writes the membership row first, and an
+invitation registers the invitee's when the code is created.
+
### 7.4 Instance policy
`hub_settings` is a key/value table an admin edits at runtime. It is **instance
@@ -2600,6 +2617,8 @@ had already been asked.
| **AV21** | **A lease is what the node granted, not what the client called it** (§5.5). `tr` was read as a boolean, so any non-empty string skipped the leaseless ceiling and every cap behind it, and a queued transfer was held back only by the honesty of the client waiting in the queue |
| **AV22** | **The node's own controls take no authority from a hub token** (§6.7). `node_status`, `node_settings_set`, `roster_read`, `denylist_read`, `denylist_clear` and `node_reload` were gated on the account id in the JWT, which is the hub's to choose — NS4 and M3 with the check written the other way round. The gate is a proved operator device, which a hub holding no user keys cannot produce |
| **AV23** | **An upload's owner is recorded when the upload ends and applied when the entry is created**, which are different moments (§5.4). Written against the index at the end of the upload it matched nothing, every time, and left every uploaded file owned by nobody — so no member could delete what they had sent |
+| **AV24** | **A node registered for no group is refused signaling, not exempted from it** (§7.2). The membership check was written as "if the node claims any group", so it skipped itself — membership, group status and the public-group gate together — for the node AV1 made commonplace: the unconfigured one, which is also the one least able to absorb the work |
+| **AV25** | **Which nodes host a group is answered to its members** (§7.3). Only the public case checked, so a private group told any authenticated account that knew its id which machines hosted it — and an ex-member knows that id for ever |
### 13.6 Chat design findings