Reduce log spam from unauthenticated websocket connections

This commit is contained in:
J. Nick Koston
2025-08-29 10:21:31 -05:00
parent 5e003627b2
commit 3fc68b00a9
2 changed files with 61 additions and 3 deletions

View File

@@ -37,6 +37,7 @@ from .messages import message_to_json_bytes
from .util import describe_request
CLOSE_MSG_TYPES = {WSMsgType.CLOSE, WSMsgType.CLOSED, WSMsgType.CLOSING}
AUTH_MESSAGE_TIMEOUT = 10 # seconds
if TYPE_CHECKING:
from .connection import ActiveConnection
@@ -389,9 +390,11 @@ class WebSocketHandler:
# Auth Phase
try:
msg = await self._wsock.receive(10)
msg = await self._wsock.receive(AUTH_MESSAGE_TIMEOUT)
except TimeoutError as err:
raise Disconnect("Did not receive auth message within 10 seconds") from err
raise Disconnect(
f"Did not receive auth message within {AUTH_MESSAGE_TIMEOUT} seconds"
) from err
if msg.type in (WSMsgType.CLOSE, WSMsgType.CLOSED, WSMsgType.CLOSING):
raise Disconnect("Received close message during auth phase")
@@ -538,6 +541,14 @@ class WebSocketHandler:
finally:
if disconnect_warn is None:
logger.debug("%s: Disconnected", self.description)
elif connection is None:
# Auth phase disconnects (connection is None) should be logged at debug level
# as they can be from random port scanners or non-legitimate connections
logger.debug(
"%s: Disconnected during auth phase: %s",
self.description,
disconnect_warn,
)
else:
logger.warning(
"%s: Disconnected: %s", self.description, disconnect_warn

View File

@@ -2,6 +2,7 @@
import asyncio
from datetime import timedelta
import logging
from typing import Any, cast
from unittest.mock import patch
@@ -20,7 +21,11 @@ from homeassistant.setup import async_setup_component
from homeassistant.util.dt import utcnow
from tests.common import async_call_logger_set_level, async_fire_time_changed
from tests.typing import MockHAClientWebSocket, WebSocketGenerator
from tests.typing import (
ClientSessionGenerator,
MockHAClientWebSocket,
WebSocketGenerator,
)
@pytest.fixture
@@ -400,6 +405,48 @@ async def test_prepare_fail_connection_reset(
assert "Connection reset by peer while preparing WebSocket" in caplog.text
async def test_auth_timeout_logs_at_debug(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test auth timeout is logged at debug level not warning."""
# Setup websocket API
assert await async_setup_component(hass, "websocket_api", {})
client = await hass_client()
# Patch the auth timeout to be very short (0.001 seconds)
with (
caplog.at_level(logging.DEBUG, "homeassistant.components.websocket_api"),
patch(
"homeassistant.components.websocket_api.http.AUTH_MESSAGE_TIMEOUT", 0.001
),
):
# Try to connect - will timeout quickly since we don't send auth
ws = await client.ws_connect("/api/websocket")
# Wait a bit for the timeout to trigger and cleanup to complete
await asyncio.sleep(0.1)
await ws.close()
await asyncio.sleep(0.1)
# Check that "Did not receive auth message" is logged at debug, not warning
debug_messages = [
r.message for r in caplog.records if r.levelno == logging.DEBUG
]
assert any(
"Disconnected during auth phase: Did not receive auth message" in msg
for msg in debug_messages
)
# Check it's NOT logged at warning level
warning_messages = [
r.message for r in caplog.records if r.levelno >= logging.WARNING
]
for msg in warning_messages:
assert "Did not receive auth message" not in msg
async def test_enable_coalesce(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,