diff options
Diffstat (limited to 'docs/MESHBAY_DESIGN.md')
| -rw-r--r-- | docs/MESHBAY_DESIGN.md | 19 |
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 |