diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index d17e4875b1..c3da5a7513 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -610,40 +610,46 @@ func CommonRoutes() *web.Router { }, reqPackageAccess(perm.AccessModeWrite)) }, reqPackageAccess(perm.AccessModeRead)) r.Group("/swift", func() { - r.Group("/{scope}/{name}", func() { - r.Group("", func() { - r.Get("", swift.EnumeratePackageVersions) - r.Get(".json", swift.EnumeratePackageVersions) - }, swift.CheckAcceptMediaType(swift.AcceptJSON)) - r.Group("/{version}", func() { - r.Get("/Package.swift", swift.CheckAcceptMediaType(swift.AcceptSwift), swift.DownloadManifest) - r.Put("", reqPackageAccess(perm.AccessModeWrite), swift.CheckAcceptMediaType(swift.AcceptJSON), swift.UploadPackageFile) - r.Get("", func(ctx *context.Context) { - // Can't use normal routes here: https://github.com/go-chi/chi/issues/781 + r.Group("", func() { // Needs to be unauthenticated. + r.Post("", swift.CheckAuthenticate) + r.Post("/login", swift.CheckAuthenticate) + }) + r.Group("", func() { + r.Group("/{scope}/{name}", func() { + r.Group("", func() { + r.Get("", swift.EnumeratePackageVersions) + r.Get(".json", swift.EnumeratePackageVersions) + }, swift.CheckAcceptMediaType(swift.AcceptJSON)) + r.Group("/{version}", func() { + r.Get("/Package.swift", swift.CheckAcceptMediaType(swift.AcceptSwift), swift.DownloadManifest) + r.Put("", reqPackageAccess(perm.AccessModeWrite), swift.CheckAcceptMediaType(swift.AcceptJSON), swift.UploadPackageFile) + r.Get("", func(ctx *context.Context) { + // Can't use normal routes here: https://github.com/go-chi/chi/issues/781 - version := ctx.PathParam("version") - if strings.HasSuffix(version, ".zip") { - swift.CheckAcceptMediaType(swift.AcceptZip)(ctx) - if ctx.Written() { - return + version := ctx.PathParam("version") + if strings.HasSuffix(version, ".zip") { + swift.CheckAcceptMediaType(swift.AcceptZip)(ctx) + if ctx.Written() { + return + } + ctx.SetPathParam("version", version[:len(version)-4]) + swift.DownloadPackageFile(ctx) + } else { + swift.CheckAcceptMediaType(swift.AcceptJSON)(ctx) + if ctx.Written() { + return + } + if strings.HasSuffix(version, ".json") { + ctx.SetPathParam("version", version[:len(version)-5]) + } + swift.PackageVersionMetadata(ctx) } - ctx.SetPathParam("version", version[:len(version)-4]) - swift.DownloadPackageFile(ctx) - } else { - swift.CheckAcceptMediaType(swift.AcceptJSON)(ctx) - if ctx.Written() { - return - } - if strings.HasSuffix(version, ".json") { - ctx.SetPathParam("version", version[:len(version)-5]) - } - swift.PackageVersionMetadata(ctx) - } + }) }) }) - }) - r.Get("/identifiers", swift.CheckAcceptMediaType(swift.AcceptJSON), swift.LookupPackageIdentifiers) - }, reqPackageAccess(perm.AccessModeRead)) + r.Get("/identifiers", swift.CheckAcceptMediaType(swift.AcceptJSON), swift.LookupPackageIdentifiers) + }, reqPackageAccess(perm.AccessModeRead)) + }) r.Group("/vagrant", func() { r.Group("/authenticate", func() { r.Get("", vagrant.CheckAuthenticate) diff --git a/routers/api/packages/swift/swift.go b/routers/api/packages/swift/swift.go index d5d4d4e9d1..4d7fb8b1a6 100644 --- a/routers/api/packages/swift/swift.go +++ b/routers/api/packages/swift/swift.go @@ -27,7 +27,7 @@ import ( "github.com/hashicorp/go-version" ) -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#35-api-versioning +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#35-api-versioning const ( AcceptJSON = "application/vnd.swift.registry.v1+json" AcceptSwift = "application/vnd.swift.registry.v1+swift" @@ -35,9 +35,9 @@ const ( ) var ( - // https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#361-package-scope + // https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#361-package-scope scopePattern = regexp.MustCompile(`\A[a-zA-Z0-9][a-zA-Z0-9-]{0,38}\z`) - // https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#362-package-name + // https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#362-package-name namePattern = regexp.MustCompile(`\A[a-zA-Z0-9][a-zA-Z0-9-_]{0,99}\z`) ) @@ -49,7 +49,7 @@ type headers struct { Link string } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#35-api-versioning +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#35-api-versioning func setResponseHeaders(resp http.ResponseWriter, h *headers) { if h.ContentType != "" { resp.Header().Set("Content-Type", h.ContentType) @@ -69,7 +69,7 @@ func setResponseHeaders(resp http.ResponseWriter, h *headers) { } } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#33-error-handling +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#33-error-handling func apiError(ctx *context.Context, status int, obj any) { // https://www.rfc-editor.org/rfc/rfc7807 type Problem struct { @@ -91,7 +91,7 @@ func apiError(ctx *context.Context, status int, obj any) { }) } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#35-api-versioning +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#35-api-versioning func CheckAcceptMediaType(requiredAcceptHeader string) func(ctx *context.Context) { return func(ctx *context.Context) { accept := ctx.Req.Header.Get("Accept") @@ -101,6 +101,16 @@ func CheckAcceptMediaType(requiredAcceptHeader string) func(ctx *context.Context } } +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/PackageRegistryUsage.md#registry-authentication +func CheckAuthenticate(ctx *context.Context) { + if ctx.Doer == nil { + apiError(ctx, http.StatusUnauthorized, nil) + return + } + + ctx.Status(http.StatusOK) +} + func buildPackageID(scope, name string) string { return scope + "." + name } @@ -113,7 +123,7 @@ type EnumeratePackageVersionsResponse struct { Releases map[string]Release `json:"releases"` } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#41-list-package-releases +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#41-list-package-releases func EnumeratePackageVersions(ctx *context.Context) { packageScope := ctx.PathParam("scope") packageName := ctx.PathParam("name") @@ -170,7 +180,7 @@ type PackageVersionMetadataResponse struct { Metadata *swift_module.SoftwareSourceCode `json:"metadata"` } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#endpoint-2 +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#endpoint-2 func PackageVersionMetadata(ctx *context.Context) { id := buildPackageID(ctx.PathParam("scope"), ctx.PathParam("name")) @@ -228,7 +238,7 @@ func PackageVersionMetadata(ctx *context.Context) { }) } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#43-fetch-manifest-for-a-package-release +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#43-fetch-manifest-for-a-package-release func DownloadManifest(ctx *context.Context) { packageScope := ctx.PathParam("scope") packageName := ctx.PathParam("name") @@ -280,7 +290,7 @@ func DownloadManifest(ctx *context.Context) { }) } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#endpoint-6 +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#endpoint-6 func UploadPackageFile(ctx *context.Context) { packageScope := ctx.PathParam("scope") packageName := ctx.PathParam("name") @@ -379,7 +389,7 @@ func UploadPackageFile(ctx *context.Context) { ctx.Status(http.StatusCreated) } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#endpoint-4 +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#endpoint-4 func DownloadPackageFile(ctx *context.Context) { pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeSwift, buildPackageID(ctx.PathParam("scope"), ctx.PathParam("name")), ctx.PathParam("version")) if err != nil { @@ -420,7 +430,7 @@ type LookupPackageIdentifiersResponse struct { Identifiers []string `json:"identifiers"` } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#endpoint-5 +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#endpoint-5 func LookupPackageIdentifiers(ctx *context.Context) { url := ctx.FormTrim("url") if url == "" { diff --git a/tests/integration/api_packages_swift_test.go b/tests/integration/api_packages_swift_test.go index 7d4ff954e2..c0e0dccfab 100644 --- a/tests/integration/api_packages_swift_test.go +++ b/tests/integration/api_packages_swift_test.go @@ -42,6 +42,24 @@ func TestPackageSwift(t *testing.T) { url := fmt.Sprintf("/api/packages/%s/swift", user.Name) + t.Run("CheckLogin", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + req := NewRequestWithBody(t, "POST", url, strings.NewReader("")) + MakeRequest(t, req, http.StatusUnauthorized) + + req = NewRequestWithBody(t, "POST", url, strings.NewReader("")). + AddBasicAuth(user.Name) + MakeRequest(t, req, http.StatusOK) + + req = NewRequestWithBody(t, "POST", url+"/login", strings.NewReader("")) + MakeRequest(t, req, http.StatusUnauthorized) + + req = NewRequestWithBody(t, "POST", url+"/login", strings.NewReader("")). + AddBasicAuth(user.Name) + MakeRequest(t, req, http.StatusOK) + }) + t.Run("CheckAcceptMediaType", func(t *testing.T) { defer tests.PrintCurrentTest(t)()