""" MeshBay Node — local administration web UI (localhost:18000). FastAPI app providing: - Dashboard: node status, connected peers, group overview - Groups: file listing, shared directory info - Peers: connected WebRTC/QUIC clients - Audit log: IP + action log for legal compliance - API endpoints for all data (JSON) Served only on 127.0.0.1 — not exposed to the network. Gated by a per-run session token (11.5.3) — printed at daemon startup. """ import base64 import json import logging import time from html import escape from pathlib import Path from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Query from fastapi.responses import HTMLResponse, JSONResponse from meshbay_node import __version__ from meshbay_common.crypto import generate_gek, wrap_gek_aes log = logging.getLogger(__name__) def create_ui_app(state: dict) -> FastAPI: app = FastAPI( title="MeshBay Node Admin", version=__version__, docs_url=None, redoc_url=None, ) @app.middleware("http") async def _require_session_token(request, call_next): """ Gate the admin UI behind a per-run token (11.5.3). "localhost only" is weaker than it sounds: any process on the machine can reach it, and a page in the operator's browser can reach it too via DNS rebinding. Since this API can re-initialise a group's GEK and read the audit log, an unauthenticated loopback service is a privilege boundary waiting to be crossed. The token is printed at startup and accepted as ?t= or the X-MeshBay-Token header. """ from fastapi.responses import PlainTextResponse token = state.get("ui_token") if token: supplied = (request.query_params.get("t") or request.headers.get("X-MeshBay-Token")) if supplied != token: return PlainTextResponse("Forbidden", status_code=403) return await call_next(request) @app.middleware("http") async def _security_headers(request, call_next): """ Defence in depth behind the escaping fixes for H2. This UI is unauthenticated on loopback, so script execution here equals full control of the node admin API. Note what this does and does not do: the page relies on inline """ def _render_audit_page(token: str = "") -> str: return _AUDIT_HTML.replace("__TOKEN__", json.dumps(token)) _AUDIT_HTML = """ MeshBay Node — Audit Log

Audit Log

TimeEventUserIPGroupDetail
"""