Skip to content

Commit 216e691

Browse files
committed
fix: sanitize server-provided paths
Make sure these match expected style.
1 parent 3ee9d14 commit 216e691

File tree

3 files changed

+45
-7
lines changed

3 files changed

+45
-7
lines changed

wlc/main.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import wlc
2222
from wlc.config import NoOptionError, WeblateConfig, WLCConfigurationError
2323

24+
from .utils import sanitize_slug
25+
2426
COMMANDS: dict[str, type[Command]] = {}
2527

2628
SORT_ORDER: list[str] = []
@@ -655,13 +657,11 @@ def download_component(self, component) -> None:
655657
raise CommandError("Output is needed for download!")
656658

657659
directory = Path(self.args.output)
658-
file_path = directory.joinpath(f"{component.project.slug}-{component.slug}.zip")
659-
660-
if not directory.exists():
661-
directory.mkdir(exist_ok=True, parents=True)
662-
663-
with open(file_path, "wb") as file:
664-
file.write(content)
660+
file_path = directory / (
661+
f"{sanitize_slug(component.project.slug)}-{sanitize_slug(component.slug)}.zip"
662+
)
663+
directory.mkdir(exist_ok=True, parents=True)
664+
file_path.write_bytes(content)
665665

666666
def download_components(self, iterable) -> None:
667667
for component in iterable:

wlc/test_utils.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright © Michal Čihař <[email protected]>
2+
#
3+
# SPDX-License-Identifier: GPL-3.0-or-later
4+
5+
"""Utils tests."""
6+
7+
from unittest import TestCase
8+
9+
from .utils import sanitize_slug
10+
11+
12+
class UtilsTestCase(TestCase):
13+
"""Utils tests."""
14+
15+
def test_sanitize_slug(self):
16+
self.assertEqual(sanitize_slug("slug"), "slug")
17+
18+
def test_sanitize_slug_dangerous(self):
19+
self.assertEqual(sanitize_slug("../\\slug"), "----slug")
20+
self.assertEqual(sanitize_slug("slug/other"), "slug-other")
21+
self.assertEqual(sanitize_slug("slug/"), "slug-")

wlc/utils.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright © Michal Čihař <[email protected]>
2+
#
3+
# SPDX-License-Identifier: GPL-3.0-or-later
4+
"""Utility helpers."""
5+
6+
from __future__ import annotations
7+
8+
import re
9+
10+
# This matches Django's SlugField validation minus dash which is
11+
# excluded by Weblate's validate_slug
12+
NON_SLUG_RE = re.compile(r"[^a-zA-Z0-9_]")
13+
14+
15+
def sanitize_slug(slug: str) -> str:
16+
"""Sanitize slug for safe use as a filename component."""
17+
return NON_SLUG_RE.sub("-", slug)

0 commit comments

Comments
 (0)