Hide credentials from generated titles in generic camera (#70204)
parent
f9450d32ea
commit
d69a7e7be9
|
@ -8,13 +8,13 @@ import io
|
||||||
import logging
|
import logging
|
||||||
from types import MappingProxyType
|
from types import MappingProxyType
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from urllib.parse import urlparse, urlunparse
|
|
||||||
|
|
||||||
import PIL
|
import PIL
|
||||||
from async_timeout import timeout
|
from async_timeout import timeout
|
||||||
import av
|
import av
|
||||||
from httpx import HTTPStatusError, RequestError, TimeoutException
|
from httpx import HTTPStatusError, RequestError, TimeoutException
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
import yarl
|
||||||
|
|
||||||
from homeassistant.components.stream.const import SOURCE_TIMEOUT
|
from homeassistant.components.stream.const import SOURCE_TIMEOUT
|
||||||
from homeassistant.config_entries import ConfigEntry, ConfigFlow, OptionsFlow
|
from homeassistant.config_entries import ConfigEntry, ConfigFlow, OptionsFlow
|
||||||
|
@ -172,8 +172,7 @@ def slug_url(url) -> str | None:
|
||||||
"""Convert a camera url into a string suitable for a camera name."""
|
"""Convert a camera url into a string suitable for a camera name."""
|
||||||
if not url:
|
if not url:
|
||||||
return None
|
return None
|
||||||
url_no_scheme = urlparse(url)._replace(scheme="")
|
return slugify(yarl.URL(url).host)
|
||||||
return slugify(urlunparse(url_no_scheme).strip("/"))
|
|
||||||
|
|
||||||
|
|
||||||
async def async_test_stream(hass, info) -> dict[str, str]:
|
async def async_test_stream(hass, info) -> dict[str, str]:
|
||||||
|
|
|
@ -62,7 +62,7 @@ async def test_form(hass, fakeimg_png, mock_av_open, user_flow):
|
||||||
TESTDATA,
|
TESTDATA,
|
||||||
)
|
)
|
||||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
assert result2["title"] == "127_0_0_1_testurl_1"
|
assert result2["title"] == "127_0_0_1"
|
||||||
assert result2["options"] == {
|
assert result2["options"] == {
|
||||||
CONF_STILL_IMAGE_URL: "http://127.0.0.1/testurl/1",
|
CONF_STILL_IMAGE_URL: "http://127.0.0.1/testurl/1",
|
||||||
CONF_STREAM_SOURCE: "http://127.0.0.1/testurl/2",
|
CONF_STREAM_SOURCE: "http://127.0.0.1/testurl/2",
|
||||||
|
@ -96,7 +96,7 @@ async def test_form_only_stillimage(hass, fakeimg_png, user_flow):
|
||||||
data,
|
data,
|
||||||
)
|
)
|
||||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
assert result2["title"] == "127_0_0_1_testurl_1"
|
assert result2["title"] == "127_0_0_1"
|
||||||
assert result2["options"] == {
|
assert result2["options"] == {
|
||||||
CONF_STILL_IMAGE_URL: "http://127.0.0.1/testurl/1",
|
CONF_STILL_IMAGE_URL: "http://127.0.0.1/testurl/1",
|
||||||
CONF_AUTHENTICATION: HTTP_BASIC_AUTHENTICATION,
|
CONF_AUTHENTICATION: HTTP_BASIC_AUTHENTICATION,
|
||||||
|
@ -176,7 +176,7 @@ async def test_form_rtsp_mode(hass, fakeimg_png, mock_av_open, user_flow):
|
||||||
)
|
)
|
||||||
assert "errors" not in result2, f"errors={result2['errors']}"
|
assert "errors" not in result2, f"errors={result2['errors']}"
|
||||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
assert result2["title"] == "127_0_0_1_testurl_1"
|
assert result2["title"] == "127_0_0_1"
|
||||||
assert result2["options"] == {
|
assert result2["options"] == {
|
||||||
CONF_STILL_IMAGE_URL: "http://127.0.0.1/testurl/1",
|
CONF_STILL_IMAGE_URL: "http://127.0.0.1/testurl/1",
|
||||||
CONF_AUTHENTICATION: HTTP_BASIC_AUTHENTICATION,
|
CONF_AUTHENTICATION: HTTP_BASIC_AUTHENTICATION,
|
||||||
|
@ -202,6 +202,7 @@ async def test_form_only_stream(hass, mock_av_open, fakeimgbytes_jpg):
|
||||||
)
|
)
|
||||||
data = TESTDATA.copy()
|
data = TESTDATA.copy()
|
||||||
data.pop(CONF_STILL_IMAGE_URL)
|
data.pop(CONF_STILL_IMAGE_URL)
|
||||||
|
data[CONF_STREAM_SOURCE] = "rtsp://user:pass@127.0.0.1/testurl/2"
|
||||||
with mock_av_open as mock_setup:
|
with mock_av_open as mock_setup:
|
||||||
result3 = await hass.config_entries.flow.async_configure(
|
result3 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
|
@ -209,10 +210,10 @@ async def test_form_only_stream(hass, mock_av_open, fakeimgbytes_jpg):
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
assert result3["title"] == "127_0_0_1_testurl_2"
|
assert result3["title"] == "127_0_0_1"
|
||||||
assert result3["options"] == {
|
assert result3["options"] == {
|
||||||
CONF_AUTHENTICATION: HTTP_BASIC_AUTHENTICATION,
|
CONF_AUTHENTICATION: HTTP_BASIC_AUTHENTICATION,
|
||||||
CONF_STREAM_SOURCE: "http://127.0.0.1/testurl/2",
|
CONF_STREAM_SOURCE: "rtsp://user:pass@127.0.0.1/testurl/2",
|
||||||
CONF_USERNAME: "fred_flintstone",
|
CONF_USERNAME: "fred_flintstone",
|
||||||
CONF_PASSWORD: "bambam",
|
CONF_PASSWORD: "bambam",
|
||||||
CONF_LIMIT_REFETCH_TO_URL_CHANGE: False,
|
CONF_LIMIT_REFETCH_TO_URL_CHANGE: False,
|
||||||
|
@ -227,7 +228,7 @@ async def test_form_only_stream(hass, mock_av_open, fakeimgbytes_jpg):
|
||||||
"homeassistant.components.generic.camera.GenericCamera.async_camera_image",
|
"homeassistant.components.generic.camera.GenericCamera.async_camera_image",
|
||||||
return_value=fakeimgbytes_jpg,
|
return_value=fakeimgbytes_jpg,
|
||||||
):
|
):
|
||||||
image_obj = await async_get_image(hass, "camera.127_0_0_1_testurl_2")
|
image_obj = await async_get_image(hass, "camera.127_0_0_1")
|
||||||
assert image_obj.content == fakeimgbytes_jpg
|
assert image_obj.content == fakeimgbytes_jpg
|
||||||
assert len(mock_setup.mock_calls) == 1
|
assert len(mock_setup.mock_calls) == 1
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue