From 84b032c65e17267d41e04605e79eea82a6f5a59f Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Sat, 15 Aug 2026 02:34:19 +0200 Subject: feat(groups): editable description, and one source of operator authority MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A description could only be set the moment a group was created, so every group made before anyone thought of one stayed blank for good. The owner can now edit it from the group's page, and PATCH /v1/groups/{id} takes it. That endpoint takes the description and nothing else, deliberately. The name, the visibility and the join policy are the terms members joined on; a private group that can quietly become public is not the group they agreed to be in. Changing those needs a decision about who gets told, not a field on a form — there is a test saying so. Separately, the legacy operator key is gone. `admin_pk_ed25519` in node.toml named the operator before the roster existed and was kept so that an existing deployment would keep working; nothing uses it, and a second source of node authority is not something to carry around out of politeness. Authority is the roster, read fresh on every check. It is removed rather than ignored: a config that still names the key gets a warning at startup pointing at the file. Dropping it in silence would refuse invites and file deletion with a signature error that looks like a bug somewhere else — which is exactly how finding M3 presented. Two tests were verifying admin operations by naming a key in the context, which was the legacy path. They now pair an operator into a roster, the way an operator does. The authority test anchored on the deleted function and passed vacuously once it disappeared; it states the invariant against the verifier and the daemon instead. Also defined .btn-secondary, used in four places and styled in none. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'CLAUDE.md') diff --git a/CLAUDE.md b/CLAUDE.md index 14d1980..ad215d5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -119,8 +119,10 @@ Scope: `hub`, `node`, `common`, or omitted for cross-cutting - **NS4** ~~`admin_pk_ed25519` auto-pinned from keystore~~ ❌ **that was finding M3.** The keystore key is not the key the browser signs with, so every admin operation failed closed. Authority now comes from the node's roster — `meshbay-node operator pair` - (2026-08-14). `admin_pk_ed25519` is still read as a legacy form; never auto-pin again, - and never resolve the operator's key through the hub + (2026-08-14). `admin_pk_ed25519` was kept as a legacy form and is now **removed** + (2026-08-15) — one source of authority, the roster. A config still naming it is + warned about at startup, never obeyed. Never auto-pin again, and never resolve the + operator's key through the hub - **NS5** DTLS channel binding in GEK-HMAC — `HMAC(GEK, nonce || offer_fp || answer_fp)` detects WebRTC signaling MitM ✅ DONE - **NS6** Chat `sender_id` enforced from authenticated session — prevents impersonation ✅ DONE - **NS7** Node Ed25519 auth — node daemon authenticates to hub via `POST /v1/nodes/auth` (Ed25519 signed timestamp), no auth_key/password on node. JWT `scope: "node"` blocks group management (create/add/delete/join). Operator manages groups from browser only. ✅ DONE -- cgit v1.2.3