diff options
Diffstat (limited to 'packages/meshbay-node/src')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/config.py | 19 | ||||
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/daemon.py | 33 | ||||
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py | 15 |
3 files changed, 21 insertions, 46 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/config.py b/packages/meshbay-node/src/meshbay_node/config.py index f3752ea..e4444d3 100644 --- a/packages/meshbay-node/src/meshbay_node/config.py +++ b/packages/meshbay-node/src/meshbay_node/config.py @@ -6,6 +6,7 @@ All values have sensible defaults and can be overridden by env vars prefixed with MESHBAY_ (e.g. MESHBAY_HUB_URL). """ +import logging import os from dataclasses import dataclass, field from pathlib import Path @@ -15,6 +16,8 @@ try: except ImportError: import tomli as tomllib # type: ignore[no-redef] +log = logging.getLogger(__name__) + DEFAULT_CONFIG_PATH = Path.home() / ".config" / "meshbay" / "node.toml" EXAMPLE_CONFIG = """\ @@ -58,10 +61,9 @@ visibility = "public" # discoverable on the hub # unlock_file = "~/.config/meshbay/unlock.key" # or set MESHBAY_UNLOCK_KEY env var -# Node sovereignty: pin the operator's Ed25519 public key (base64, 32 bytes raw). -# Admin operations (file delete) require cryptographic proof of this key. -# Auto-pinned on first startup from the node operator's keystore. -# admin_pk_ed25519 = "base64-encoded-32-bytes" +# Operator authority is not configured here. Run `meshbay-node operator pair` and +# enter the code in your browser: the node pins that browser's key, and invites +# and file deletion are signed with it. """ @@ -112,7 +114,6 @@ class Config: groups: list[GroupConfig] = field(default_factory=list) keystore: KeystoreConfig = field(default_factory=KeystoreConfig) data_dir: Path = field(default_factory=lambda: Path.home() / ".local" / "share" / "meshbay") - admin_pk_ed25519: str = "" # base64 raw Ed25519 public key pinned locally # Back-compat: single-group access @property @@ -167,7 +168,13 @@ def load_config(path: Path = DEFAULT_CONFIG_PATH) -> Config: cfg.data_dir = Path(raw["data_dir"]).expanduser().resolve() if "admin_pk_ed25519" in raw: - cfg.admin_pk_ed25519 = raw["admin_pk_ed25519"] + # Removed, not merely unused: a key named here granted operator + # authority, and dropping it silently would refuse invites and file + # deletion with a signature error that looks like something else. + log.warning( + "admin_pk_ed25519 in %s is ignored — operator authority now comes " + "from the roster. Run `meshbay-node operator pair` and delete the " + "line.", path) ks = raw.get("keystore", {}) if "path" in ks: 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") diff --git a/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py b/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py index 572f6fd..64df7ac 100644 --- a/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py +++ b/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py @@ -1415,8 +1415,7 @@ class WebRTCPeerSession: `_verify_admin_sig`. The flag is set at startup and refreshed in-process when an operator pairs. """ - return bool(self._ctx.get("admin_pk_ed25519") - or self._ctx.get("has_admin_authority")) + return bool(self._ctx.get("has_admin_authority")) async def _verify_admin_sig(self, transcript: bytes, sig: bytes) -> bool: """ @@ -1424,14 +1423,12 @@ class WebRTCPeerSession: Read from the roster on each call rather than cached: revoking a paired browser must take effect immediately, and admin operations are rare enough - that a SQLite read costs nothing. `admin_pk_ed25519` in node.toml is still - honoured so an existing deployment keeps working until its operator pairs - (M3) — it is the legacy form of the same statement. - """ - legacy = self._ctx.get("admin_pk_ed25519") - if self._verify_sig(legacy, transcript, sig): - return True + that a SQLite read costs nothing. + There is one source of operator authority and this is it. `admin_pk_ed25519` + in node.toml used to be honoured alongside the roster; it is gone, and a + config that still names it is warned about at startup rather than obeyed. + """ roster = self._ctx.get("roster") if roster is None: return False |