Skip to content

Commit

Permalink
Use PEP 503 rules to validate upload filename
Browse files Browse the repository at this point in the history
  • Loading branch information
uranusjr committed Nov 26, 2021
1 parent 8c486f4 commit 5ee21e6
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 10 deletions.
20 changes: 14 additions & 6 deletions tests/unit/forklift/test_legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from cgi import FieldStorage
from unittest import mock

import pkg_resources
import pretend
import pytest
import requests
Expand Down Expand Up @@ -2354,7 +2353,7 @@ def test_upload_fails_with_diff_filename_same_blake2(
"filetype": "sdist",
"md5_digest": hashlib.md5(file_content.getvalue()).hexdigest(),
"content": pretend.stub(
filename="{}-fake.tar.gz".format(project.name),
filename="{}-1.0.tar.gz".format(project.name),
file=file_content,
type="application/tar",
),
Expand Down Expand Up @@ -2388,7 +2387,16 @@ def test_upload_fails_with_diff_filename_same_blake2(
"400 File already exists. See /the/help/url/ for more information."
)

def test_upload_fails_with_wrong_filename(self, pyramid_config, db_request):
@pytest.mark.parametrize(
"filename",
[
"nope-{}.tar.gz",
"nope-{}-py3-none-any.whl",
],
)
def test_upload_fails_with_wrong_filename(
self, pyramid_config, db_request, filename
):
pyramid_config.testing_securitypolicy(userid=1)

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

filename = "nope-{}.tar.gz".format(release.version)
filename = filename.format(release.version)

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

assert resp.status_code == 400
assert resp.status == (
"400 Start filename for {!r} with {!r}.".format(
project.name, pkg_resources.safe_name(project.name).lower()
"400 Filename {!r} must match project {!r}.".format(
filename, project.normalized_name
)
)

Expand Down
23 changes: 19 additions & 4 deletions warehouse/forklift/legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import packaging.specifiers
import packaging.utils
import packaging.version
import pkg_resources
import requests
import stdlib_list
import wtforms
Expand Down Expand Up @@ -628,6 +627,22 @@ def full_validate(self):
)


def _is_valid_filename(filename, specified_normalized_name):
if filename.endswith(".whl"):
parse_func = packaging.utils.parse_wheel_filename
else:
parse_func = packaging.utils.parse_sdist_filename
try:
parsed_parts = parse_func(filename)
except (
packaging.utils.InvalidSdistFilename,
packaging.utils.InvalidWheelFilename,
packaging.version.InvalidVersion,
):
return False
return parsed_parts[0] == specified_normalized_name


_safe_zipnames = re.compile(r"(purelib|platlib|headers|scripts|data).+", re.I)
# .tar uncompressed, .tar.gz .tgz, .tar.bz2 .tbz2
_tar_filenames_re = re.compile(r"\.(?:tar$|t(?:ar\.)?(?P<z_type>gz|bz2)$)")
Expand Down Expand Up @@ -1194,11 +1209,11 @@ def file_upload(request):

# Make sure that our filename matches the project that it is being uploaded
# to.
prefix = pkg_resources.safe_name(project.name).lower()
if not pkg_resources.safe_name(filename).lower().startswith(prefix):
normalized_name = project.normalized_name
if not _is_valid_filename(filename, normalized_name):
raise _exc_with_message(
HTTPBadRequest,
"Start filename for {!r} with {!r}.".format(project.name, prefix),
"Filename {!r} must match project {!r}.".format(filename, normalized_name),
)

# Check the content type of what is being uploaded
Expand Down

0 comments on commit 5ee21e6

Please sign in to comment.