summaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
diff options
context:
space:
mode:
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md23
1 files changed, 22 insertions, 1 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index b8c2646..b2ff32a 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -143,7 +143,8 @@ Scope: `hub`, `node`, `common`, or omitted for cross-cutting
- `_bundleKey` persisted in IndexedDB (CryptoKey survives page refresh)
- `_sessionKeys` persisted in sessionStorage (survives refresh, cleared on tab close)
- `_pkFromSk()`: derive X25519 public key from recovered private key via JWK export (no hub fetch)
-- Removed auto-`regenerateKeys()` on login (was silently rotating hub keys, breaking GEK unwrap)
+- `regenerateKeys()` is gone entirely (2026-08-14): identity keys are per node, so
+ rotation is `meshbay-node member unpin <user>` plus a fresh code
- Raw answer SDP saved before `setRemoteDescription` (Chrome strips sha-256 from multi-hash SDP)
- Upload chunk size: 48KB (fits aiortc SCTP limit after msgpack overhead)
@@ -212,6 +213,26 @@ See `docs/invite-pairing-v1.md`. Read it before touching invites, admin authorit
- Floor: 12 characters and ~60 estimated bits, enforced client-side only — with the
password split (T1) the hub never sees a passphrase
+## Identity keys are PER NODE (2026-08-14)
+
+See `docs/per-node-identity-v1.md`. Read it before touching registration, the
+keypair bundle, or anything that looks like a user's public key.
+
+- A keypair is created at **first contact with a node**, encrypted under the
+ passphrase, and left on that node. Never reused elsewhere. Cracking one yields
+ the identity used with that operator and nothing anywhere else
+- **The hub stores and publishes no user keys.** `users.pk_ed25519`/`pk_x25519`
+ are dropped, `PUT /me/keys` is gone, `/pubkeys` returns an account id and the
+ node linking key. Do not reintroduce a key directory — that was H3
+- **Tokens carry no `pk_user`.** The node recorded it as the uploader's identity
+ and authorized deletion against it, so whoever issued tokens decided who could
+ delete a file. Attribution uses the roster pin (`_pinned_pk`)
+- Registration generates nothing, so a scripted signup is a real account —
+ `QE/deploy/demo.py bootstrap` takes a wiped hub and node to a working demo
+- The key handed back on a join belongs to the **group of the connection**, not
+ the group named in the invitation (an operator pairs node-wide while opening a
+ group)
+
## Two lessons that cost four rounds of live testing
- **`QE/deploy/e2e.py` cannot test `app.js`.** It is a second implementation of the