[dashboard] Add ESPHOME_TRUSTED_DOMAINS support to events WebSocket (#12479)

This commit is contained in:
J. Nick Koston
2025-12-14 13:30:55 -06:00
committed by GitHub
parent cfc0d8bdfc
commit 780a407b10
2 changed files with 105 additions and 14 deletions

View File

@@ -1567,3 +1567,90 @@ async def test_dashboard_yaml_loading_with_packages_and_secrets(
# If we get here, secret resolution worked!
assert "esphome" in config
assert config["esphome"]["name"] == "test-download-secrets"
@pytest.mark.asyncio
async def test_websocket_check_origin_default_same_origin(
dashboard: DashboardTestHelper,
) -> None:
"""Test WebSocket uses default same-origin check when ESPHOME_TRUSTED_DOMAINS not set."""
# Ensure ESPHOME_TRUSTED_DOMAINS is not set
env = os.environ.copy()
env.pop("ESPHOME_TRUSTED_DOMAINS", None)
with patch.dict(os.environ, env, clear=True):
from tornado.httpclient import HTTPRequest
url = f"ws://127.0.0.1:{dashboard.port}/events"
# Same origin should work (default Tornado behavior)
request = HTTPRequest(
url, headers={"Origin": f"http://127.0.0.1:{dashboard.port}"}
)
ws = await websocket_connect(request)
try:
msg = await ws.read_message()
assert msg is not None
data = json.loads(msg)
assert data["event"] == "initial_state"
finally:
ws.close()
@pytest.mark.asyncio
async def test_websocket_check_origin_trusted_domain(
dashboard: DashboardTestHelper,
) -> None:
"""Test WebSocket accepts connections from trusted domains."""
with patch.dict(os.environ, {"ESPHOME_TRUSTED_DOMAINS": "trusted.example.com"}):
from tornado.httpclient import HTTPRequest
url = f"ws://127.0.0.1:{dashboard.port}/events"
request = HTTPRequest(url, headers={"Origin": "https://trusted.example.com"})
ws = await websocket_connect(request)
try:
# Should receive initial state
msg = await ws.read_message()
assert msg is not None
data = json.loads(msg)
assert data["event"] == "initial_state"
finally:
ws.close()
@pytest.mark.asyncio
async def test_websocket_check_origin_untrusted_domain(
dashboard: DashboardTestHelper,
) -> None:
"""Test WebSocket rejects connections from untrusted domains."""
with patch.dict(os.environ, {"ESPHOME_TRUSTED_DOMAINS": "trusted.example.com"}):
from tornado.httpclient import HTTPRequest
url = f"ws://127.0.0.1:{dashboard.port}/events"
request = HTTPRequest(url, headers={"Origin": "https://untrusted.example.com"})
with pytest.raises(HTTPClientError) as exc_info:
await websocket_connect(request)
# Should get HTTP 403 Forbidden due to origin check failure
assert exc_info.value.code == 403
@pytest.mark.asyncio
async def test_websocket_check_origin_multiple_trusted_domains(
dashboard: DashboardTestHelper,
) -> None:
"""Test WebSocket accepts connections from multiple trusted domains."""
with patch.dict(
os.environ,
{"ESPHOME_TRUSTED_DOMAINS": "first.example.com, second.example.com"},
):
from tornado.httpclient import HTTPRequest
url = f"ws://127.0.0.1:{dashboard.port}/events"
# Test second domain in list (with space after comma)
request = HTTPRequest(url, headers={"Origin": "https://second.example.com"})
ws = await websocket_connect(request)
try:
msg = await ws.read_message()
assert msg is not None
data = json.loads(msg)
assert data["event"] == "initial_state"
finally:
ws.close()