3.7 KiB
LAN の HTTP アクセスで crypto.randomUUID() が WebSocket 接続開始を阻害する
概要
Workspace WebUI の Vite dev server を --host 付きで LAN に公開し、別端末から
http://192.168.1.32:5173 にアクセスすると、Worker Console の protocol 状態が
connecting のまま進まなかった。
原因は WebSocket や Vite proxy ではなく、WebSocket multiplexing の相関 ID 生成に
crypto.randomUUID() を直接使っていることである。http://localhost はブラウザから
potentially trustworthy origin として扱われる一方、LAN IP 上の平文 HTTP は secure
context ではない。crypto.randomUUID() は secure context 限定なので、LAN アクセスでは
接続処理が WebSocket の生成前に例外終了する。
発生経路
Worker Console の connectProtocolTransport は、最初に protocolState を
"connecting" に設定してから WorkspaceMultiplexer.subscribe() を呼ぶ。
web/workspace/src/routes/w/[workspaceId]/runtimes/[runtimeId]/workers/[workerId]/console/+page.svelteprotocolState = "connecting"- 直後に
workspaceMultiplexer(...).subscribe(...)
web/workspace/src/lib/workspace/multiplexer.tssubscribe()の先頭でconst clientId = crypto.randomUUID()- その後の
#ensureConnected()で初めてnew WebSocket(url)を実行する
このため crypto.randomUUID() が利用できないブラウザでは、画面状態だけが
connecting に更新された後に同期例外が発生し、WebSocket request 自体が送信されない。
接続失敗を示す closed や diagnostic にも遷移しないため、見た目からは WebSocket の
接続待ちに見える。
同じ multiplexer では crypto.randomUUID() を次の3用途に使っている。
- ブラウザ内で subscription を区別する
clientId subscribe_eventsrequest と response を対応付けるrequest_idunsubscribe_eventsのrequest_id
いずれも暗号化や認証のためではなく、ローカル Map のキーまたはプロトコル上の相関 ID である。secure-context-only API を要求する必要性はない。
切り分け結果
開発ホスト上から次の条件で /api/w/<workspace-id>/protocol/ws に WebSocket upgrade を
送ると、backend への直接接続と Vite の 5173 proxy 経由の両方で
101 Switching Protocols が返った。
Host: 192.168.1.32:5173Origin: http://192.168.1.32:5173
したがって、現在の Vite 設定にある proxy["/api"].ws = true と、loopback に bind した
backend への proxy はこの現象の直接原因ではない。
改善案
- UI 全体で使う ID 生成 helper を用意し、secure context に依存しない実装にする。
crypto.getRandomValues()から UUID v4 相当を生成する方法で十分である。 WorkspaceMultiplexer.subscribe()の同期初期化失敗を Console の diagnostic/state に 反映し、初期値のconnectingに留まらないようにする。- LAN 上の平文 HTTP を開発時の対応経路とするなら、insecure context から subscription 初期化できることを regression test として固定する。
- 本番相当の LAN 公開では HTTPS を使う。Passkey/WebAuthn も secure context を要求し、
現在の開発設定は
rp_id = localhostなので、LAN origin を正式対応する場合は auth の origin/RP ID 設計も別途必要になる。
補足
--host は Vite の listener を LAN に bind するだけであり、配信 origin を secure
context に変えるものではない。localhost で正常に動くことだけでは、LAN IP の HTTP
アクセスでも同じブラウザ API が利用できることを証明できない。