Now, the chars `=:;()[]{}~!@#$%^ &` are possible as well Fixes #30134 --------- Co-authored-by: KN4CK3R <admin@oldschoolhack.me>tags/v1.22.0-rc0
@@ -8,6 +8,7 @@ import ( | |||
"net/http" | |||
"regexp" | |||
"strings" | |||
"unicode" | |||
packages_model "code.gitea.io/gitea/models/packages" | |||
"code.gitea.io/gitea/modules/log" | |||
@@ -18,8 +19,8 @@ import ( | |||
) | |||
var ( | |||
packageNameRegex = regexp.MustCompile(`\A[A-Za-z0-9\.\_\-\+]+\z`) | |||
filenameRegex = packageNameRegex | |||
packageNameRegex = regexp.MustCompile(`\A[-_+.\w]+\z`) | |||
filenameRegex = regexp.MustCompile(`\A[-_+=:;.()\[\]{}~!@#$%^& \w]+\z`) | |||
) | |||
func apiError(ctx *context.Context, status int, obj any) { | |||
@@ -54,20 +55,38 @@ func DownloadPackageFile(ctx *context.Context) { | |||
helper.ServePackageFile(ctx, s, u, pf) | |||
} | |||
func isValidPackageName(packageName string) bool { | |||
if len(packageName) == 1 && !unicode.IsLetter(rune(packageName[0])) && !unicode.IsNumber(rune(packageName[0])) { | |||
return false | |||
} | |||
return packageNameRegex.MatchString(packageName) && packageName != ".." | |||
} | |||
func isValidFileName(filename string) bool { | |||
return filenameRegex.MatchString(filename) && | |||
strings.TrimSpace(filename) == filename && | |||
filename != "." && filename != ".." | |||
} | |||
// UploadPackage uploads the specific generic package. | |||
// Duplicated packages get rejected. | |||
func UploadPackage(ctx *context.Context) { | |||
packageName := ctx.Params("packagename") | |||
filename := ctx.Params("filename") | |||
if !packageNameRegex.MatchString(packageName) || !filenameRegex.MatchString(filename) { | |||
apiError(ctx, http.StatusBadRequest, errors.New("Invalid package name or filename")) | |||
if !isValidPackageName(packageName) { | |||
apiError(ctx, http.StatusBadRequest, errors.New("invalid package name")) | |||
return | |||
} | |||
if !isValidFileName(filename) { | |||
apiError(ctx, http.StatusBadRequest, errors.New("invalid filename")) | |||
return | |||
} | |||
packageVersion := ctx.Params("packageversion") | |||
if packageVersion != strings.TrimSpace(packageVersion) { | |||
apiError(ctx, http.StatusBadRequest, errors.New("Invalid package version")) | |||
apiError(ctx, http.StatusBadRequest, errors.New("invalid package version")) | |||
return | |||
} | |||
@@ -0,0 +1,65 @@ | |||
// Copyright 2024 The Gitea Authors. All rights reserved. | |||
// SPDX-License-Identifier: MIT | |||
package generic | |||
import ( | |||
"testing" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
func TestValidatePackageName(t *testing.T) { | |||
bad := []string{ | |||
"", | |||
".", | |||
"..", | |||
"-", | |||
"a?b", | |||
"a b", | |||
"a/b", | |||
} | |||
for _, name := range bad { | |||
assert.False(t, isValidPackageName(name), "bad=%q", name) | |||
} | |||
good := []string{ | |||
"a", | |||
"1", | |||
"a-", | |||
"a_b", | |||
"c.d+", | |||
} | |||
for _, name := range good { | |||
assert.True(t, isValidPackageName(name), "good=%q", name) | |||
} | |||
} | |||
func TestValidateFileName(t *testing.T) { | |||
bad := []string{ | |||
"", | |||
".", | |||
"..", | |||
"a?b", | |||
"a/b", | |||
" a", | |||
"a ", | |||
} | |||
for _, name := range bad { | |||
assert.False(t, isValidFileName(name), "bad=%q", name) | |||
} | |||
good := []string{ | |||
"-", | |||
"a", | |||
"1", | |||
"a-", | |||
"a_b", | |||
"a b", | |||
"c.d+", | |||
`-_+=:;.()[]{}~!@#$%^& aA1`, | |||
} | |||
for _, name := range good { | |||
assert.True(t, isValidFileName(name), "good=%q", name) | |||
} | |||
} |
@@ -84,7 +84,7 @@ func TestPackageGeneric(t *testing.T) { | |||
t.Run("InvalidParameter", func(t *testing.T) { | |||
defer tests.PrintCurrentTest(t)() | |||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, "invalid+package name", packageVersion, filename), bytes.NewReader(content)). | |||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, "invalid package name", packageVersion, filename), bytes.NewReader(content)). | |||
AddBasicAuth(user.Name) | |||
MakeRequest(t, req, http.StatusBadRequest) | |||
@@ -92,7 +92,7 @@ func TestPackageGeneric(t *testing.T) { | |||
AddBasicAuth(user.Name) | |||
MakeRequest(t, req, http.StatusBadRequest) | |||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, "inval+id.na me"), bytes.NewReader(content)). | |||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, "inva|id.name"), bytes.NewReader(content)). | |||
AddBasicAuth(user.Name) | |||
MakeRequest(t, req, http.StatusBadRequest) | |||
}) |