Terminal & Screen Streaming
Authentication and Credential Management
Section titled “Authentication and Credential Management”The CookieSigner issues and verifies HMAC-signed cookies (e.g., scribe_admin) that authenticate subsequent admin browser traffic . These cookies contain an issued timestamp, a session ID, and an HMAC signature 1. Invalidation is handled through three mechanisms: factory_reset rotates the signing key by bumping the auth_version, logout adds the session ID to a revocation list, and natural expiry occurs after max_age_seconds (default 7 days). A distinct CookieSigner instance handles the scribe_kiosk cookie, which is bound to the Role.KIOSK principal for cage chromium sessions on GB10 hardware, ensuring domain separation between admin and kiosk cookies.
The TicketStore mints short-lived, single-use nonces required for the terminal WebSocket handshake . Tickets are formatted as <rand64>.<hmac64> and are consumed immediately upon use to prevent replay 2. A background sweep task removes expired tickets every 30 seconds.
Terminal Session Management
Section titled “Terminal Session Management”The terminal server exposes a tmux-first PTY over a WebSocket, utilizing a vendored xterm.js client for the in-browser panel 3. The WebSocket handshake requires both a valid scribe_admin cookie and a valid single-use HMAC ticket from the TicketStore .
Admin WebSocket connections are tracked by session ID in state._admin_ws_by_session 2. The register_admin_ws context manager manages the lifecycle of these connections, adding the WebSocket to the session’s set upon entry and removing it on exit. If a session is revoked (e.g., via logout), the system iterates through all WebSockets associated with that session ID and closes them with code 1008 (revoked). This ensures that re-authentication on the same browser invalidates the previous session’s terminal access.
Screen Streaming and Kiosk Displays
Section titled “Screen Streaming and Kiosk Displays”The architecture supports screen streaming for admin and kiosk displays, utilizing WebRTC for the streaming mechanism 3. Kiosk displays are authenticated via the scribe_kiosk cookie, which is issued by the /kiosk-bootstrap endpoint to the cage chromium session running on the GB10 hardware . This cookie binds the session to the Role.KIOSK principal, restricting access to kiosk-allowlisted endpoints while preventing write operations (PUT/POST/DELETE) on the admin surface .
# Per-instance HMAC info; defaults to the admin cookie format so
# every existing call site stays byte-identical. The kiosk signer
# is constructed with ``hmac_info=_KIOSK_COOKIE_HMAC_INFO`` so its
# cookies are domain-separated from admin cookies even when both
# signers share the same boot-derived subkey.
hmac_info: bytes = _COOKIE_HMAC_INFO
def _hmac(self, payload: bytes) -> str:
"""Compute the per-boot-keyed HMAC over ``payload``.
Domain-separated via :attr:`hmac_info` so an admin-cookie and
a kiosk-cookie with the same ``<issued>.<sid>`` body produce
different HMACs: they cannot be replayed across roles.
"""
return hmac.new(self.secret, self.hmac_info + payload, hashlib.sha256).hexdigest()
def rotate_secret(self, new_secret: bytes) -> None:
"""Replace the live signing key. Called by
``setup_state.bump_auth_version_and_rotate`` so a factory_reset
invalidates every previously-issued admin cookie immediately
(vs. waiting for restart). Tests use this to simulate that
rotation in-process."""
object.__setattr__(self, "secret", new_secret)
def issue(self, now: float | None = None, *, session_id: str | None = None) -> str:
"""Mint a cookie. Generates a fresh ``session_id`` if not provided.
Callers that need the ``session_id`` separately (to register active
admin WebSockets in ``state._admin_ws_by_session``) get it via
:func:`decode_verified_cookie` after issuing.
"""
issued = str(int(now if now is not None else time.time()))
sid = session_id or secrets.token_hex(16)
payload = f"{issued}|{sid}".encode()
sig = self._hmac(payload)
return f"{issued}.{sid}.{sig}"
def verify(self, value: str | None, now: float | None = None) -> bool:
"""Pure-boolean validity check - preserved signature for every caller.
def prune_revoked(
revoked_sessions: dict[str, float],
*,
now: float | None = None,
) -> int:
"""Drop revocation entries whose expiry has passed.
Returns the number of entries pruned. Called periodically from the
cookie/ticket sweeper; idempotent and safe to call from any task.
"""
current = now if now is not None else time.time()
stale = [sid for sid, exp in revoked_sessions.items() if exp < current]
for sid in stale:
revoked_sessions.pop(sid, None)
return len(stale)
@contextlib.asynccontextmanager
async def register_admin_ws(session_id: str, ws, by_session: dict[str, set]):
"""Track ``ws`` under ``session_id`` for the duration of the with-block.
On entry the WS joins ``by_session[session_id]`` (set is created on
first use). On exit - normal close, exception, network error, server
shutdown - the WS is removed; if the resulting set is empty, the
``session_id`` key is popped so the dict stays sized to active
sessions.
Logout (from the admin web/UI) iterates every WS in the logging-out
session's set and closes each one with WS code 1008 ``revoked``;
re-auth on the same browser does the same for the prior session_id
before minting the fresh cookie.
Usage::
async with register_admin_ws(sid, websocket,
state._admin_ws_by_session):
await main_handler(websocket)
"""
"""In-browser terminal panel for the meeting-scribe popout.
Exposes a tmux-first PTY over a WebSocket with HMAC-ticket auth, byte-level
flow control, and a vendored xterm.js client.
Submodules are imported lazily - server.py pulls in what it needs by name,
and tests import leaf modules directly. Keeping this file empty of side
effects avoids circular-import hazards during ``server.py`` bootstrap.
"""
from __future__ import annotations