diff options
author | KN4CK3R <admin@oldschoolhack.me> | 2022-07-28 05:59:39 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-28 11:59:39 +0800 |
commit | 86e5268c396bd89716b2617a4949837982c1b0c3 (patch) | |
tree | a01a04c069644694470c3159ce3daed94436ef08 /routers/api | |
parent | 4604048010347ea946ae57628d694a631787ab17 (diff) | |
download | gitea-86e5268c396bd89716b2617a4949837982c1b0c3.tar.gz gitea-86e5268c396bd89716b2617a4949837982c1b0c3.zip |
Add Docker /v2/_catalog endpoint (#20469)
* Added properties for packages.
* Fixed authenticate header format.
* Added _catalog endpoint.
* Check owner visibility.
* Extracted condition.
* Added test for _catalog.
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Diffstat (limited to 'routers/api')
-rw-r--r-- | routers/api/packages/api.go | 1 | ||||
-rw-r--r-- | routers/api/packages/composer/api.go | 2 | ||||
-rw-r--r-- | routers/api/packages/composer/composer.go | 2 | ||||
-rw-r--r-- | routers/api/packages/container/blob.go | 12 | ||||
-rw-r--r-- | routers/api/packages/container/container.go | 35 | ||||
-rw-r--r-- | routers/api/packages/container/manifest.go | 12 | ||||
-rw-r--r-- | routers/api/packages/npm/api.go | 2 |
7 files changed, 60 insertions, 6 deletions
diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index b5fdc739d7..bb9a42e33d 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -257,6 +257,7 @@ func ContainerRoutes() *web.Route { r.Get("", container.ReqContainerAccess, container.DetermineSupport) r.Get("/token", container.Authenticate) + r.Get("/_catalog", container.ReqContainerAccess, container.GetRepositoryList) r.Group("/{username}", func() { r.Group("/{image}", func() { r.Group("/blobs/uploads", func() { diff --git a/routers/api/packages/composer/api.go b/routers/api/packages/composer/api.go index 5e1cc293da..45bb7eae1c 100644 --- a/routers/api/packages/composer/api.go +++ b/routers/api/packages/composer/api.go @@ -88,7 +88,7 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac for _, pd := range pds { packageType := "" - for _, pvp := range pd.Properties { + for _, pvp := range pd.VersionProperties { if pvp.Name == composer_module.TypeProperty { packageType = pvp.Value break diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go index b7c1f140dc..81cef39f1c 100644 --- a/routers/api/packages/composer/composer.go +++ b/routers/api/packages/composer/composer.go @@ -227,7 +227,7 @@ func UploadPackage(ctx *context.Context) { SemverCompatible: true, Creator: ctx.Doer, Metadata: cp.Metadata, - Properties: map[string]string{ + VersionProperties: map[string]string{ composer_module.TypeProperty: cp.Type, }, }, diff --git a/routers/api/packages/container/blob.go b/routers/api/packages/container/blob.go index 8f6254f583..8a9cbd4a15 100644 --- a/routers/api/packages/container/blob.go +++ b/routers/api/packages/container/blob.go @@ -29,6 +29,7 @@ func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pi *packages_servic contentStore := packages_module.NewContentStore() err := db.WithTx(func(ctx context.Context) error { + created := true p := &packages_model.Package{ OwnerID: pi.Owner.ID, Type: packages_model.TypeContainer, @@ -37,12 +38,21 @@ func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pi *packages_servic } var err error if p, err = packages_model.TryInsertPackage(ctx, p); err != nil { - if err != packages_model.ErrDuplicatePackage { + if err == packages_model.ErrDuplicatePackage { + created = false + } else { log.Error("Error inserting package: %v", err) return err } } + if created { + if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypePackage, p.ID, container_module.PropertyRepository, strings.ToLower(pi.Owner.LowerName+"/"+pi.Name)); err != nil { + log.Error("Error setting package property: %v", err) + return err + } + } + pv := &packages_model.PackageVersion{ PackageID: p.ID, CreatorID: pi.Owner.ID, diff --git a/routers/api/packages/container/container.go b/routers/api/packages/container/container.go index 2a564b3446..b961cd4afb 100644 --- a/routers/api/packages/container/container.go +++ b/routers/api/packages/container/container.go @@ -112,7 +112,7 @@ func apiErrorDefined(ctx *context.Context, err *namedError) { // ReqContainerAccess is a middleware which checks the current user valid (real user or ghost for anonymous access) func ReqContainerAccess(ctx *context.Context) { if ctx.Doer == nil { - ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+setting.AppURL+`v2/token"`) + ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+setting.AppURL+`v2/token",service="container_registry",scope="*"`) apiErrorDefined(ctx, errUnauthorized) } } @@ -151,6 +151,39 @@ func Authenticate(ctx *context.Context) { }) } +// https://docs.docker.com/registry/spec/api/#listing-repositories +func GetRepositoryList(ctx *context.Context) { + n := ctx.FormInt("n") + if n <= 0 || n > 100 { + n = 100 + } + last := ctx.FormTrim("last") + + repositories, err := container_model.GetRepositories(ctx, ctx.Doer, n, last) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + + type RepositoryList struct { + Repositories []string `json:"repositories"` + } + + if len(repositories) == n { + v := url.Values{} + if n > 0 { + v.Add("n", strconv.Itoa(n)) + } + v.Add("last", repositories[len(repositories)-1]) + + ctx.Resp.Header().Set("Link", fmt.Sprintf(`</v2/_catalog?%s>; rel="next"`, v.Encode())) + } + + jsonResponse(ctx, http.StatusOK, RepositoryList{ + Repositories: repositories, + }) +} + // https://github.com/opencontainers/distribution-spec/blob/main/spec.md#mounting-a-blob-from-another-repository // https://github.com/opencontainers/distribution-spec/blob/main/spec.md#single-post // https://github.com/opencontainers/distribution-spec/blob/main/spec.md#pushing-a-blob-in-chunks diff --git a/routers/api/packages/container/manifest.go b/routers/api/packages/container/manifest.go index d899ac8ee2..319c9bcabc 100644 --- a/routers/api/packages/container/manifest.go +++ b/routers/api/packages/container/manifest.go @@ -267,6 +267,7 @@ func processImageManifestIndex(mci *manifestCreationInfo, buf *packages_module.H } func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, metadata *container_module.Metadata) (*packages_model.PackageVersion, error) { + created := true p := &packages_model.Package{ OwnerID: mci.Owner.ID, Type: packages_model.TypeContainer, @@ -275,12 +276,21 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met } var err error if p, err = packages_model.TryInsertPackage(ctx, p); err != nil { - if err != packages_model.ErrDuplicatePackage { + if err == packages_model.ErrDuplicatePackage { + created = false + } else { log.Error("Error inserting package: %v", err) return nil, err } } + if created { + if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypePackage, p.ID, container_module.PropertyRepository, strings.ToLower(mci.Owner.LowerName+"/"+mci.Image)); err != nil { + log.Error("Error setting package property: %v", err) + return nil, err + } + } + metadata.IsTagged = mci.IsTagged metadataJSON, err := json.Marshal(metadata) diff --git a/routers/api/packages/npm/api.go b/routers/api/packages/npm/api.go index 56c8977043..4b6b803971 100644 --- a/routers/api/packages/npm/api.go +++ b/routers/api/packages/npm/api.go @@ -25,7 +25,7 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac for _, pd := range pds { versions[pd.SemVer.String()] = createPackageMetadataVersion(registryURL, pd) - for _, pvp := range pd.Properties { + for _, pvp := range pd.VersionProperties { if pvp.Name == npm_module.TagProperty { distTags[pvp.Value] = pd.Version.Version } |