aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node/daemon.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-15 02:34:19 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-15 02:34:19 +0200
commit84b032c65e17267d41e04605e79eea82a6f5a59f (patch)
treeeb7708a72944bb15540e103b4319242199af6fbb /packages/meshbay-node/src/meshbay_node/daemon.py
parent5338894f7fec9e1a60affb0e2ff3b9797bcbc968 (diff)
downloadmeshbay-84b032c65e17267d41e04605e79eea82a6f5a59f.tar.gz
feat(groups): editable description, and one source of operator authority
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 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/daemon.py')
-rw-r--r--packages/meshbay-node/src/meshbay_node/daemon.py33
1 files changed, 2 insertions, 31 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/daemon.py b/packages/meshbay-node/src/meshbay_node/daemon.py
index 58fa99a..1fe68b1 100644
--- a/packages/meshbay-node/src/meshbay_node/daemon.py
+++ b/packages/meshbay-node/src/meshbay_node/daemon.py
@@ -35,7 +35,6 @@ import sys
from pathlib import Path
import uvicorn
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from meshbay_common import MNP_VERSION
from meshbay_common.protocol import MNP
@@ -288,15 +287,10 @@ class NodeDaemon:
self._webrtc._ctx["roster"] = self._roster
self._webrtc._ctx["invite_ttl"] = (
self._config.node.invite_ttl_hours * 3600)
- admin_pk = self._legacy_admin_pk()
paired = await self._roster.has_operator() if self._roster else False
- if admin_pk:
- self._webrtc._ctx["admin_pk_ed25519"] = admin_pk
self._webrtc._ctx["has_admin_authority"] = paired
- if paired or admin_pk:
- sources = ([] if not paired else ["paired operator"]) + \
- ([] if not admin_pk else ["node.toml admin_pk"])
- log.info("Node authority: %s", " + ".join(sources))
+ if paired:
+ log.info("Node authority: paired operator")
else:
log.warning(
"No operator paired — invites and file deletion are "
@@ -482,26 +476,6 @@ class NodeDaemon:
log.warning("No unwrappable GEK bundle found for group %s", group_id[:8])
return None
- def _legacy_admin_pk(self) -> Ed25519PublicKey | None:
- """
- The pre-roster way of naming the operator: `admin_pk_ed25519` in node.toml.
-
- Still honoured so a deployment configured that way keeps working, but no
- longer the only path — and the auto-pin that used to stand in for it is
- gone. It pinned the node's *keystore* key while the browser signed with the
- user's *identity* key, so admin operations failed closed with a signature
- error that looked like a bug elsewhere (finding M3). An operator now pairs
- a browser with `meshbay-node operator pair`.
- """
- if not self._config.admin_pk_ed25519:
- return None
- try:
- raw = base64.b64decode(self._config.admin_pk_ed25519)
- return Ed25519PublicKey.from_public_bytes(raw)
- except Exception as e:
- log.error("Invalid admin_pk_ed25519 in config: %s", e)
- return None
-
async def _on_index_change(self, indexer: DirectoryIndexer) -> None:
"""Called when a DirectoryIndexer detects file changes."""
group_id = indexer.group_id
@@ -770,9 +744,6 @@ def main() -> None:
print(f"operator {op.get('username') or op['user_id'][:8]}"
f" key {(op.get('pk_ed25519') or '')[:16]}…"
f" paired {op.get('pinned_at', '?')}")
- elif cfg.admin_pk_ed25519:
- print("operator node.toml admin_pk_ed25519 (legacy)")
- print(" run `meshbay-node operator pair` to replace it")
else:
print("operator NONE PAIRED — file deletion and member invites are")
print(" refused. Run: meshbay-node operator pair")