Commit Graph

8 Commits

Author SHA1 Message Date
Brian Krabach 8e53dbe1cf fix: address Phase 3 COE verification findings — tile click guard, disclosure visibility, mobile confirm, dead code cleanup 2026-04-15 21:57:38 -07:00
Brian Krabach 50abb4f40b fix: WebSocket federation proxy accepts self-signed TLS certificates
websockets.connect() used default SSL verification, rejecting self-signed
certs on remote instances. Same issue as the httpx fix (2c21dfe) but for
the websockets library. Fix: pass ssl.SSLContext with CERT_NONE when the
remote URL is wss://.
2026-04-06 17:25:25 -07:00
Brian Krabach 086ef19aa4 feat: add WS /federation/{remote_id}/terminal/ws proxy endpoint 2026-04-01 11:42:19 -07:00
Brian Krabach d07800c8c5 feat: add Bearer token auth to WebSocket proxy for federation 2026-04-01 11:32:17 -07:00
Brian Krabach 38e2fc45d5 fix: WS proxy checks ttyd liveness before accepting + reset counter on message
Root cause (4th iteration): The WS proxy called websocket.accept() before
verifying ttyd was alive. The browser 'open' event fired immediately, resetting
_reconnectAttempts to 0. Counter bounced 0→1→0→1 forever — the client-side
/connect POST at >= 2 attempts never fired.

Server fix: _ttyd_is_listening() TCP probe (socket.create_connection, <1ms)
before websocket.accept(). If ttyd is dead, auto-spawns it from active_session
in state (kill_ttyd → spawn_ttyd → sleep 0.8s) THEN accepts. Browser 'open'
only fires when ttyd is confirmed reachable.

Client fix: _reconnectAttempts reset moved from 'open' handler to 'message'
handler. First data message proves ttyd is alive and relaying — not just that
the proxy accepted. Belt-and-suspenders: client-side /connect fetch still fires
at attempt >= 2 as a fallback.

Tests added:
- test_ttyd_is_listening_function_exists: function importable from main
- test_ws_proxy_checks_ttyd_before_accepting: source inspection ensures
  _ttyd_is_listening() call appears before await websocket.accept()
- test_ws_proxy_auto_spawns_ttyd_when_dead: verifies spawn_ttyd called with
  active_session when _ttyd_is_listening returns False
- terminal.mjs: _reconnectAttempts = 0 NOT in open handler, IS in message
2026-04-01 06:56:51 -07:00
Brian Krabach d0eb91dca7 refactor: replace fixed sleeps with deterministic polling in ws proxy tests; document CORS permissiveness 2026-03-30 21:56:05 -07:00
Brian Krabach b1cbeeb02c test: expand WebSocket proxy test suite 2026-03-30 21:47:17 -07:00
Brian Krabach 38c78fb575 fix: WebSocket proxy drops text frames — receive_bytes() silently fails on auth token
terminal.js sends the ttyd auth token as a TEXT WebSocket frame. The proxy's
client_to_ttyd() called receive_bytes() which fails silently on text frames,
swallows the exception, and exits — auth never reached ttyd, ttyd never
started streaming, resulting in permanent black screen and reconnect loop.

Fix: use receive() and dispatch on message type, handling both bytes and text.
2026-03-28 08:50:43 -07:00