Skip to content

Commit c6e2a38

Browse files
committed
Use PEP 503 rules to validate upload filename
1 parent 8c486f4 commit c6e2a38

File tree

2 files changed

+32
-9
lines changed

2 files changed

+32
-9
lines changed

tests/unit/forklift/test_legacy.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from cgi import FieldStorage
2121
from unittest import mock
2222

23-
import pkg_resources
2423
import pretend
2524
import pytest
2625
import requests
@@ -2388,7 +2387,16 @@ def test_upload_fails_with_diff_filename_same_blake2(
23882387
"400 File already exists. See /the/help/url/ for more information."
23892388
)
23902389

2391-
def test_upload_fails_with_wrong_filename(self, pyramid_config, db_request):
2390+
@pytest.mark.parametrize(
2391+
"filename",
2392+
[
2393+
"nope-{}.tar.gz",
2394+
"nope-{}-py3-none-any.whl",
2395+
],
2396+
)
2397+
def test_upload_fails_with_wrong_filename(
2398+
self, pyramid_config, db_request, filename
2399+
):
23922400
pyramid_config.testing_securitypolicy(userid=1)
23932401

23942402
user = UserFactory.create()
@@ -2398,7 +2406,7 @@ def test_upload_fails_with_wrong_filename(self, pyramid_config, db_request):
23982406
release = ReleaseFactory.create(project=project, version="1.0")
23992407
RoleFactory.create(user=user, project=project)
24002408

2401-
filename = "nope-{}.tar.gz".format(release.version)
2409+
filename = filename.format(release.version)
24022410

24032411
db_request.POST = MultiDict(
24042412
{
@@ -2422,8 +2430,8 @@ def test_upload_fails_with_wrong_filename(self, pyramid_config, db_request):
24222430

24232431
assert resp.status_code == 400
24242432
assert resp.status == (
2425-
"400 Start filename for {!r} with {!r}.".format(
2426-
project.name, pkg_resources.safe_name(project.name).lower()
2433+
"400 Filename {!r} must match project {!r}.".format(
2434+
filename, project.normalized_name
24272435
)
24282436
)
24292437

warehouse/forklift/legacy.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import packaging.specifiers
2727
import packaging.utils
2828
import packaging.version
29-
import pkg_resources
3029
import requests
3130
import stdlib_list
3231
import wtforms
@@ -628,6 +627,22 @@ def full_validate(self):
628627
)
629628

630629

630+
def _is_valid_filename(filename, specified_normalized_name):
631+
if filename.endswith(".whl"):
632+
parse_func = packaging.utils.parse_wheel_filename
633+
else:
634+
parse_func = packaging.utils.parse_sdist_filename
635+
try:
636+
parsed_parts = parse_func(filename)
637+
except (
638+
packaging.utils.InvalidSdistFilename,
639+
packaging.utils.InvalidWheelFilename,
640+
packaging.version.InvalidVersion,
641+
):
642+
return False
643+
return parsed_parts[0] == specified_normalized_name
644+
645+
631646
_safe_zipnames = re.compile(r"(purelib|platlib|headers|scripts|data).+", re.I)
632647
# .tar uncompressed, .tar.gz .tgz, .tar.bz2 .tbz2
633648
_tar_filenames_re = re.compile(r"\.(?:tar$|t(?:ar\.)?(?P<z_type>gz|bz2)$)")
@@ -1194,11 +1209,11 @@ def file_upload(request):
11941209

11951210
# Make sure that our filename matches the project that it is being uploaded
11961211
# to.
1197-
prefix = pkg_resources.safe_name(project.name).lower()
1198-
if not pkg_resources.safe_name(filename).lower().startswith(prefix):
1212+
normalized_name = project.normalized_name
1213+
if not _is_valid_filename(filename, normalized_name):
11991214
raise _exc_with_message(
12001215
HTTPBadRequest,
1201-
"Start filename for {!r} with {!r}.".format(project.name, prefix),
1216+
"Filename {!r} must match project {!r}.".format(filename, normalized_name),
12021217
)
12031218

12041219
# Check the content type of what is being uploaded

0 commit comments

Comments
 (0)