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

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions routers/api/packages/pypi/pypi.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import (
packages_service "code.gitea.io/gitea/services/packages"
)

// https://www.python.org/dev/peps/pep-0503/#normalized-names
// https://peps.python.org/pep-0426/#name
var normalizer = strings.NewReplacer(".", "-", "_", "-")
var nameMatcher = regexp.MustCompile(`\A[a-zA-Z0-9\.\-_]+\z`)
var nameMatcher = regexp.MustCompile(`\A(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\.\-_]*[a-zA-Z0-9])\z`)

// https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions
var versionMatcher = regexp.MustCompile(`\Av?` +
Expand Down Expand Up @@ -128,7 +128,7 @@ func UploadPackageFile(ctx *context.Context) {

packageName := normalizer.Replace(ctx.Req.FormValue("name"))
packageVersion := ctx.Req.FormValue("version")
if !nameMatcher.MatchString(packageName) || !versionMatcher.MatchString(packageVersion) {
if hasInvalidMetadata(packageName, packageVersion) {
apiError(ctx, http.StatusBadRequest, "invalid name or version")
return
}
Expand All @@ -146,7 +146,7 @@ func UploadPackageFile(ctx *context.Context) {
Name: packageName,
Version: packageVersion,
},
SemverCompatible: true,
SemverCompatible: false,
Creator: ctx.Doer,
Metadata: &pypi_module.Metadata{
Author: ctx.Req.FormValue("author"),
Expand Down Expand Up @@ -177,3 +177,7 @@ func UploadPackageFile(ctx *context.Context) {

ctx.Status(http.StatusCreated)
}

func hasInvalidMetadata(packageName, packageVersion string) bool {
return !nameMatcher.MatchString(packageName) || !versionMatcher.MatchString(packageVersion)
}
37 changes: 37 additions & 0 deletions routers/api/packages/pypi/pypi_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package pypi

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestHasInvalidMetadata(t *testing.T) {
// The test cases below were created from the following Python PEPs:
// https://peps.python.org/pep-0426/#name
// https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions

// Valid Cases
assert.False(t, hasInvalidMetadata("A", "1.0.1"))
assert.False(t, hasInvalidMetadata("Test.Name.1234", "1.0.1"))
assert.False(t, hasInvalidMetadata("test_name", "1.0.1"))
assert.False(t, hasInvalidMetadata("test-name", "1.0.1"))
assert.False(t, hasInvalidMetadata("test-name", "v1.0.1"))
assert.False(t, hasInvalidMetadata("test-name", "2012.4"))
assert.False(t, hasInvalidMetadata("test-name", "1.0.1-alpha"))
assert.False(t, hasInvalidMetadata("test-name", "1.0.1a1"))
assert.False(t, hasInvalidMetadata("test-name", "1.0b2.r345.dev456"))
assert.False(t, hasInvalidMetadata("test-name", "1!1.0.1"))
assert.False(t, hasInvalidMetadata("test-name", "1.0.1+local.1"))

// Invalid Cases
assert.True(t, hasInvalidMetadata(".test-name", "1.0.1"))
assert.True(t, hasInvalidMetadata("test!name", "1.0.1"))
assert.True(t, hasInvalidMetadata("test-name", "a1.0.1"))
assert.True(t, hasInvalidMetadata("test-name", "1.0.1aa"))
assert.True(t, hasInvalidMetadata("test-name", "1.0.0-alpha.beta"))
}
6 changes: 3 additions & 3 deletions tests/integration/api_packages_pypi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestPackagePyPI(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})

packageName := "test-package"
packageVersion := "1.0.1+r1234"
packageVersion := "1!1.0.1+r1234"
packageAuthor := "KN4CK3R"
packageDescription := "Test Description"

Expand Down Expand Up @@ -72,7 +72,7 @@ func TestPackagePyPI(t *testing.T) {

pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
assert.NoError(t, err)
assert.NotNil(t, pd.SemVer)
assert.Nil(t, pd.SemVer)
assert.IsType(t, &pypi.Metadata{}, pd.Metadata)
assert.Equal(t, packageName, pd.Package.Name)
assert.Equal(t, packageVersion, pd.Version.Version)
Expand Down Expand Up @@ -100,7 +100,7 @@ func TestPackagePyPI(t *testing.T) {

pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
assert.NoError(t, err)
assert.NotNil(t, pd.SemVer)
assert.Nil(t, pd.SemVer)
assert.IsType(t, &pypi.Metadata{}, pd.Metadata)
assert.Equal(t, packageName, pd.Package.Name)
assert.Equal(t, packageVersion, pd.Version.Version)
Expand Down