From 6c47507edf48e665db4efb9268218753116edbc4 Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Wed, 3 Aug 2022 21:29:37 +0000 Subject: [PATCH 1/4] Allow multiple files in generic packages. --- docs/content/doc/packages/generic.en-us.md | 39 ++++++++++- integrations/api_packages_generic_test.go | 78 +++++++++++++++------- routers/api/packages/api.go | 12 ++-- routers/api/packages/generic/generic.go | 58 ++++++---------- 4 files changed, 115 insertions(+), 72 deletions(-) diff --git a/docs/content/doc/packages/generic.en-us.md b/docs/content/doc/packages/generic.en-us.md index a82058da8ac5c..4844a2bb3adbb 100644 --- a/docs/content/doc/packages/generic.en-us.md +++ b/docs/content/doc/packages/generic.en-us.md @@ -27,7 +27,7 @@ To authenticate to the Package Registry, you need to provide [custom HTTP header ## Publish a package To publish a generic package perform a HTTP PUT operation with the package content in the request body. -You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first. +You cannot publish a file with the same name twice to a package. You must delete the existing package version first. ``` PUT https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{package_version}/{file_name} @@ -55,7 +55,7 @@ The server reponds with the following HTTP Status codes. | HTTP Status Code | Meaning | | ----------------- | ------- | | `201 Created` | The package has been published. | -| `400 Bad Request` | The package name and/or version are invalid or a package with the same name and version already exist. | +| `400 Bad Request` | The package name and/or version and/or file name are invalid or a file with the same name exist. | ## Download a package @@ -80,3 +80,38 @@ Example request using HTTP Basic authentication: curl --user your_username:your_token_or_password \ https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0/file.bin ``` + +The server reponds with the following HTTP Status codes. + +| HTTP Status Code | Meaning | +| ----------------- | ------- | +| `200 OK` | Success | +| `404 Not Found` | The package or file was not found. | + +## Delete a package + +To delete a generic package perform a HTTP DELETE operation. This will delete all files of this version. + +``` +DELETE https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{package_version} +``` + +| Parameter | Description | +| ----------------- | ----------- | +| `owner` | The owner of the package. | +| `package_name` | The package name. | +| `package_version` | The package version. | + +Example request using HTTP Basic authentication: + +```shell +curl --user your_username:your_token_or_password -X DELETE \ + https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0 +``` + +The server reponds with the following HTTP Status codes. + +| HTTP Status Code | Meaning | +| ----------------- | ------- | +| `200 OK` | Success | +| `404 Not Found` | The package was not found. | diff --git a/integrations/api_packages_generic_test.go b/integrations/api_packages_generic_test.go index adaf99e981ae9..6e23a78c4bf37 100644 --- a/integrations/api_packages_generic_test.go +++ b/integrations/api_packages_generic_test.go @@ -27,12 +27,12 @@ func TestPackageGeneric(t *testing.T) { filename := "fi-le_na.me" content := []byte{1, 2, 3} - url := fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, filename) + url := fmt.Sprintf("/api/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion) t.Run("Upload", func(t *testing.T) { defer PrintCurrentTest(t)() - req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)) + req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content)) AddBasicAuthHeader(req, user.Name) MakeRequest(t, req, http.StatusCreated) @@ -55,28 +55,60 @@ func TestPackageGeneric(t *testing.T) { pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID) assert.NoError(t, err) assert.Equal(t, int64(len(content)), pb.Size) - }) - t.Run("UploadExists", func(t *testing.T) { - defer PrintCurrentTest(t)() + t.Run("Exists", func(t *testing.T) { + defer PrintCurrentTest(t)() - req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)) - AddBasicAuthHeader(req, user.Name) - MakeRequest(t, req, http.StatusBadRequest) + req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusBadRequest) + }) + + t.Run("Additional", func(t *testing.T) { + defer PrintCurrentTest(t)() + + req := NewRequestWithBody(t, "PUT", url+"/dummy.bin", bytes.NewReader(content)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusCreated) + + // Check deduplication + pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID) + assert.NoError(t, err) + assert.Len(t, pfs, 2) + assert.Equal(t, pfs[0].BlobID, pfs[1].BlobID) + }) }) t.Run("Download", func(t *testing.T) { defer PrintCurrentTest(t)() - req := NewRequest(t, "GET", url) + checkDownloadCount := func(count int64) { + pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) + assert.NoError(t, err) + assert.Len(t, pvs, 1) + assert.Equal(t, count, pvs[0].DownloadCount) + } + + checkDownloadCount(0) + + req := NewRequest(t, "GET", url+"/"+filename) resp := MakeRequest(t, req, http.StatusOK) assert.Equal(t, content, resp.Body.Bytes()) - pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) - assert.NoError(t, err) - assert.Len(t, pvs, 1) - assert.Equal(t, int64(1), pvs[0].DownloadCount) + checkDownloadCount(1) + + req = NewRequest(t, "GET", url+"/dummy.bin") + MakeRequest(t, req, http.StatusOK) + + checkDownloadCount(2) + + t.Run("NotExists", func(t *testing.T) { + defer PrintCurrentTest(t)() + + req := NewRequest(t, "GET", url+"/not.found") + MakeRequest(t, req, http.StatusNotFound) + }) }) t.Run("Delete", func(t *testing.T) { @@ -89,20 +121,16 @@ func TestPackageGeneric(t *testing.T) { pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) assert.NoError(t, err) assert.Empty(t, pvs) - }) - t.Run("DownloadNotExists", func(t *testing.T) { - defer PrintCurrentTest(t)() + t.Run("NotExists", func(t *testing.T) { + defer PrintCurrentTest(t)() - req := NewRequest(t, "GET", url) - MakeRequest(t, req, http.StatusNotFound) - }) - - t.Run("DeleteNotExists", func(t *testing.T) { - defer PrintCurrentTest(t)() + req := NewRequest(t, "GET", url+"/"+filename) + MakeRequest(t, req, http.StatusNotFound) - req := NewRequest(t, "DELETE", url) - AddBasicAuthHeader(req, user.Name) - MakeRequest(t, req, http.StatusNotFound) + req = NewRequest(t, "DELETE", url) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusNotFound) + }) }) } diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index bb9a42e33dc99..d4e76f4e94ffe 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -155,12 +155,12 @@ func Routes() *web.Route { }) }) r.Group("/generic", func() { - r.Group("/{packagename}/{packageversion}/{filename}", func() { - r.Get("", generic.DownloadPackageFile) - r.Group("", func() { - r.Put("", generic.UploadPackage) - r.Delete("", generic.DeletePackage) - }, reqPackageAccess(perm.AccessModeWrite)) + r.Group("/{packagename}/{packageversion}", func() { + r.Delete("", reqPackageAccess(perm.AccessModeWrite), generic.DeletePackage) + r.Group("/{filename}", func() { + r.Get("", generic.DownloadPackageFile) + r.Put("", reqPackageAccess(perm.AccessModeWrite), generic.UploadPackage) + }) }) }) r.Group("/helm", func() { diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go index 9a3a185d9da50..23073a92c943e 100644 --- a/routers/api/packages/generic/generic.go +++ b/routers/api/packages/generic/generic.go @@ -31,22 +31,16 @@ func apiError(ctx *context.Context, status int, obj interface{}) { // DownloadPackageFile serves the specific generic package. func DownloadPackageFile(ctx *context.Context) { - packageName, packageVersion, filename, err := sanitizeParameters(ctx) - if err != nil { - apiError(ctx, http.StatusBadRequest, err) - return - } - s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion( ctx, &packages_service.PackageInfo{ Owner: ctx.Package.Owner, PackageType: packages_model.TypeGeneric, - Name: packageName, - Version: packageVersion, + Name: ctx.Params("packagename"), + Version: ctx.Params("packageversion"), }, &packages_service.PackageFileInfo{ - Filename: filename, + Filename: ctx.Params("filename"), }, ) if err != nil { @@ -65,9 +59,17 @@ func DownloadPackageFile(ctx *context.Context) { // UploadPackage uploads the specific generic package. // Duplicated packages get rejected. func UploadPackage(ctx *context.Context) { - packageName, packageVersion, filename, err := sanitizeParameters(ctx) - if err != nil { - apiError(ctx, http.StatusBadRequest, err) + 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")) + return + } + + packageVersion := strings.TrimSpace(ctx.Params("packageversion")) + if packageVersion == "" { + apiError(ctx, http.StatusBadRequest, errors.New("Invalid package version")) return } @@ -88,7 +90,7 @@ func UploadPackage(ctx *context.Context) { } defer buf.Close() - _, _, err = packages_service.CreatePackageAndAddFile( + _, _, err = packages_service.CreatePackageOrAddFileToExisting( &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, @@ -107,7 +109,7 @@ func UploadPackage(ctx *context.Context) { }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + if err == packages_model.ErrDuplicatePackageFile { apiError(ctx, http.StatusBadRequest, err) return } @@ -120,19 +122,13 @@ func UploadPackage(ctx *context.Context) { // DeletePackage deletes the specific generic package. func DeletePackage(ctx *context.Context) { - packageName, packageVersion, _, err := sanitizeParameters(ctx) - if err != nil { - apiError(ctx, http.StatusBadRequest, err) - return - } - - err = packages_service.RemovePackageVersionByNameAndVersion( + err := packages_service.RemovePackageVersionByNameAndVersion( ctx.Doer, &packages_service.PackageInfo{ Owner: ctx.Package.Owner, PackageType: packages_model.TypeGeneric, - Name: packageName, - Version: packageVersion, + Name: ctx.Params("packagename"), + Version: ctx.Params("packageversion"), }, ) if err != nil { @@ -146,19 +142,3 @@ func DeletePackage(ctx *context.Context) { ctx.Status(http.StatusOK) } - -func sanitizeParameters(ctx *context.Context) (string, string, string, error) { - packageName := ctx.Params("packagename") - filename := ctx.Params("filename") - - if !packageNameRegex.MatchString(packageName) || !filenameRegex.MatchString(filename) { - return "", "", "", errors.New("Invalid package name or filename") - } - - packageVersion := strings.TrimSpace(ctx.Params("packageversion")) - if packageVersion == "" { - return "", "", "", errors.New("Invalid package version") - } - - return packageName, packageVersion, filename, nil -} From df77d94d8751bf1d68ae279da1188779241db1d2 Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Thu, 4 Aug 2022 19:37:03 +0000 Subject: [PATCH 2/4] Added deletion of single files. --- docs/content/doc/packages/generic.en-us.md | 33 +++++++++++- integrations/api_packages_generic_test.go | 59 ++++++++++++++++++---- routers/api/packages/api.go | 5 +- routers/api/packages/generic/generic.go | 49 +++++++++++++++++- 4 files changed, 132 insertions(+), 14 deletions(-) diff --git a/docs/content/doc/packages/generic.en-us.md b/docs/content/doc/packages/generic.en-us.md index 4844a2bb3adbb..67a36546c4c25 100644 --- a/docs/content/doc/packages/generic.en-us.md +++ b/docs/content/doc/packages/generic.en-us.md @@ -55,7 +55,8 @@ The server reponds with the following HTTP Status codes. | HTTP Status Code | Meaning | | ----------------- | ------- | | `201 Created` | The package has been published. | -| `400 Bad Request` | The package name and/or version and/or file name are invalid or a file with the same name exist. | +| `400 Bad Request` | The package name and/or version and/or file name are invalid. | +| `409 Conflict` | A file with the same name exist already in the package. | ## Download a package @@ -113,5 +114,33 @@ The server reponds with the following HTTP Status codes. | HTTP Status Code | Meaning | | ----------------- | ------- | -| `200 OK` | Success | +| `204 No Content` | Success | | `404 Not Found` | The package was not found. | + +## Delete a package file + +To delete a file of a generic package perform a HTTP DELETE operation. This will delete the package version too if there is no file left. +``` +DELETE https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{package_version}/{filename} +``` + +| Parameter | Description | +| ----------------- | ----------- | +| `owner` | The owner of the package. | +| `package_name` | The package name. | +| `package_version` | The package version. | +| `filename` | The filename. | + +Example request using HTTP Basic authentication: + +```shell +curl --user your_username:your_token_or_password -X DELETE \ + https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0/file.bin +``` + +The server reponds with the following HTTP Status codes. + +| HTTP Status Code | Meaning | +| ----------------- | ------- | +| `204 No Content` | Success | +| `404 Not Found` | The package or file was not found. | diff --git a/integrations/api_packages_generic_test.go b/integrations/api_packages_generic_test.go index 6e23a78c4bf37..5fd55593754d7 100644 --- a/integrations/api_packages_generic_test.go +++ b/integrations/api_packages_generic_test.go @@ -61,7 +61,7 @@ func TestPackageGeneric(t *testing.T) { req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content)) AddBasicAuthHeader(req, user.Name) - MakeRequest(t, req, http.StatusBadRequest) + MakeRequest(t, req, http.StatusConflict) }) t.Run("Additional", func(t *testing.T) { @@ -114,18 +114,59 @@ func TestPackageGeneric(t *testing.T) { t.Run("Delete", func(t *testing.T) { defer PrintCurrentTest(t)() - req := NewRequest(t, "DELETE", url) - AddBasicAuthHeader(req, user.Name) - MakeRequest(t, req, http.StatusOK) + t.Run("File", func(t *testing.T) { + defer PrintCurrentTest(t)() - pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) - assert.NoError(t, err) - assert.Empty(t, pvs) + req := NewRequest(t, "DELETE", url+"/"+filename) + MakeRequest(t, req, http.StatusUnauthorized) - t.Run("NotExists", func(t *testing.T) { + req = NewRequest(t, "DELETE", url+"/"+filename) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusNoContent) + + req = NewRequest(t, "GET", url+"/"+filename) + MakeRequest(t, req, http.StatusNotFound) + + req = NewRequest(t, "DELETE", url+"/"+filename) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusNotFound) + + pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) + assert.NoError(t, err) + assert.Len(t, pvs, 1) + + t.Run("RemovesVersion", func(t *testing.T) { + defer PrintCurrentTest(t)() + + req = NewRequest(t, "DELETE", url+"/dummy.bin") + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusNoContent) + + pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) + assert.NoError(t, err) + assert.Empty(t, pvs) + }) + }) + + t.Run("Version", func(t *testing.T) { defer PrintCurrentTest(t)() - req := NewRequest(t, "GET", url+"/"+filename) + req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusCreated) + + req = NewRequest(t, "DELETE", url) + MakeRequest(t, req, http.StatusUnauthorized) + + req = NewRequest(t, "DELETE", url) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusNoContent) + + pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) + assert.NoError(t, err) + assert.Empty(t, pvs) + + req = NewRequest(t, "GET", url+"/"+filename) MakeRequest(t, req, http.StatusNotFound) req = NewRequest(t, "DELETE", url) diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index d4e76f4e94ffe..a20615a3fe372 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -159,7 +159,10 @@ func Routes() *web.Route { r.Delete("", reqPackageAccess(perm.AccessModeWrite), generic.DeletePackage) r.Group("/{filename}", func() { r.Get("", generic.DownloadPackageFile) - r.Put("", reqPackageAccess(perm.AccessModeWrite), generic.UploadPackage) + r.Group("", func() { + r.Put("", generic.UploadPackage) + r.Delete("", generic.DeletePackageFile) + }, reqPackageAccess(perm.AccessModeWrite)) }) }) }) diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go index 23073a92c943e..d7aa9abca6c56 100644 --- a/routers/api/packages/generic/generic.go +++ b/routers/api/packages/generic/generic.go @@ -110,7 +110,7 @@ func UploadPackage(ctx *context.Context) { ) if err != nil { if err == packages_model.ErrDuplicatePackageFile { - apiError(ctx, http.StatusBadRequest, err) + apiError(ctx, http.StatusConflict, err) return } apiError(ctx, http.StatusInternalServerError, err) @@ -140,5 +140,50 @@ func DeletePackage(ctx *context.Context) { return } - ctx.Status(http.StatusOK) + ctx.Status(http.StatusNoContent) +} + +// DeletePackageFile deletes the specific file of a generic package. +func DeletePackageFile(ctx *context.Context) { + pv, pf, err := func() (*packages_model.PackageVersion, *packages_model.PackageFile, error) { + pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeGeneric, ctx.Params("packagename"), ctx.Params("packageversion")) + if err != nil { + return nil, nil, err + } + + pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, ctx.Params("filename"), packages_model.EmptyFileKey) + if err != nil { + return nil, nil, err + } + + return pv, pf, nil + }() + if err != nil { + if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist { + apiError(ctx, http.StatusNotFound, err) + return + } + apiError(ctx, http.StatusInternalServerError, err) + return + } + + pfs, err := packages_model.GetFilesByVersionID(ctx, pv.ID) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + + if len(pfs) == 1 { + if err := packages_service.RemovePackageVersion(ctx.Doer, pv); err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + } else { + if err := packages_service.DeletePackageFile(ctx, pf); err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + } + + ctx.Status(http.StatusNoContent) } From 318cceb55b1f2824067298c97edae0f0c1beca9b Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Thu, 4 Aug 2022 23:55:52 +0200 Subject: [PATCH 3/4] Update docs/content/doc/packages/generic.en-us.md Co-authored-by: silverwind --- docs/content/doc/packages/generic.en-us.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/doc/packages/generic.en-us.md b/docs/content/doc/packages/generic.en-us.md index 67a36546c4c25..438a349a23afd 100644 --- a/docs/content/doc/packages/generic.en-us.md +++ b/docs/content/doc/packages/generic.en-us.md @@ -120,6 +120,7 @@ The server reponds with the following HTTP Status codes. ## Delete a package file To delete a file of a generic package perform a HTTP DELETE operation. This will delete the package version too if there is no file left. + ``` DELETE https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{package_version}/{filename} ``` From 56076c8458c6d502c4f628e60aeaf59ca6b2e3cb Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Fri, 5 Aug 2022 07:28:05 +0000 Subject: [PATCH 4/4] Changed version check. --- docs/content/doc/packages/generic.en-us.md | 6 +++--- integrations/api_packages_generic_test.go | 22 +++++++++++++++++++--- routers/api/packages/generic/generic.go | 6 +++--- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/docs/content/doc/packages/generic.en-us.md b/docs/content/doc/packages/generic.en-us.md index 67a36546c4c25..c92bc700e9788 100644 --- a/docs/content/doc/packages/generic.en-us.md +++ b/docs/content/doc/packages/generic.en-us.md @@ -36,9 +36,9 @@ PUT https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{packa | Parameter | Description | | ----------------- | ----------- | | `owner` | The owner of the package. | -| `package_name` | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`). | -| `package_version` | The package version, a non-empty string. | -| `file_name` | The filename. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`). | +| `package_name` | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), pluses (`+`), or underscores (`_`). | +| `package_version` | The package version, a non-empty string without trailing or leading whitespaces. | +| `file_name` | The filename. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), pluses (`+`), or underscores (`_`). | Example request using HTTP Basic authentication: diff --git a/integrations/api_packages_generic_test.go b/integrations/api_packages_generic_test.go index 5fd55593754d7..c60a387f533bc 100644 --- a/integrations/api_packages_generic_test.go +++ b/integrations/api_packages_generic_test.go @@ -23,7 +23,7 @@ func TestPackageGeneric(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) packageName := "te-st_pac.kage" - packageVersion := "1.0.3" + packageVersion := "1.0.3-te st" filename := "fi-le_na.me" content := []byte{1, 2, 3} @@ -77,6 +77,22 @@ func TestPackageGeneric(t *testing.T) { assert.Len(t, pfs, 2) assert.Equal(t, pfs[0].BlobID, pfs[1].BlobID) }) + + t.Run("InvalidParameter", func(t *testing.T) { + defer 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)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusBadRequest) + + req = NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, "%20test ", filename), bytes.NewReader(content)) + AddBasicAuthHeader(req, 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)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusBadRequest) + }) }) t.Run("Download", func(t *testing.T) { @@ -137,11 +153,11 @@ func TestPackageGeneric(t *testing.T) { t.Run("RemovesVersion", func(t *testing.T) { defer PrintCurrentTest(t)() - + req = NewRequest(t, "DELETE", url+"/dummy.bin") AddBasicAuthHeader(req, user.Name) MakeRequest(t, req, http.StatusNoContent) - + pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) assert.NoError(t, err) assert.Empty(t, pvs) diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go index d7aa9abca6c56..79e5afb03cae3 100644 --- a/routers/api/packages/generic/generic.go +++ b/routers/api/packages/generic/generic.go @@ -67,8 +67,8 @@ func UploadPackage(ctx *context.Context) { return } - packageVersion := strings.TrimSpace(ctx.Params("packageversion")) - if packageVersion == "" { + packageVersion := ctx.Params("packageversion") + if packageVersion != strings.TrimSpace(packageVersion) { apiError(ctx, http.StatusBadRequest, errors.New("Invalid package version")) return } @@ -155,7 +155,7 @@ func DeletePackageFile(ctx *context.Context) { if err != nil { return nil, nil, err } - + return pv, pf, nil }() if err != nil {