mirror of
https://github.com/home-assistant/core.git
synced 2025-07-30 10:48:01 +02:00
add check for allowed path
This commit is contained in:
@ -54,6 +54,13 @@ async def _async_upload_file(service_call: ServiceCall) -> None:
|
|||||||
translation_key="config_entry_not_loaded",
|
translation_key="config_entry_not_loaded",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not hass.config.is_allowed_path(target_file):
|
||||||
|
raise ServiceValidationError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="path_not_allowed",
|
||||||
|
translation_placeholders={"file": target_file},
|
||||||
|
)
|
||||||
|
|
||||||
if not os.path.isfile(target_file):
|
if not os.path.isfile(target_file):
|
||||||
raise ServiceValidationError(
|
raise ServiceValidationError(
|
||||||
translation_domain=DOMAIN,
|
translation_domain=DOMAIN,
|
||||||
|
@ -97,6 +97,9 @@
|
|||||||
"config_entry_not_loaded": {
|
"config_entry_not_loaded": {
|
||||||
"message": "Config entry not loaded."
|
"message": "Config entry not loaded."
|
||||||
},
|
},
|
||||||
|
"path_not_allowed": {
|
||||||
|
"message": "Cannot read `{file}`, no access to path; `allowlist_external_dirs` may need to be adjusted in `configuration.yaml`."
|
||||||
|
},
|
||||||
"file_not_found": {
|
"file_not_found": {
|
||||||
"message": "File `{file}` not found."
|
"message": "File `{file}` not found."
|
||||||
},
|
},
|
||||||
|
@ -37,6 +37,7 @@ async def test_upload_file(
|
|||||||
tmp_path: Path,
|
tmp_path: Path,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test upload_file service."""
|
"""Test upload_file service."""
|
||||||
|
hass.config.allowlist_external_dirs = {tmp_path}
|
||||||
test_file = tmp_path / "image.png"
|
test_file = tmp_path / "image.png"
|
||||||
test_file.write_bytes(b"abcdef")
|
test_file.write_bytes(b"abcdef")
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ async def test_upload_file_to_album(
|
|||||||
tmp_path: Path,
|
tmp_path: Path,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test upload_file service with target album_id."""
|
"""Test upload_file service with target album_id."""
|
||||||
|
hass.config.allowlist_external_dirs = {tmp_path}
|
||||||
test_file = tmp_path / "image.png"
|
test_file = tmp_path / "image.png"
|
||||||
test_file.write_bytes(b"abcdef")
|
test_file.write_bytes(b"abcdef")
|
||||||
|
|
||||||
@ -130,23 +132,48 @@ async def test_upload_file_config_entry_not_loaded(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_upload_file_file_not_found(
|
async def test_upload_file_path_not_allowed(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_immich: Mock,
|
mock_immich: Mock,
|
||||||
mock_config_entry: MockConfigEntry,
|
mock_config_entry: MockConfigEntry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test upload_file service raising file_not_found."""
|
"""Test upload_file service raising path_not_allowed."""
|
||||||
|
hass.config.allowlist_external_dirs = {}
|
||||||
await setup_integration(hass, mock_config_entry)
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ServiceValidationError, match="File `not_existing.file` not found"
|
ServiceValidationError,
|
||||||
|
match="Cannot read `/blabla/not_existing.file`, no access to path;",
|
||||||
):
|
):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_UPLOAD_FILE,
|
SERVICE_UPLOAD_FILE,
|
||||||
{
|
{
|
||||||
"config_entry_id": mock_config_entry.entry_id,
|
"config_entry_id": mock_config_entry.entry_id,
|
||||||
"file": "not_existing.file",
|
"file": "/blabla/not_existing.file",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_upload_file_file_not_found(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_immich: Mock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test upload_file service raising file_not_found."""
|
||||||
|
hass.config.allowlist_external_dirs = {"/blabla"}
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
ServiceValidationError, match="File `/blabla/not_existing.file` not found"
|
||||||
|
):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_UPLOAD_FILE,
|
||||||
|
{
|
||||||
|
"config_entry_id": mock_config_entry.entry_id,
|
||||||
|
"file": "/blabla/not_existing.file",
|
||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
@ -159,6 +186,7 @@ async def test_upload_file_album_not_found(
|
|||||||
tmp_path: Path,
|
tmp_path: Path,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test upload_file service raising album_not_found."""
|
"""Test upload_file service raising album_not_found."""
|
||||||
|
hass.config.allowlist_external_dirs = {tmp_path}
|
||||||
test_file = tmp_path / "image.png"
|
test_file = tmp_path / "image.png"
|
||||||
test_file.write_bytes(b"abcdef")
|
test_file.write_bytes(b"abcdef")
|
||||||
|
|
||||||
@ -196,6 +224,7 @@ async def test_upload_file_upload_failed(
|
|||||||
tmp_path: Path,
|
tmp_path: Path,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test upload_file service raising upload_failed."""
|
"""Test upload_file service raising upload_failed."""
|
||||||
|
hass.config.allowlist_external_dirs = {tmp_path}
|
||||||
test_file = tmp_path / "image.png"
|
test_file = tmp_path / "image.png"
|
||||||
test_file.write_bytes(b"abcdef")
|
test_file.write_bytes(b"abcdef")
|
||||||
|
|
||||||
@ -230,6 +259,7 @@ async def test_upload_file_to_album_upload_failed(
|
|||||||
tmp_path: Path,
|
tmp_path: Path,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test upload_file service with target album_id raising upload_failed."""
|
"""Test upload_file service with target album_id raising upload_failed."""
|
||||||
|
hass.config.allowlist_external_dirs = {tmp_path}
|
||||||
test_file = tmp_path / "image.png"
|
test_file = tmp_path / "image.png"
|
||||||
test_file.write_bytes(b"abcdef")
|
test_file.write_bytes(b"abcdef")
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user