docs: resolve auth/handoff design - token-based auth, no Python relay
This commit is contained in:
@@ -55,7 +55,7 @@ Browser Server
|
|||||||
│ │ │ control protocol │
|
│ │ │ control protocol │
|
||||||
└──────────────────┘ └─────────────────────────────┘
|
└──────────────────┘ └─────────────────────────────┘
|
||||||
▲
|
▲
|
||||||
┌──────────────────┐ │ unix socket
|
┌──────────────────┐ │ process mgmt only
|
||||||
│ app.js │ ┌────────┴────────────────────┐
|
│ app.js │ ┌────────┴────────────────────┐
|
||||||
│ (dashboard, │◄── HTTP ──►│ Python FastAPI │
|
│ (dashboard, │◄── HTTP ──►│ Python FastAPI │
|
||||||
│ sidebar, grid, │ │ dashboard API, settings, │
|
│ sidebar, grid, │ │ dashboard API, settings, │
|
||||||
@@ -64,7 +64,7 @@ Browser Server
|
|||||||
└─────────────────────────────┘
|
└─────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
Python starts muxterm as a managed subprocess on startup (one process, started once). muxterm listens on a Unix socket (e.g., `/tmp/muxterm.sock`) — not a TCP port. FastAPI handles the initial WebSocket upgrade at `/terminal/ws` (auth check, then hands off the raw connection to muxterm). After the handshake, Python is out of the data path entirely.
|
Python starts muxterm as a managed subprocess on startup (one process, started once). muxterm listens on a localhost TCP port (e.g., 7682 — recycling the old ttyd port). The browser connects directly to muxterm's WebSocket endpoint after obtaining a short-lived auth token from Python. Python is never in the terminal data path — not even for the initial WebSocket handshake.
|
||||||
|
|
||||||
## Components
|
## Components
|
||||||
|
|
||||||
@@ -137,13 +137,14 @@ No explicit "screen dump" mechanism. Lean on tmux's native redraw behavior (same
|
|||||||
|
|
||||||
### Auth flow
|
### Auth flow
|
||||||
|
|
||||||
1. Browser opens `ws:///terminal/ws`
|
1. Browser requests `GET /api/terminal-token` from Python FastAPI
|
||||||
2. Python FastAPI runs `_ws_auth_check()` (cookie/bearer/localhost — same as today)
|
2. Python runs auth check (cookie/bearer/localhost — same as today)
|
||||||
3. If authorized, upgrades HTTP connection to WebSocket
|
3. If authorized, returns a short-lived HMAC token (30-second TTL, shared secret with muxterm)
|
||||||
4. Hands the raw socket to muxterm via Unix socket passthrough
|
4. Browser opens WebSocket directly to muxterm's port, including the token
|
||||||
5. Python is out of the data path from this point
|
5. muxterm validates the HMAC locally (no callback to Python) and accepts the connection
|
||||||
|
6. Python is never in the terminal data path — not even for the initial handshake
|
||||||
|
|
||||||
muxterm has zero auth logic. Trusts any connection on its internal Unix socket (not network-exposed).
|
muxterm validates tokens via HMAC with a shared secret configured at startup. No network calls to Python during connection.
|
||||||
|
|
||||||
## Wire Protocol
|
## Wire Protocol
|
||||||
|
|
||||||
@@ -204,15 +205,15 @@ Vendored into `muxplex/frontend/vendor/` alongside existing vendor pattern. WASM
|
|||||||
### Process lifecycle
|
### Process lifecycle
|
||||||
|
|
||||||
- Python FastAPI starts muxterm as a managed subprocess on startup (one process, started once)
|
- Python FastAPI starts muxterm as a managed subprocess on startup (one process, started once)
|
||||||
- muxterm listens on a Unix socket — not a TCP port
|
- muxterm listens on a localhost TCP port (e.g., 7682)
|
||||||
- If muxterm dies, Python detects it and restarts it (simple process supervision)
|
- If muxterm dies, Python detects it and restarts it (simple process supervision)
|
||||||
- On shutdown, Python sends SIGTERM to muxterm, which gracefully closes all PTYs
|
- On shutdown, Python sends SIGTERM to muxterm, which gracefully closes all PTYs
|
||||||
- PTYs are just file descriptors — tmux sessions survive muxterm restarts (tmux is independent)
|
- PTYs are just file descriptors — tmux sessions survive muxterm restarts (tmux is independent)
|
||||||
|
|
||||||
### What this replaces
|
### What this replaces
|
||||||
|
|
||||||
- No `kill_orphan_ttyd()` — no orphans possible (Unix socket, single process)
|
- No `kill_orphan_ttyd()` — single known process, Python holds the handle
|
||||||
- No port range allocation — Unix socket, not TCP
|
- No port range allocation — single fixed port, not a dynamic pool
|
||||||
- No PID file management — Python holds the process handle directly
|
- No PID file management — Python holds the process handle directly
|
||||||
|
|
||||||
## What Gets Deleted
|
## What Gets Deleted
|
||||||
@@ -268,13 +269,14 @@ Either phase can ship and be tested independently.
|
|||||||
|
|
||||||
3. **SIGWINCH for screen sync on session switch:** Instead of building a screen dump mechanism, leverage tmux's native redraw (triggered by SIGWINCH). This is exactly what happens when you resize a terminal — tmux repaints everything.
|
3. **SIGWINCH for screen sync on session switch:** Instead of building a screen dump mechanism, leverage tmux's native redraw (triggered by SIGWINCH). This is exactly what happens when you resize a terminal — tmux repaints everything.
|
||||||
|
|
||||||
4. **Unix socket, not TCP:** Eliminates the port range allocation, port conflicts, and orphan scanning that caused so much complexity. Python connects to muxterm via a well-known socket path.
|
4. **Token-based auth, not socket relay:** Python issues short-lived HMAC tokens; the browser connects directly to muxterm. Eliminates any Python relay (even at the socket level). muxterm validates tokens locally with a shared secret — no callback to Python during connection. This is the cleanest "Python out of the data path" design.
|
||||||
|
|
||||||
5. **ghostty-web over xterm.js:** API-compatible drop-in with better VT100 parsing via WASM. The terminal industry is moving this direction (Coder's ghostty-web has 2.5K stars). Reduces parser bugs that are outside our control.
|
5. **ghostty-web over xterm.js:** API-compatible drop-in with better VT100 parsing via WASM. The terminal industry is moving this direction (Coder's ghostty-web has 2.5K stars). Reduces parser bugs that are outside our control.
|
||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
|
- ~~**Socket handoff mechanism (RESOLVED):**~~ muxterm owns its own WebSocket listener on a localhost TCP port. Python is never in the terminal data path. Auth works via short-lived HMAC tokens: Python's `/api/terminal-token` endpoint authenticates the user (cookie/bearer/localhost) and returns a 30-second HMAC token. The browser includes this token when connecting to muxterm's WebSocket. muxterm validates the HMAC locally (shared secret with Python, no callback). This eliminates any form of Python relay or socket splicing.
|
||||||
- **ghostty-web maturity:** How stable is the API surface? Are there xterm.js addon equivalents (search, web links, fit) or do those need custom implementation?
|
- **ghostty-web maturity:** How stable is the API surface? Are there xterm.js addon equivalents (search, web links, fit) or do those need custom implementation?
|
||||||
- **WASM bundle caching:** Does the ~400KB ghostty-web WASM bundle cache well across page loads, or does it need explicit Cache-Control headers?
|
- **WASM bundle caching:** Does the ~400KB ghostty-web WASM bundle cache well across page loads, or does it need explicit Cache-Control headers?
|
||||||
- **muxterm socket path:** Should the Unix socket path be configurable, or is a well-known path (e.g., `/tmp/muxterm-{user}.sock`) sufficient?
|
- **muxterm port:** Should the localhost port be configurable (env var / settings), or is a fixed default (e.g., 7682) sufficient?
|
||||||
- **Federation implications:** Remote muxplex instances currently proxy through the Python WS relay. Does muxterm need its own federation-aware mode, or does Python remain the federation proxy (now forwarding to remote muxterm instances)?
|
- **Federation implications:** Remote muxplex instances currently proxy through the Python WS relay. Does muxterm need its own federation-aware mode, or does Python remain the federation proxy (now forwarding to remote muxterm instances)?
|
||||||
|
|||||||
Reference in New Issue
Block a user