Fix double space quoting in WebDAV (#140364)

This commit is contained in:
Jan-Philipp Benecke 2025-03-11 14:06:44 +01:00 committed by GitHub
parent bc6d342919
commit d2124db3ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 154 additions and 7 deletions

View File

@ -13,7 +13,11 @@ from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryError, ConfigEntryNotReady
from .const import CONF_BACKUP_PATH, DATA_BACKUP_AGENT_LISTENERS, DOMAIN
from .helpers import async_create_client, async_ensure_path_exists
from .helpers import (
async_create_client,
async_ensure_path_exists,
async_migrate_wrong_folder_path,
)
type WebDavConfigEntry = ConfigEntry[Client]
@ -46,10 +50,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: WebDavConfigEntry) -> bo
translation_key="cannot_connect",
)
path = entry.data.get(CONF_BACKUP_PATH, "/")
await async_migrate_wrong_folder_path(client, path)
# Ensure the backup directory exists
if not await async_ensure_path_exists(
client, entry.data.get(CONF_BACKUP_PATH, "/")
):
if not await async_ensure_path_exists(client, path):
raise ConfigEntryNotReady(
translation_domain=DOMAIN,
translation_key="cannot_access_or_create_backup_path",

View File

@ -1,10 +1,18 @@
"""Helper functions for the WebDAV component."""
import logging
from aiowebdav2.client import Client, ClientOptions
from aiowebdav2.exceptions import WebDavError
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
@callback
def async_create_client(
@ -36,3 +44,24 @@ async def async_ensure_path_exists(client: Client, path: str) -> bool:
return False
return True
async def async_migrate_wrong_folder_path(client: Client, path: str) -> None:
"""Migrate the wrong encoded folder path to the correct one."""
wrong_path = path.replace(" ", "%20")
if await client.check(wrong_path):
try:
await client.move(wrong_path, path)
except WebDavError as err:
raise ConfigEntryNotReady(
translation_domain=DOMAIN,
translation_key="failed_to_migrate_folder",
translation_placeholders={
"wrong_path": wrong_path,
"correct_path": path,
},
) from err
_LOGGER.debug(
"Migrated wrong encoded folder path from %s to %s", wrong_path, path
)

View File

@ -8,5 +8,5 @@
"iot_class": "cloud_polling",
"loggers": ["aiowebdav2"],
"quality_scale": "bronze",
"requirements": ["aiowebdav2==0.4.1"]
"requirements": ["aiowebdav2==0.4.2"]
}

View File

@ -36,6 +36,9 @@
},
"cannot_access_or_create_backup_path": {
"message": "Cannot access or create backup path. Please check the path and permissions."
},
"failed_to_migrate_folder": {
"message": "Failed to migrate wrong encoded folder \"{wrong_path}\" to \"{correct_path}\"."
}
}
}

2
requirements_all.txt generated
View File

@ -422,7 +422,7 @@ aiowaqi==3.1.0
aiowatttime==0.1.1
# homeassistant.components.webdav
aiowebdav2==0.4.1
aiowebdav2==0.4.2
# homeassistant.components.webostv
aiowebostv==0.7.3

View File

@ -404,7 +404,7 @@ aiowaqi==3.1.0
aiowatttime==0.1.1
# homeassistant.components.webdav
aiowebdav2==0.4.1
aiowebdav2==0.4.2
# homeassistant.components.webostv
aiowebostv==0.7.3

View File

@ -1 +1,14 @@
"""Tests for the WebDAV integration."""
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
async def setup_integration(
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Set up the WebDAV integration for testing."""
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()

View File

@ -62,4 +62,5 @@ def mock_webdav_client() -> Generator[AsyncMock]:
mock.download_iter.side_effect = _download_mock
mock.upload_iter.return_value = None
mock.clean.return_value = None
mock.move.return_value = None
yield mock

View File

@ -0,0 +1,96 @@
"""Test WebDAV component setup."""
from unittest.mock import AsyncMock
from aiowebdav2.exceptions import WebDavError
import pytest
from homeassistant.components.webdav.const import CONF_BACKUP_PATH, DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_PASSWORD, CONF_URL, CONF_USERNAME
from homeassistant.core import HomeAssistant
from . import setup_integration
from tests.common import MockConfigEntry
async def test_migrate_wrong_path(
hass: HomeAssistant, webdav_client: AsyncMock
) -> None:
"""Test migration of wrong encoded folder path."""
webdav_client.list_with_properties.return_value = [
{"/wrong%20path": []},
]
config_entry = MockConfigEntry(
title="user@webdav.demo",
domain=DOMAIN,
data={
CONF_URL: "https://webdav.demo",
CONF_USERNAME: "user",
CONF_PASSWORD: "supersecretpassword",
CONF_BACKUP_PATH: "/wrong path",
},
entry_id="01JKXV07ASC62D620DGYNG2R8H",
)
await setup_integration(hass, config_entry)
webdav_client.move.assert_called_once_with("/wrong%20path", "/wrong path")
async def test_migrate_non_wrong_path(
hass: HomeAssistant, webdav_client: AsyncMock
) -> None:
"""Test no migration of correct folder path."""
webdav_client.list_with_properties.return_value = [
{"/correct path": []},
]
webdav_client.check.side_effect = lambda path: path == "/correct path"
config_entry = MockConfigEntry(
title="user@webdav.demo",
domain=DOMAIN,
data={
CONF_URL: "https://webdav.demo",
CONF_USERNAME: "user",
CONF_PASSWORD: "supersecretpassword",
CONF_BACKUP_PATH: "/correct path",
},
entry_id="01JKXV07ASC62D620DGYNG2R8H",
)
await setup_integration(hass, config_entry)
webdav_client.move.assert_not_called()
async def test_migrate_error(
hass: HomeAssistant,
webdav_client: AsyncMock,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test migration of wrong encoded folder path with error."""
webdav_client.list_with_properties.return_value = [
{"/wrong%20path": []},
]
webdav_client.move.side_effect = WebDavError("Failed to move")
config_entry = MockConfigEntry(
title="user@webdav.demo",
domain=DOMAIN,
data={
CONF_URL: "https://webdav.demo",
CONF_USERNAME: "user",
CONF_PASSWORD: "supersecretpassword",
CONF_BACKUP_PATH: "/wrong path",
},
entry_id="01JKXV07ASC62D620DGYNG2R8H",
)
await setup_integration(hass, config_entry)
assert config_entry.state is ConfigEntryState.SETUP_RETRY
assert (
'Failed to migrate wrong encoded folder "/wrong%20path" to "/wrong path"'
in caplog.text
)