Remove login details before logging stream source (#45398)

* Remove login details before logging stream source

* Convert to str before re

* Use compiled RE

* Add tests and filter log message in worker

* Update import

Co-authored-by: Erik Montnemery <erik@montnemery.com>

* isort

Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
uvjustin 2021-03-23 14:30:45 +08:00 committed by GitHub
parent 55b689b464
commit cd455e296e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 3 deletions

View File

@ -15,6 +15,7 @@ tokens are expired. Alternatively, a Stream can be configured with keepalive
to always keep workers active. to always keep workers active.
""" """
import logging import logging
import re
import secrets import secrets
import threading import threading
import time import time
@ -38,6 +39,8 @@ from .hls import async_setup_hls
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
STREAM_SOURCE_RE = re.compile("//(.*):(.*)@")
def create_stream(hass, stream_source, options=None): def create_stream(hass, stream_source, options=None):
"""Create a stream with the specified identfier based on the source url. """Create a stream with the specified identfier based on the source url.
@ -173,7 +176,9 @@ class Stream:
target=self._run_worker, target=self._run_worker,
) )
self._thread.start() 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): def update_source(self, new_source):
"""Restart the stream with a new stream source.""" """Restart the stream with a new stream source."""
@ -239,7 +244,9 @@ class Stream:
self._thread_quit.set() self._thread_quit.set()
self._thread.join() self._thread.join()
self._thread = None 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): async def async_record(self, video_path, duration=30, lookback=5):
"""Make a .mp4 recording from a provided stream.""" """Make a .mp4 recording from a provided stream."""

View File

@ -5,6 +5,7 @@ import logging
import av import av
from . import STREAM_SOURCE_RE
from .const import ( from .const import (
AUDIO_CODECS, AUDIO_CODECS,
MAX_MISSING_DTS, MAX_MISSING_DTS,
@ -127,7 +128,9 @@ def stream_worker(source, options, segment_buffer, quit_event):
try: try:
container = av.open(source, options=options, timeout=STREAM_TIMEOUT) container = av.open(source, options=options, timeout=STREAM_TIMEOUT)
except av.AVError: except av.AVError:
_LOGGER.error("Error opening stream %s", source) _LOGGER.error(
"Error opening stream %s", STREAM_SOURCE_RE.sub("//", str(source))
)
return return
try: try:
video_stream = container.streams.video[0] video_stream = container.streams.video[0]

View File

@ -257,3 +257,13 @@ async def test_record_stream_audio(
# Verify that the save worker was invoked, then block until its # Verify that the save worker was invoked, then block until its
# thread completes and is shutdown completely to avoid thread leaks. # thread completes and is shutdown completely to avoid thread leaks.
await record_worker_sync.join() 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

View File

@ -574,3 +574,18 @@ async def test_update_stream_source(hass):
# Ccleanup # Ccleanup
stream.stop() 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