/* * Copyright 2026 Oleg Borodin */ package handler import ( "net/http" "mstore/app/imageoper" "mstore/app/router" "mstore/pkg/terms" ) // GetProperty godoc // // @Summary Get manifest info // @Description Get manifest info // @Tags manifest // @Param name path string true "Manifest path" // @Param reference path string true "Manifest tag" // @Success 200 // @Failure 404,405,500 // @Router /v2/{name}/manifests/{reference} [HEAD] // @Header 200 {string} Content-Length "Manifest size" // @Header 200 {string} Content-Type "Manifest type" // @Header 200 {string} Docker-Content-Digest "Manigest digest" func (hand *Handler) ManifestExists(rctx *router.Context) { name, _ := rctx.GetSubpath("name") reference, _ := rctx.GetSubpath("reference") hand.DumpHeaders("ManigestExists:\n", rctx) params := &imageoper.ManifestExistsParams{ Name: name, Reference: reference, } // Rigth checking operatorID, _ := rctx.GetString(userTag) opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadImages, params.Name) if err != nil { rctx.SetStatus(http.StatusInternalServerError) return } if !opEnable { rctx.SetStatus(http.StatusMethodNotAllowed) return } // Execution of the operation ctx := rctx.GetContext() res, code, err := hand.imop.ManifestExists(ctx, params) if err != nil { hand.logg.Errorf("ManifestExist error: %v", err) } else if code == http.StatusOK { rctx.SetHeader("Content-Length", res.ContentLength) rctx.SetHeader("Content-Type", res.ContentType) rctx.SetHeader("Docker-Content-Digest", res.DockerContentDigest) } hand.logg.Debugf(res.ContentType) hand.logg.Debugf(res.DockerContentDigest) rctx.SetStatus(code) } // GetProperty godoc // // @Summary Put manifest // @Description Put manifest // @Tags manifest // @Param name path string true "Manifest path" // @Param reference path string true "Manifest tag" // @Param Content-Length header string true "Manifest size" // @Param Content-Type header string true "Manifest type" // @Success 200 // @Failure 404,405,500 // @Router /v2/{name}/manifests/{reference} [PUT] func (hand *Handler) PutManifest(rctx *router.Context) { //hand.DumpHeaders("PutManifest headers", rctx) contentType := rctx.GetHeader("Content-Type") contentLength := rctx.GetHeader("Content-Length") name, _ := rctx.GetSubpath("name") reference, _ := rctx.GetSubpath("reference") params := &imageoper.PutManifestParams{ ContentType: contentType, ContentLength: contentLength, Name: name, Reference: reference, Reader: rctx.Request.Body, } // Rigth checking operatorID, _ := rctx.GetString(userTag) opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteImages, params.Name) if err != nil { rctx.SetStatus(http.StatusInternalServerError) return } if !opEnable { rctx.SetStatus(http.StatusMethodNotAllowed) return } // Execution of the operation ctx := rctx.GetContext() res, code, err := hand.imop.PutManifest(ctx, params) if err != nil { hand.logg.Errorf("PutManifest error: %v", err) } else { rctx.SetHeader("Location", res.Location) } rctx.SetStatus(code) } // GetProperty godoc // // @Summary Get manifest // @Description Get manifest // @Tags manifest // @Param name path string true "Manifest path" // @Param reference path string true "Manifest tag" // @Success 200 // @Failure 404,405,500 // @Router /v2/{name}/manifests/{reference} [GET] // @Header 200 {string} Content-Length "Manifest size" // @Header 200 {string} Content-Type "Manifest type" // @Header 200 {string} Docker-Content-Digest "Manigest digest" func (hand *Handler) GetManifest(rctx *router.Context) { name, _ := rctx.GetSubpath("name") reference, _ := rctx.GetSubpath("reference") //hand.DumpHeaders("GetManigest", rctx) params := &imageoper.GetManifestParams{ Name: name, Reference: reference, } // Rigth checking operatorID, _ := rctx.GetString(userTag) opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadImages, params.Name) if err != nil { rctx.SetStatus(http.StatusInternalServerError) return } if !opEnable { rctx.SetStatus(http.StatusMethodNotAllowed) return } // Execution of the operation ctx := rctx.GetContext() res, code, err := hand.imop.GetManifest(ctx, params) if err != nil { hand.logg.Errorf("GetManifest error: %v", err) rctx.SetStatus(code) return } if code == http.StatusOK { //hand.logg.Debugf("GetManifest type: %s", res.ContentType) //hand.logg.Debugf("GetManifest payload: %s", res.Payload) rctx.SetHeader("Content-Length", res.ContentLength) //rctx.SetHeader("Content-Type", res.ContentType) rctx.SetHeader("Docker-Content-Digest", res.DockerContentDigest) rctx.SendBytes(code, res.ContentType, []byte(res.Payload)) return } rctx.SetStatus(code) } // GetProperty godoc // // @Summary Delete manifest // @Description Delete manifest // @Tags manifest // @Param name path string true "Manifest path" // @Param reference path string true "Manifest tag" // @Success 202 // @Failure 404,405,500 // @Router /v2/{name}/manifests/{reference} [DELETE] func (hand *Handler) DeleteManifest(rctx *router.Context) { name, _ := rctx.GetSubpath("name") reference, _ := rctx.GetSubpath("reference") params := &imageoper.DeleteManifestParams{ Name: name, Reference: reference, } // Rigth checking operatorID, _ := rctx.GetString(userTag) opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteImages, params.Name) if err != nil { rctx.SetStatus(http.StatusInternalServerError) return } if !opEnable { rctx.SetStatus(http.StatusMethodNotAllowed) return } // Execution of the operation ctx := rctx.GetContext() _, code, err := hand.imop.DeleteManifest(ctx, params) if err != nil { hand.logg.Errorf("DeleteManifest error: %v", err) } rctx.SetStatus(code) } // GET /v2//referrers/ 200 404/400 // GET /v2//referrers/?artifactType= 200 404/400 // GetProperty godoc // // @Summary Get manifest referer // @Description Get manifest referer // @Tags manifest // @Param name path string true "Manifest path" // @Param digest path string true "Manifest digest" // @Failure 404,405,500 // @Router /v2/{name}/referrers/{digest} [GET] // @Success 200 {object} imageoper.GetRefererResult.Reference // @Produce application/json func (hand *Handler) GetReferer(rctx *router.Context) { name, _ := rctx.GetSubpath("name") digest, _ := rctx.GetSubpath("digest") params := &imageoper.GetRefererParams{ Name: name, Digest: digest, } // Rigth checking operatorID, _ := rctx.GetString(userTag) opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadImages, params.Name) if err != nil { rctx.SetStatus(http.StatusInternalServerError) return } if !opEnable { rctx.SetStatus(http.StatusMethodNotAllowed) return } // Execution of the operation res, code, err := hand.imop.GetReferer(rctx.Ctx, params) if err != nil { hand.logg.Errorf("GetReferer error: %v", err) } rctx.SendText(code, res.Reference) } // GET /v2//tags/list 200 404 // GET /v2//tags/list?n=&last= // GetProperty godoc // // @Summary List manifest tags // @Description List manifest tags // @Tags manifest // @Param name path string true "Manifest path" // @Failure 404,405,500 // @Router /v2/{name}/tags/list [GET] // @Success 200 {object} imageoper.GetTagsResult.TagDescr // @Produce application/json func (hand *Handler) GetTags(rctx *router.Context) { name, _ := rctx.GetSubpath("name") params := &imageoper.GetTagsParams{ Name: name, } // Rigth checking operatorID, _ := rctx.GetString(userTag) opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadImages, params.Name) if err != nil { rctx.SetStatus(http.StatusInternalServerError) return } if !opEnable { rctx.SetStatus(http.StatusMethodNotAllowed) return } // Execution of the operation ctx := rctx.GetContext() res, code, err := hand.imop.GetTags(ctx, params) if err != nil { hand.logg.Errorf("GetTags error: %v", err) } rctx.SendJSON(code, res.TagDescr) } // GET /v2/_catalog?n=1000 200 404 // GetProperty godoc // // @Summary List manifests // @Description List manifests // @Tags manifest // @Failure 404,405,500 // @Router /v2/_catalog [GET] // @Success 200 {object} imageoper.ListManifestsResult.Repositories // @Produce application/json func (hand *Handler) ListManifests(rctx *router.Context) { params := &imageoper.ListManifestsParams{} // Rigth checking operatorID, _ := rctx.GetString(userTag) opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadImages, "_catalog") if err != nil { rctx.SetStatus(http.StatusInternalServerError) return } if !opEnable { rctx.SetStatus(http.StatusMethodNotAllowed) return } // Execution of the operation ctx := rctx.GetContext() res, code, err := hand.imop.ListManifests(ctx, params) if err != nil { hand.logg.Errorf("ListManifests error: %v", err) } rctx.SendJSON(code, res.Repositories) } // GetProperty godoc // // @Summary Check images // @Description Check images // @Tags manifest // @Failure 404,405,500 // @Router /v2/checker/{name} [POST] // @Router /v2/checker/ [POST] // @Success 200 {object} imageoper.CheckImagesResult.Repositories // @Produce application/json func (hand *Handler) CheckImages(rctx *router.Context) { name, _ := rctx.GetSubpath("name") params := &imageoper.CheckImagesParams{ Name: name, } // Rigth checking operatorID, _ := rctx.GetString(userTag) opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteImages, name) if err != nil { rctx.SetStatus(http.StatusInternalServerError) return } if !opEnable { rctx.SetStatus(http.StatusMethodNotAllowed) return } // Execution of the operation ctx := rctx.GetContext() res, code, err := hand.imop.CheckImages(ctx, params) if err != nil { hand.logg.Errorf("CheckImages error: %v", err) } rctx.SendJSON(code, res.Repositories) }