diff --git a/homeassistant/components/stream/__init__.py b/homeassistant/components/stream/__init__.py index 184ed1f2719..0226bb82f6d 100644 --- a/homeassistant/components/stream/__init__.py +++ b/homeassistant/components/stream/__init__.py @@ -15,6 +15,7 @@ tokens are expired. Alternatively, a Stream can be configured with keepalive to always keep workers active. """ import logging +import re import secrets import threading import time @@ -38,6 +39,8 @@ from .hls import async_setup_hls _LOGGER = logging.getLogger(__name__) +STREAM_SOURCE_RE = re.compile("//(.*):(.*)@") + def create_stream(hass, stream_source, options=None): """Create a stream with the specified identfier based on the source url. @@ -173,7 +176,9 @@ class Stream: target=self._run_worker, ) self._thread.start() - _LOGGER.info("Started stream: %s", self.source) + _LOGGER.info( + "Started stream: %s", STREAM_SOURCE_RE.sub("//", str(self.source)) + ) def update_source(self, new_source): """Restart the stream with a new stream source.""" @@ -239,7 +244,9 @@ class Stream: self._thread_quit.set() self._thread.join() self._thread = None - _LOGGER.info("Stopped stream: %s", self.source) + _LOGGER.info( + "Stopped stream: %s", STREAM_SOURCE_RE.sub("//", str(self.source)) + ) async def async_record(self, video_path, duration=30, lookback=5): """Make a .mp4 recording from a provided stream.""" diff --git a/homeassistant/components/stream/worker.py b/homeassistant/components/stream/worker.py index 8d1df37d039..5a129356983 100644 --- a/homeassistant/components/stream/worker.py +++ b/homeassistant/components/stream/worker.py @@ -5,6 +5,7 @@ import logging import av +from . import STREAM_SOURCE_RE from .const import ( AUDIO_CODECS, MAX_MISSING_DTS, @@ -127,7 +128,9 @@ def stream_worker(source, options, segment_buffer, quit_event): try: container = av.open(source, options=options, timeout=STREAM_TIMEOUT) except av.AVError: - _LOGGER.error("Error opening stream %s", source) + _LOGGER.error( + "Error opening stream %s", STREAM_SOURCE_RE.sub("//", str(source)) + ) return try: video_stream = container.streams.video[0] diff --git a/tests/components/stream/test_recorder.py b/tests/components/stream/test_recorder.py index 2b44c16243b..564da4b108e 100644 --- a/tests/components/stream/test_recorder.py +++ b/tests/components/stream/test_recorder.py @@ -257,3 +257,13 @@ async def test_record_stream_audio( # Verify that the save worker was invoked, then block until its # thread completes and is shutdown completely to avoid thread leaks. await record_worker_sync.join() + + +async def test_recorder_log(hass, caplog): + """Test starting a stream to record logs the url without username and password.""" + await async_setup_component(hass, "stream", {"stream": {}}) + stream = create_stream(hass, "https://abcd:efgh@foo.bar") + with patch.object(hass.config, "is_allowed_path", return_value=True): + await stream.async_record("/example/path") + assert "https://abcd:efgh@foo.bar" not in caplog.text + assert "https://foo.bar" in caplog.text diff --git a/tests/components/stream/test_worker.py b/tests/components/stream/test_worker.py index bef5d366a8f..cf72a90168b 100644 --- a/tests/components/stream/test_worker.py +++ b/tests/components/stream/test_worker.py @@ -574,3 +574,18 @@ async def test_update_stream_source(hass): # Ccleanup stream.stop() + + +async def test_worker_log(hass, caplog): + """Test that the worker logs the url without username and password.""" + stream = Stream(hass, "https://abcd:efgh@foo.bar") + stream.add_provider(STREAM_OUTPUT_FORMAT) + with patch("av.open") as av_open: + av_open.side_effect = av.error.InvalidDataError(-2, "error") + segment_buffer = SegmentBuffer(stream.outputs) + stream_worker( + "https://abcd:efgh@foo.bar", {}, segment_buffer, threading.Event() + ) + await hass.async_block_till_done() + assert "https://abcd:efgh@foo.bar" not in caplog.text + assert "https://foo.bar" in caplog.text