fix(backup): add utf-8 encoding when writing url list files (#4345)

This commit is contained in:
Andrew Peabody
2026-08-31 13:41:46 +02:00
committed by GitHub
parent 9c0dfcd5d5
commit be75168570
2 changed files with 45 additions and 3 deletions
@@ -60,13 +60,13 @@ def create_backup(datastore_path, watches: dict, tags: dict = None):
# Create a list file with just the URLs, so it's easier to port somewhere else in the future
list_file = "url-list.txt"
with open(os.path.join(datastore_path, list_file), "w") as f:
with open(os.path.join(datastore_path, list_file), "w", encoding="utf-8") as f:
for uuid in watches:
url = watches[uuid]["url"]
f.write("{}\r\n".format(url))
list_with_tags_file = "url-list-with-tags.txt"
with open(
os.path.join(datastore_path, list_with_tags_file), "w"
os.path.join(datastore_path, list_with_tags_file), "w", encoding="utf-8"
) as f:
for uuid in watches:
url = watches[uuid].get('url')
+43 -1
View File
@@ -258,4 +258,46 @@ def test_backup_restore_zip_bomb_rejected(client, live_server, measure_memory_us
include_watches_replace=True,
)
finally:
restore_mod._MAX_DECOMPRESSED_BYTES = original_limit
restore_mod._MAX_DECOMPRESSED_BYTES = original_limit
def test_backup_with_extended_utf8_urls_and_tags(datastore_path):
"""Test create_backup handles extended UTF-8 characters in URLs and tags without encoding errors (issue #1805)."""
import os
import tempfile
from unittest.mock import MagicMock
from changedetectionio.blueprint.backups import create_backup
with tempfile.TemporaryDirectory() as tmp_dir:
watch_mock = MagicMock()
watch_mock.data_dir = tmp_dir
watch_mock.__getitem__.side_effect = lambda key: (
"https://example.com/products/café-öl-日本語-🎉?query=test#section" if key == "url" else None
)
watch_mock.get.side_effect = lambda key, default=None: (
"https://example.com/products/café-öl-日本語-🎉?query=test#section"
if key == "url"
else (["Größe", "日本語タグ", "🏷️special"] if key == "tags" else default)
)
watches = {"test-uuid-1": watch_mock}
# Should create backup without UnicodeEncodeError
create_backup(datastore_path=tmp_dir, watches=watches, tags={})
url_list_path = os.path.join(tmp_dir, "url-list.txt")
url_list_tags_path = os.path.join(tmp_dir, "url-list-with-tags.txt")
assert os.path.isfile(url_list_path)
assert os.path.isfile(url_list_tags_path)
with open(url_list_path, encoding="utf-8") as f:
content = f.read()
assert "café-öl-日本語-🎉" in content
with open(url_list_tags_path, encoding="utf-8") as f:
content = f.read()
assert "café-öl-日本語-🎉" in content
assert "Größe" in content
assert "日本語タグ" in content
assert "🏷️special" in content