Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion weblate/trans/backups.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ def validate(self) -> None:
self.load_memory(zipfile)
self.load_components(zipfile)
for name in zipfile.namelist():
validate_filename(name)
validate_filename(name, check_prohibited=False)

def restore_unit(
self,
Expand Down
2 changes: 1 addition & 1 deletion weblate/utils/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@


def remove_tree(path: str | Path, ignore_errors: bool = False) -> None:
shutil.rmtree(path, ignore_errors=ignore_errors, onexc=remove_readonly)

Check failure on line 72 in weblate/utils/files.py

View workflow job for this annotation

GitHub Actions / mypy

Argument "onexc" to "__call__" of "_RmtreeType" has incompatible type "Callable[[Callable[..., Any], str, Exception], None]"; expected "Callable[[Callable[..., Any], str, BaseException], object] | None"


def should_skip(location):
Expand All @@ -90,7 +90,7 @@
)


def is_excluded(path):
def is_excluded(path: str) -> bool:
"""Whether path should be excluded from zip extraction."""
return any(exclude in f"/{path}/" for exclude in PATH_EXCLUDES) or ".." in path

Expand Down
10 changes: 10 additions & 0 deletions weblate/utils/tests/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,16 @@ def test_simplification(self) -> None:
def test_empty(self) -> None:
validate_filename("")

def test_prohibited(self) -> None:
with self.assertRaises(ValidationError):
validate_filename(".git/config")
validate_filename(".git/config", check_prohibited=False)

def test_prohibited_subdir(self) -> None:
with self.assertRaises(ValidationError):
validate_filename("path/.git/config")
validate_filename("path/.git/config", check_prohibited=False)


class RegexTest(SimpleTestCase):
def test_empty(self) -> None:
Expand Down
5 changes: 4 additions & 1 deletion weblate/utils/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from weblate.trans.util import cleanup_path
from weblate.utils.const import WEBHOOKS_SECRET_PREFIX
from weblate.utils.data import data_dir
from weblate.utils.files import is_excluded

USERNAME_MATCHER = re.compile(r"^[\w@+-][\w.@+-]*$")

Expand Down Expand Up @@ -238,7 +239,7 @@
) from error


def validate_filename(value) -> None:
def validate_filename(value: str, *, check_prohibited: bool = True) -> None:
if "../" in value or "..\\" in value:
raise ValidationError(
gettext("The filename can not contain reference to a parent directory.")
Expand All @@ -254,6 +255,8 @@
"Maybe you want to use: {}"
).format(cleaned)
)
if check_prohibited and is_excluded(cleaned):
raise ValidationError(gettext("The filename contains a prohibited folder."))


def validate_backup_path(value: str) -> None:
Expand Down Expand Up @@ -432,7 +435,7 @@

# URL validation using for http (the URL validator is too strict to handle others)
if parsed.scheme in {"http", "https"}:
validator = URLValidator(schemes=settings.VCS_ALLOW_SCHEMES)

Check failure on line 438 in weblate/utils/validators.py

View workflow job for this annotation

GitHub Actions / mypy

Argument "schemes" to "URLValidator" has incompatible type "set[str]"; expected "Sequence[str] | None"
validator(url)

# Filter hosts if configured
Expand Down
Loading