mirror of
https://github.com/esphome/esphome.git
synced 2026-02-18 23:45:40 -07:00
Reject empty file names and fix FlashImage.path endswith call
- Return 400 for empty or whitespace-only file_name to prevent the idedata fallback from matching everything via empty-string suffix. - Use image.path.as_posix().endswith() since FlashImage.path is a Path object which does not have a string endswith method. - Add parametrized test for empty/whitespace file name values.
This commit is contained in:
@@ -1054,7 +1054,7 @@ class DownloadBinaryRequestHandler(BaseHandler):
|
||||
# fallback to type=, but prioritize file=
|
||||
file_name = self.get_argument("type", None)
|
||||
file_name = self.get_argument("file", file_name)
|
||||
if file_name is None:
|
||||
if file_name is None or not file_name.strip():
|
||||
self.send_error(400)
|
||||
return
|
||||
# get requested download name, or build it based on filename
|
||||
@@ -1087,7 +1087,7 @@ class DownloadBinaryRequestHandler(BaseHandler):
|
||||
|
||||
found = False
|
||||
for image in idedata.extra_flash_images:
|
||||
if image.path.endswith(file_name):
|
||||
if image.path.as_posix().endswith(file_name):
|
||||
path = image.path
|
||||
download_name = file_name
|
||||
found = True
|
||||
|
||||
@@ -614,6 +614,28 @@ async def test_download_binary_handler_no_firmware_bin_path(
|
||||
assert exc_info.value.code == 404
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("mock_ext_storage_path")
|
||||
@pytest.mark.parametrize("file_value", ["", " ", "%20"])
|
||||
async def test_download_binary_handler_empty_file_name(
|
||||
dashboard: DashboardTestHelper,
|
||||
mock_storage_json: MagicMock,
|
||||
file_value: str,
|
||||
) -> None:
|
||||
"""Test that download returns 400 for empty or whitespace-only file names."""
|
||||
mock_storage = Mock()
|
||||
mock_storage.name = "test_device"
|
||||
mock_storage.firmware_bin_path = Path("/fake/firmware.bin")
|
||||
mock_storage_json.load.return_value = mock_storage
|
||||
|
||||
with pytest.raises(HTTPClientError) as exc_info:
|
||||
await dashboard.fetch(
|
||||
f"/download.bin?configuration=test.yaml&file={file_value}",
|
||||
method="GET",
|
||||
)
|
||||
assert exc_info.value.code == 400
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("mock_ext_storage_path")
|
||||
async def test_download_binary_handler_multiple_subdirectory_levels(
|
||||
|
||||
Reference in New Issue
Block a user