fix(dashboard): allow desktop websocket origins on remote binds

This commit is contained in:
Leonard Sellem
2026-06-02 18:29:08 -07:00
committed by Teknium
parent 54343bcade
commit 6ed9a2de8f
2 changed files with 35 additions and 10 deletions
@@ -381,8 +381,9 @@ class TestWsHostOriginGuardOrigins:
Electron loads the packaged renderer over ``file://``, so its WebSocket
handshake carries ``Origin: file://`` (or the opaque ``null``). The
DNS-rebinding guard only needs to block cross-site http(s) origins. On a
loopback bind these non-web origins are trusted because the session token
is the real gate. Public/gated binds keep rejecting them.
loopback or explicit non-loopback insecure bind these non-web origins are
trusted because the session token is the real gate. OAuth-gated public
binds keep rejecting them.
"""
def _ws(self, *, origin, host):
@@ -413,8 +414,29 @@ class TestWsHostOriginGuardOrigins:
ws = self._ws(origin="http://evil.test", host="127.0.0.1:8080")
assert web_server._ws_host_origin_is_allowed(ws) is False
def test_explicit_non_loopback_file_origin_allowed(self, insecure_explicit_host_app):
"""Packaged Hermes Desktop also uses file:// when connecting to a
Tailscale/LAN dashboard bind.
The WebSocket route calls _ws_auth_ok before this guard, so in
non-gated mode the legacy session token remains the auth boundary.
"""
ws = self._ws(origin="file://", host="100.64.0.10:9119")
assert web_server._ws_host_origin_is_allowed(ws) is True
def test_explicit_non_loopback_null_origin_allowed(self, insecure_explicit_host_app):
ws = self._ws(origin="null", host="100.64.0.10:9119")
assert web_server._ws_host_origin_is_allowed(ws) is True
def test_explicit_non_loopback_cross_site_http_origin_rejected(
self, insecure_explicit_host_app
):
ws = self._ws(origin="http://localhost:9119", host="100.64.0.10:9119")
assert web_server._ws_host_origin_is_allowed(ws) is False
def test_gated_file_origin_rejected(self, gated_app):
# A public/gated bind has no legitimate file:// client.
# OAuth-gated public dashboards authenticate with cookies/tickets,
# not the legacy desktop session token.
ws = self._ws(origin="file://", host="fly-app.fly.dev")
assert web_server._ws_host_origin_is_allowed(ws) is False