mirror of
https://github.com/home-assistant/core.git
synced 2025-08-30 09:51:37 +02:00
Reduce log spam from unauthenticated websocket connections
This commit is contained in:
@@ -37,6 +37,7 @@ from .messages import message_to_json_bytes
|
|||||||
from .util import describe_request
|
from .util import describe_request
|
||||||
|
|
||||||
CLOSE_MSG_TYPES = {WSMsgType.CLOSE, WSMsgType.CLOSED, WSMsgType.CLOSING}
|
CLOSE_MSG_TYPES = {WSMsgType.CLOSE, WSMsgType.CLOSED, WSMsgType.CLOSING}
|
||||||
|
AUTH_MESSAGE_TIMEOUT = 10 # seconds
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .connection import ActiveConnection
|
from .connection import ActiveConnection
|
||||||
@@ -389,9 +390,11 @@ class WebSocketHandler:
|
|||||||
|
|
||||||
# Auth Phase
|
# Auth Phase
|
||||||
try:
|
try:
|
||||||
msg = await self._wsock.receive(10)
|
msg = await self._wsock.receive(AUTH_MESSAGE_TIMEOUT)
|
||||||
except TimeoutError as err:
|
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):
|
if msg.type in (WSMsgType.CLOSE, WSMsgType.CLOSED, WSMsgType.CLOSING):
|
||||||
raise Disconnect("Received close message during auth phase")
|
raise Disconnect("Received close message during auth phase")
|
||||||
@@ -538,6 +541,14 @@ class WebSocketHandler:
|
|||||||
finally:
|
finally:
|
||||||
if disconnect_warn is None:
|
if disconnect_warn is None:
|
||||||
logger.debug("%s: Disconnected", self.description)
|
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:
|
else:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"%s: Disconnected: %s", self.description, disconnect_warn
|
"%s: Disconnected: %s", self.description, disconnect_warn
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
import logging
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
@@ -20,7 +21,11 @@ from homeassistant.setup import async_setup_component
|
|||||||
from homeassistant.util.dt import utcnow
|
from homeassistant.util.dt import utcnow
|
||||||
|
|
||||||
from tests.common import async_call_logger_set_level, async_fire_time_changed
|
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
|
@pytest.fixture
|
||||||
@@ -400,6 +405,48 @@ async def test_prepare_fail_connection_reset(
|
|||||||
assert "Connection reset by peer while preparing WebSocket" in caplog.text
|
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(
|
async def test_enable_coalesce(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
hass_ws_client: WebSocketGenerator,
|
hass_ws_client: WebSocketGenerator,
|
||||||
|
Reference in New Issue
Block a user