Skip to content

Commit 0197d2d

Browse files
diewdurbin
authored andcommitted
Block registration of 'ultranormalized' names (pypi#10498)
* Block registration of 'ultranormalized' names * Create an index over ultranormalize_name * Update warehouse/migrations/versions/d18d443f89f0_ultranormalize_name_function.py * update help, differentiate message for ultranormalized collisions Co-authored-by: Ee Durbin <[email protected]>
1 parent a2df9ff commit 0197d2d

File tree

5 files changed

+257
-124
lines changed

5 files changed

+257
-124
lines changed

tests/unit/forklift/test_legacy.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,57 @@ def test_fails_with_invalid_names(self, pyramid_config, db_request, name):
10431043
"for more information."
10441044
).format(name)
10451045

1046+
@pytest.mark.parametrize(
1047+
"conflicting_name",
1048+
[
1049+
"toast1ng",
1050+
"toastlng",
1051+
"t0asting",
1052+
"toast-ing",
1053+
"toast.ing",
1054+
"toast_ing",
1055+
],
1056+
)
1057+
def test_fails_with_ultranormalized_names(
1058+
self, pyramid_config, db_request, conflicting_name
1059+
):
1060+
pyramid_config.testing_securitypolicy(userid=1)
1061+
user = UserFactory.create()
1062+
EmailFactory.create(user=user)
1063+
ProjectFactory.create(name="toasting")
1064+
db_request.user = user
1065+
db_request.db.flush()
1066+
1067+
db_request.POST = MultiDict(
1068+
{
1069+
"metadata_version": "1.2",
1070+
"name": conflicting_name,
1071+
"version": "1.0",
1072+
"filetype": "sdist",
1073+
"md5_digest": "a fake md5 digest",
1074+
"content": pretend.stub(
1075+
filename=f"{conflicting_name}-1.0.tar.gz",
1076+
file=io.BytesIO(_TAR_GZ_PKG_TESTDATA),
1077+
type="application/tar",
1078+
),
1079+
}
1080+
)
1081+
1082+
db_request.help_url = pretend.call_recorder(lambda **kw: "/the/help/url/")
1083+
1084+
with pytest.raises(HTTPBadRequest) as excinfo:
1085+
legacy.file_upload(db_request)
1086+
1087+
resp = excinfo.value
1088+
1089+
assert db_request.help_url.calls == [pretend.call(_anchor="project-name")]
1090+
1091+
assert resp.status_code == 400
1092+
assert resp.status == (
1093+
"400 The name {!r} is too similar to an existing project. "
1094+
"See /the/help/url/ for more information."
1095+
).format(conflicting_name)
1096+
10461097
@pytest.mark.parametrize(
10471098
("description_content_type", "description", "message"),
10481099
[

warehouse/forklift/legacy.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -913,14 +913,16 @@ def file_upload(request):
913913
).format(projecthelp=request.help_url(_anchor="admin-intervention")),
914914
) from None
915915

916-
# Before we create the project, we're going to check our prohibited names to
917-
# see if this project is even allowed to be registered. If it is not,
916+
# Before we create the project, we're going to check our prohibited
917+
# names to see if this project name prohibited, or if the project name
918+
# is a close approximation of an existing project name. If it is,
918919
# then we're going to deny the request to create this project.
919-
if request.db.query(
920+
_prohibited_name = request.db.query(
920921
exists().where(
921922
ProhibitedProjectName.name == func.normalize_pep426_name(form.name.data)
922923
)
923-
).scalar():
924+
).scalar()
925+
if _prohibited_name:
924926
raise _exc_with_message(
925927
HTTPBadRequest,
926928
(
@@ -932,6 +934,24 @@ def file_upload(request):
932934
),
933935
) from None
934936

937+
_ultranormalize_collision = request.db.query(
938+
exists().where(
939+
func.ultranormalize_name(Project.name)
940+
== func.ultranormalize_name(form.name.data)
941+
)
942+
).scalar()
943+
if _ultranormalize_collision:
944+
raise _exc_with_message(
945+
HTTPBadRequest,
946+
(
947+
"The name {name!r} is too similar to an existing project. "
948+
"See {projecthelp} for more information."
949+
).format(
950+
name=form.name.data,
951+
projecthelp=request.help_url(_anchor="project-name"),
952+
),
953+
) from None
954+
935955
# Also check for collisions with Python Standard Library modules.
936956
if packaging.utils.canonicalize_name(form.name.data) in STDLIB_PROHIBITED:
937957
raise _exc_with_message(

0 commit comments

Comments
 (0)