diff --git a/ociclient/authbas.go b/ociclient/authbas.go deleted file mode 100644 index 1b555eb..0000000 --- a/ociclient/authbas.go +++ /dev/null @@ -1,20 +0,0 @@ -package repocli - -import ( - "encoding/base64" -) - -type Authenticator interface { - MakeHeader(user, pass string) (key, value string, err error) -} - -type BasicAuthenticator struct{} - -func NewBasicAuthenticator() *BasicAuthenticator { - return &BasicAuthenticator{} -} - -func (auth *BasicAuthenticator) MakeHeader(user, pass string) (string, string, error) { - pair := base64.StdEncoding.EncodeToString([]byte(user + ":" + pass)) - return "Authorization", "Basic " + pair, nil -} diff --git a/ociclient/blobexist.go b/ociclient/blobexist.go deleted file mode 100644 index 3f4ab09..0000000 --- a/ociclient/blobexist.go +++ /dev/null @@ -1,50 +0,0 @@ -package repocli - -import ( - "context" - "fmt" - "net/http" - "strconv" -) - -func (cli *Client) BlobExists(ctx context.Context, rawrepo string, digest string) (bool, int64, error) { - var err error - var exist bool - var size int64 - - ref, err := NewRepository(rawrepo) - if err != nil { - return exist, size, err - } - uri := ref.Blob(digest) - - fmt.Println(uri) - req, err := http.NewRequestWithContext(ctx, http.MethodHead, uri, nil) - if err != nil { - return exist, size, err - } - req.Header.Set("User-Agent", cli.userAgent) - req.Header.Set("Accept", "*/*") - - resp, err := cli.httpClient.Do(req) - if err != nil { - return exist, size, err - } - defer resp.Body.Close() - - if resp.StatusCode == http.StatusNotFound { - return exist, size, err - } - if resp.StatusCode != http.StatusOK { - err := fmt.Errorf("Unxected response code %s", resp.Status) - return exist, size, err - } - contentLength := resp.Header.Get("Content-Length") - size, err = strconv.ParseInt(contentLength, 10, 64) - if err != nil { - return exist, size, err - } - - exist = true - return exist, size, err -} diff --git a/ociclient/client.go b/ociclient/client.go deleted file mode 100644 index 0983196..0000000 --- a/ociclient/client.go +++ /dev/null @@ -1,136 +0,0 @@ -package repocli - -import ( - "crypto/tls" - "encoding/base64" - "net/http" -) - -type Client struct { - httpClient *http.Client - userAgent string -} - -func NewClient() *Client { - defaultTripper := NewDefaultTransport() - httpClient := &http.Client{ - Transport: defaultTripper, - } - return &Client{ - httpClient: httpClient, - userAgent: "ociClient/1.0", - } -} - -func NewClientWithTransport(transport http.RoundTripper, mwFunc ...MiddlewareFunc) *Client { - if transport == nil { - transport = NewDefaultTransport() - } - httpClient := &http.Client{ - Transport: transport, - } - return &Client{ - httpClient: httpClient, - userAgent: "ociClient/1.0", - } -} - -func (cli *Client) SetTransport(transport http.RoundTripper) { - cli.httpClient.Transport = transport -} - -type MiddlewareFunc func(next http.RoundTripper) http.RoundTripper - -func (cli *Client) UseMiddleware(mwFunc MiddlewareFunc) { - cli.httpClient.Transport = mwFunc(cli.httpClient.Transport) -} - -// ExampleMiddleware -func NewExampleMiddleware() MiddlewareFunc { - return func(next http.RoundTripper) http.RoundTripper { - return newExampleTransport(next) - } -} - -type ExampleTransport struct { - next http.RoundTripper -} - -func newExampleTransport(next http.RoundTripper) *ExampleTransport { - return &ExampleTransport{ - next: next, - } -} - -func (tran ExampleTransport) RoundTrip(req *http.Request) (*http.Response, error) { - return tran.next.RoundTrip(req) -} - -// BasicAuthMiddleware -func NewBasicAuthMiddleware(user, pass string) MiddlewareFunc { - return func(next http.RoundTripper) http.RoundTripper { - return newBasicAuthMW(next, user, pass) - } -} - -type BasicAuthMW struct { - user, pass string - next http.RoundTripper -} - -func newBasicAuthMW(next http.RoundTripper, user, pass string) *BasicAuthMW { - return &BasicAuthMW{ - user: user, - pass: pass, - next: next, - } -} - -func (tran BasicAuthMW) RoundTrip(req *http.Request) (*http.Response, error) { - pair := base64.StdEncoding.EncodeToString([]byte(tran.user + ":" + tran.pass)) - req.Header.Set("Authorization", "Basic "+pair) - return tran.next.RoundTrip(req) -} - -// BearerAuthMiddleware -func NewBearerAuthMiddleware(token string) MiddlewareFunc { - return func(next http.RoundTripper) http.RoundTripper { - return newBearerAuthMW(next, token) - } -} - -type BearerAuthMW struct { - token string - next http.RoundTripper -} - -func newBearerAuthMW(next http.RoundTripper, token string) *BearerAuthMW { - return &BearerAuthMW{ - token: token, - next: next, - } -} - -func (tran BearerAuthMW) RoundTrip(req *http.Request) (*http.Response, error) { - req.Header.Set("Authorization", "Bearer "+tran.token) - return tran.next.RoundTrip(req) -} - -// DefaultTransport -type DefaultTransport struct { - transport http.RoundTripper -} - -func NewDefaultTransport() *DefaultTransport { - return &DefaultTransport{ - transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - }, - } -} - -func (wrap *DefaultTransport) RoundTrip(req *http.Request) (*http.Response, error) { - return wrap.transport.RoundTrip(req) -} diff --git a/ociclient/client_test.go b/ociclient/client_test.go deleted file mode 100644 index efcb220..0000000 --- a/ociclient/client_test.go +++ /dev/null @@ -1,159 +0,0 @@ -package repocli - -import ( - "github.com/stretchr/testify/require" - - "bytes" - "context" - "encoding/json" - "fmt" - "math/rand" - "testing" - "time" -) - -func xxxTestClientGetManifest(t *testing.T) { - rawrepo := "mirror.gcr.io/alpine" - tags := []string{ - "3.20.0", - "sha256:29e5ba63e79337818e6c63cfcc68e2ab4e9ca483853b2de303bfbfba9372426c", - } - for _, tag := range tags { - cli := NewClient() - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - exist, mime, man, err := cli.GetManifest(ctx, rawrepo, tag) - require.NoError(t, err) - require.True(t, exist) - - fmt.Printf("Type: %s\n", mime) - buffer := bytes.NewBuffer(nil) - err = json.Indent(buffer, man, " ", " ") - require.NoError(t, err) - //fmt.Printf("%s\n", buffer.String()) - } -} - -func xxxTestClientManifestExists(t *testing.T) { - rawrepo := "mirror.gcr.io/alpine" - tags := []string{ - "3.20.0", - "sha256:29e5ba63e79337818e6c63cfcc68e2ab4e9ca483853b2de303bfbfba9372426c", - } - for _, tag := range tags { - - cli := NewClient() - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - exist, mime, size, csum, err := cli.ManifestExists(ctx, rawrepo, tag) - require.NoError(t, err) - require.True(t, exist) - - fmt.Printf("MIME: %s\n", mime) - fmt.Printf("Size: %d\n", size) - fmt.Printf("Sum: %s\n", csum) - fmt.Printf("Typ: %d\n", DigestType(csum)) - } -} - -func xxxTestClientBlobExists(t *testing.T) { - rawrepos := []string{ - "mirror.gcr.io/alpine", - } - for _, rawrepo := range rawrepos { - cli := NewClient() - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - digest := "sha256:3b8747b05489980f63da1d2b8e5a444c55777f69540394397b0bc1c76c3e41f2" - exist, size, err := cli.BlobExists(ctx, rawrepo, digest) - require.NoError(t, err) - require.True(t, exist) - - fmt.Printf("Size: %d\n", size) - } -} - -func xxxTestClientGetBlob(t *testing.T) { - rawrepos := []string{ - "mirror.gcr.io/alpine", - } - for _, rawrepo := range rawrepos { - cli := NewClient() - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - buffer := bytes.NewBuffer(nil) - digest := "sha256:3b8747b05489980f63da1d2b8e5a444c55777f69540394397b0bc1c76c3e41f2" - exist, err := cli.GetBlob(ctx, rawrepo, buffer, digest) - require.NoError(t, err) - require.True(t, exist) - fmt.Printf("Size: %d\n", len(buffer.Bytes())) - } -} - -func xxxxTestClientGetUpload(t *testing.T) { - rawrepos := []string{ - "mstore:mstore@localhost:1025/alpine:3.20.0", - } - cli := NewClient() - cli.UseMiddleware(NewBasicAuthMiddleware("mstore", "mstore")) - - for _, rawrepo := range rawrepos { - var err error - var loc string - { - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - loc, err = cli.GetUpload(ctx, rawrepo) - require.NoError(t, err) - fmt.Printf("Upload Location: %s\n", loc) - } - { - srcsize := 1024 + 145 - srcdata := make([]byte, srcsize) - _, err = rand.Read(srcdata) - require.NoError(t, err) - - src := bytes.NewReader(srcdata) - //digest := SHA256Digest(srcdata) - - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - bloc, err := cli.PatchUpload(ctx, rawrepo, src, loc, int64(len(srcdata))) - require.NoError(t, err) - fmt.Printf("Path Location: %s\n", bloc) - } - { - srcsize := 1024 + 145 - srcdata := make([]byte, srcsize) - _, err = rand.Read(srcdata) - require.NoError(t, err) - - src := bytes.NewReader(srcdata) - digest := SHA256Digest(srcdata) - - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - bloc, err := cli.PutUpload(ctx, rawrepo, src, loc, digest, int64(len(srcdata))) - require.NoError(t, err) - fmt.Printf("Put blob Location: %s\n", bloc) - } - - } -} - -func xxxxTestClientGetToken(t *testing.T) { - var token string - var err error - { - cli := NewClient() - cli.UseMiddleware(NewBasicAuthMiddleware("onborodin", "2Albert334")) - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - token, err = cli.GetToken(ctx, "https://auth.docker.io/token") - require.NoError(t, err) - - } - fmt.Printf("Token: %s\n", token) - { - rawrepo := "docker.io/onborodin/toolbox:0.18" - cli := NewClient() - cli.UseMiddleware(NewBearerAuthMiddleware(token)) - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - loc, err := cli.GetUpload(ctx, rawrepo) - require.NoError(t, err) - fmt.Printf("Upload Location: %s\n", loc) - } - -} diff --git a/ociclient/copyctx.go b/ociclient/copyctx.go deleted file mode 100644 index b9a8acf..0000000 --- a/ociclient/copyctx.go +++ /dev/null @@ -1,39 +0,0 @@ -package repocli - -import ( - "context" - "errors" - "io" -) - -func Copy(ctx context.Context, writer io.Writer, reader io.Reader) (int64, error) { - var err error - var size int64 - var halt bool - buffer := make([]byte, 1024*4) - for { - select { - case <-ctx.Done(): - err = errors.New("Break copy by context") - break - default: - } - rsize, err := reader.Read(buffer) - if err == io.EOF { - err = nil - halt = true - } - if err != nil { - return size, err - } - wsize, err := writer.Write(buffer[0:rsize]) - size += int64(wsize) - if err != nil { - return size, err - } - if halt { - break - } - } - return size, err -} diff --git a/ociclient/copyctx_test.go b/ociclient/copyctx_test.go deleted file mode 100644 index b6c991e..0000000 --- a/ociclient/copyctx_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package repocli - -import ( - "github.com/stretchr/testify/require" - - "bytes" - "context" - "fmt" - "math/rand" - "testing" -) - -func TestCopy(t *testing.T) { - srcsize := 1024 + 145 - srcdata := make([]byte, srcsize) - _, err := rand.Read(srcdata) - require.NoError(t, err) - - src := bytes.NewReader(srcdata) - dst := bytes.NewBuffer(nil) - - ctx := context.Background() - recsize, err := Copy(ctx, dst, src) - require.NoError(t, err) - - fmt.Printf("Size: %d %d\n", recsize, srcsize) - require.Equal(t, int64(srcsize), recsize) -} diff --git a/ociclient/delman.go b/ociclient/delman.go deleted file mode 100644 index 0050a8f..0000000 --- a/ociclient/delman.go +++ /dev/null @@ -1,38 +0,0 @@ -package repocli - -import ( - "context" - "fmt" - "net/http" -) - -func (cli *Client) DeleteManifest(ctx context.Context, rawrepo, tag string) (bool, error) { - var err error - var exist bool - - ref, err := NewRepository(rawrepo) - if err != nil { - return exist, err - } - uri := ref.Manifest(tag) - req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri, nil) - if err != nil { - return exist, err - } - req.Header.Set("User-Agent", cli.userAgent) - req.Header.Set("Accept", "*/*") - resp, err := cli.httpClient.Do(req) - if err != nil { - return exist, err - } - defer resp.Body.Close() - if resp.StatusCode == http.StatusNotFound { - return exist, err - } - if resp.StatusCode != http.StatusOK { - err := fmt.Errorf("Unxected response code %s", resp.Status) - return exist, err - } - exist = true - return exist, err -} diff --git a/ociclient/digest.go b/ociclient/digest.go deleted file mode 100644 index 2eab175..0000000 --- a/ociclient/digest.go +++ /dev/null @@ -1,49 +0,0 @@ -package repocli - -import ( - "crypto/sha256" - "crypto/sha512" - "encoding/hex" - "strings" -) - -func SHA256Digest(src []byte) string { - hasher := sha256.New() - hasher.Write(src) - sum := hasher.Sum(nil) - return "sha256:" + hex.EncodeToString(sum) -} - -func SHA512Digest(src []byte) string { - hasher := sha512.New() - hasher.Write(src) - sum := hasher.Sum(nil) - return "sha512:" + hex.EncodeToString(sum) -} - -const ( - Undefined int = iota - SHA256 - SHA512 -) - -func DigestType(digest string) int { - var err error - var typ int - digest = strings.ToLower(digest) - digest = strings.TrimPrefix(digest, "sha256:") - digest = strings.TrimPrefix(digest, "sha512:") - decoded, err := hex.DecodeString(digest) - if err != nil { - return Undefined - } - switch len(decoded) { - case 32: - typ = SHA256 - case 64: - typ = SHA512 - default: - typ = Undefined - } - return typ -} diff --git a/ociclient/getblob.go b/ociclient/getblob.go deleted file mode 100644 index ee92aab..0000000 --- a/ociclient/getblob.go +++ /dev/null @@ -1,53 +0,0 @@ -package repocli - -import ( - "context" - "fmt" - "io" - "net/http" - "strconv" -) - -func (cli *Client) GetBlob(ctx context.Context, rawrepo string, writer io.Writer, digest string) (bool, error) { - var err error - var exist bool - - ref, err := NewRepository(rawrepo) - if err != nil { - return exist, err - } - uri := ref.Blob(digest) - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) - if err != nil { - return exist, err - } - req.Header.Set("User-Agent", cli.userAgent) - req.Header.Set("Accept", "*/*") - resp, err := cli.httpClient.Do(req) - if err != nil { - return exist, err - } - defer resp.Body.Close() - - if resp.StatusCode == http.StatusNotFound { - return exist, err - } - if resp.StatusCode != http.StatusOK { - err := fmt.Errorf("Unexpected response code %s", resp.Status) - return exist, err - } - contentLength := resp.Header.Get("Content-Length") - blobSize, err := strconv.ParseInt(contentLength, 10, 64) - if err != nil { - return exist, err - } - - recSize, err := Copy(ctx, writer, resp.Body) - if blobSize != recSize { - err := fmt.Errorf("Mismatch declared and actual body size, %d and %d", blobSize, recSize) - return exist, err - } - exist = true - return exist, err -} diff --git a/ociclient/getman.go b/ociclient/getman.go deleted file mode 100644 index a51dc84..0000000 --- a/ociclient/getman.go +++ /dev/null @@ -1,90 +0,0 @@ -package repocli - -import ( - "bytes" - "context" - "errors" - "fmt" - "net/http" - "strconv" - "strings" -) - -func (cli *Client) GetManifest(ctx context.Context, rawrepo, tag string) (bool, string, []byte, error) { - var err error - var exist bool - var mime string - var man []byte - - ref, err := NewRepository(rawrepo) - if err != nil { - return exist, mime, man, err - } - uri := ref.Manifest(tag) - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) - if err != nil { - return exist, mime, man, err - } - req.Header.Set("User-Agent", cli.userAgent) - req.Header.Set("Accept", "*/*") - resp, err := cli.httpClient.Do(req) - if err != nil { - return exist, mime, man, err - } - defer resp.Body.Close() - - if resp.StatusCode == http.StatusNotFound { - return exist, mime, man, err - } - if resp.StatusCode != http.StatusOK { - err := fmt.Errorf("Unxected response code %s", resp.Status) - return exist, mime, man, err - } - contentLength := resp.Header.Get("Content-Length") - if contentLength == "" { - err = errors.New("Empty Content-Length header") - return exist, mime, man, err - } - manSize, err := strconv.ParseInt(contentLength, 10, 64) - if err != nil { - return exist, mime, man, err - } - mime = resp.Header.Get("Content-Type") - if mime == "" { - err := fmt.Errorf("Empty MIME type declaration") - return exist, mime, man, err - } - buffer := bytes.NewBuffer(nil) - recSize, err := Copy(ctx, buffer, resp.Body) - if manSize != recSize { - err := fmt.Errorf("Mismatch declared and actual body size, %d and %d", manSize, recSize) - return exist, mime, man, err - } - man = buffer.Bytes() - - csum := resp.Header.Get("Docker-Content-Digest") - if csum == "" { - err := fmt.Errorf("Empty digest declaration") - return exist, mime, man, err - } - csum = strings.ToLower(csum) - switch DigestType(csum) { - case SHA256: - if csum != SHA256Digest(man) { - err := fmt.Errorf("Mismatch digest and actual declaration") - return exist, mime, man, err - } - case SHA512: - if csum != SHA256Digest(man) { - err := fmt.Errorf("Mismatch digest and actual declaration") - return exist, mime, man, err - } - default: - err := fmt.Errorf("Unknown digest type: %s", csum) - return exist, mime, man, err - } - - exist = true - return exist, mime, man, err -} diff --git a/ociclient/getupload.go b/ociclient/getupload.go deleted file mode 100644 index e4c3cd6..0000000 --- a/ociclient/getupload.go +++ /dev/null @@ -1,44 +0,0 @@ -package repocli - -import ( - "context" - "fmt" - "net/http" -) - -func (cli *Client) GetUpload(ctx context.Context, rawrepo string) (string, error) { - var err error - var loc string - - ref, err := NewRepository(rawrepo) - if err != nil { - return loc, err - } - uri := ref.Upload() - - req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, nil) - if err != nil { - return loc, err - } - req.Header.Set("User-Agent", cli.userAgent) - req.Header.Set("Accept", "*/*") - resp, err := cli.httpClient.Do(req) - if err != nil { - return loc, err - } - defer resp.Body.Close() - - fmt.Printf("=== %++v\n", resp.Header) - - if resp.StatusCode != http.StatusAccepted { - err := fmt.Errorf("Unxected response code %s", resp.Status) - return loc, err - } - loc = resp.Header.Get("Location") - - if loc == "" { - err := fmt.Errorf("Empty location declaration") - return loc, err - } - return loc, err -} diff --git a/ociclient/go.mod b/ociclient/go.mod deleted file mode 100644 index e1c0b83..0000000 --- a/ociclient/go.mod +++ /dev/null @@ -1,15 +0,0 @@ -module client - -go 1.25.0 - -require ( - github.com/opencontainers/image-spec v1.1.0 - github.com/stretchr/testify v1.11.1 -) - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/ociclient/go.sum b/ociclient/go.sum deleted file mode 100644 index e4da8cc..0000000 --- a/ociclient/go.sum +++ /dev/null @@ -1,16 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= -github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/ociclient/jwt.go b/ociclient/jwt.go deleted file mode 100644 index 6c1b218..0000000 --- a/ociclient/jwt.go +++ /dev/null @@ -1,63 +0,0 @@ -package repocli - -import ( - "bytes" - "context" - "fmt" - "net/http" - //"strconv" - //"strings" - "encoding/json" - "time" -) - -type JWT struct { - Token string `json:"token"` - AccessToken string `json:"access_token"` - ExpiresIn int `json:"expires_in"` - IssuedAt time.Time `json:"issued_at"` -} - -func (cli *Client) GetToken(ctx context.Context, uri string) (string, error) { - var err error - var token string - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) - if err != nil { - return token, err - } - req.Header.Set("User-Agent", cli.userAgent) - req.Header.Set("Accept", "*/*") - resp, err := cli.httpClient.Do(req) - if err != nil { - return token, err - } - defer resp.Body.Close() - - if resp.StatusCode == http.StatusNotFound { - return token, err - } - if resp.StatusCode != http.StatusOK { - err := fmt.Errorf("Unxected response code %s", resp.Status) - return token, err - } - mime := resp.Header.Get("Content-Type") - if mime != "application/json" { - err := fmt.Errorf("Empty MIME type declaration") - return token, err - } - buffer := bytes.NewBuffer(nil) - recSize, err := Copy(ctx, buffer, resp.Body) - if recSize == 0 { - err := fmt.Errorf("Zero actual body size") - return token, err - } - tokenJson := buffer.Bytes() - jwt := &JWT{} - err = json.Unmarshal(tokenJson, jwt) - if err != nil { - return token, err - } - token = jwt.Token - return token, err -} diff --git a/ociclient/manexist.go b/ociclient/manexist.go deleted file mode 100644 index f4855ac..0000000 --- a/ociclient/manexist.go +++ /dev/null @@ -1,60 +0,0 @@ -package repocli - -import ( - "context" - "fmt" - "net/http" - "strconv" -) - -func (cli *Client) ManifestExists(ctx context.Context, rawrepo, tag string) (bool, string, int64, string, error) { - var err error - var exist bool - var mime string - var size int64 - var csum string - - ref, err := NewRepository(rawrepo) - if err != nil { - return exist, mime, size, csum, err - } - uri := ref.Manifest(tag) - - req, err := http.NewRequestWithContext(ctx, http.MethodHead, uri, nil) - if err != nil { - return exist, mime, size, csum, err - } - req.Header.Set("User-Agent", cli.userAgent) - req.Header.Set("Accept", "*/*") - resp, err := cli.httpClient.Do(req) - if err != nil { - return exist, mime, size, csum, err - } - defer resp.Body.Close() - - if resp.StatusCode == http.StatusNotFound { - return exist, mime, size, csum, err - } - if resp.StatusCode != http.StatusOK { - err := fmt.Errorf("Unxected response code %s", resp.Status) - return exist, mime, size, csum, err - } - contentLength := resp.Header.Get("Content-Length") - size, err = strconv.ParseInt(contentLength, 10, 64) - if err != nil { - return exist, mime, size, csum, err - } - mime = resp.Header.Get("Content-Type") - if mime == "" { - err := fmt.Errorf("Empty MIME type declaration") - return exist, mime, size, csum, err - } - csum = resp.Header.Get("Docker-Content-Digest") - if csum == "" { - err := fmt.Errorf("Empty digest declaration") - return exist, mime, size, csum, err - } - - exist = true - return exist, mime, size, csum, err -} diff --git a/ociclient/mimetyp.go b/ociclient/mimetyp.go deleted file mode 100644 index c5da23f..0000000 --- a/ociclient/mimetyp.go +++ /dev/null @@ -1,6 +0,0 @@ -package repocli - -const ( - MediaTypeDDMLv2 = "application/vnd.docker.distribution.manifest.list.v2+json" - MediaTypeDDMv2 = "application/vnd.docker.distribution.manifest.v2+json" -) diff --git a/ociclient/pathupload.go b/ociclient/pathupload.go deleted file mode 100644 index f1bc1b6..0000000 --- a/ociclient/pathupload.go +++ /dev/null @@ -1,45 +0,0 @@ -package repocli - -import ( - "context" - "fmt" - "io" - "net/http" - "strconv" -) - -func (cli *Client) PatchUpload(ctx context.Context, rawrepo string, src io.Reader, uploc string, size int64) (string, error) { - var err error - var ouloc string - - ref, err := NewRepository(rawrepo) - if err != nil { - return ouloc, err - } - uri, err := ref.Patch(uploc) - if err != nil { - return ouloc, err - } - req, err := http.NewRequestWithContext(ctx, http.MethodPatch, uri, src) - if err != nil { - return ouloc, err - } - req.Header.Set("User-Agent", cli.userAgent) - req.Header.Set("Content-Type", "application/octet-stream") - req.Header.Set("Content-Length", strconv.FormatInt(size, 10)) - resp, err := cli.httpClient.Do(req) - if err != nil { - return ouloc, err - } - resp.Body.Close() - if resp.StatusCode != http.StatusAccepted { - err = fmt.Errorf("Upload not accepted, code %d", resp.StatusCode) - return ouloc, err - } - ouloc = resp.Header.Get("Location") - if ouloc == "" { - err := fmt.Errorf("Empty blob location declaration") - return ouloc, err - } - return ouloc, err -} diff --git a/ociclient/pullimage.go b/ociclient/pullimage.go deleted file mode 100644 index c29e78b..0000000 --- a/ociclient/pullimage.go +++ /dev/null @@ -1,104 +0,0 @@ -package repocli - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - - ocispec "github.com/opencontainers/image-spec/specs-go/v1" -) - -const ( - MediaTypeOIIv1 = "application/vnd.oci.image.index.v1+json" - MediatypeDDMLv2 = "application/vnd.docker.distribution.manifest.list.v2+json" - - MediatypeDDMv2 = "application/vnd.docker.distribution.manifest.v2+json" - MediaTypeOIMv1 = "application/vnd.oci.image.manifest.v1+json" -) - -type Downloader struct { - cli *Client -} - -func NewDownloader(client *Client) *Downloader { - return &Downloader{ - cli: client, - } -} - -func (down *Downloader) Pull(ctx context.Context, rawref, dir, os, arch string) error { - var err error - ref, err := NewReference(rawref) - if err != nil { - return err - } - rawrepo := ref.Repo() - tag := ref.Tag() - - exist, mime, man, err := down.cli.GetManifest(ctx, rawrepo, tag) - if err != nil { - return err - } - if !exist { - err = errors.New("Manifest not found") - return err - } - - if mime == MediaTypeOIIv1 || mime == MediatypeDDMLv2 { - var index ocispec.Index - err = json.Unmarshal(man, &index) - if err != nil { - return err - } - for _, descr := range index.Manifests { - if descr.Platform != nil { - cond := descr.Platform.Architecture == arch - cond = cond && descr.Platform.OS == os - if cond { - tag = descr.Digest.String() - } - } - } - } - fmt.Printf("Tag: %s\n", tag) - exist, mime, man, err = down.cli.GetManifest(ctx, rawrepo, tag) - if err != nil { - return err - } - fmt.Printf("Mime: %s\n", mime) - if !exist { - err = errors.New("Manifest not found") - return err - } - if mime != MediaTypeOIMv1 && mime != MediatypeDDMv2 { - err = errors.New("Unknown manifest media type") - return err - } - var manifest ocispec.Manifest - err = json.Unmarshal(man, &manifest) - if err != nil { - return err - } - "oci-layout" - "index.json" - - layers := make([]ocispec.Descriptor, 0) - layers = append(layers, manifest.Config) - layers = append(layers, manifest.Layers...) - for _, layer := range layers { - digest := layer.Digest.String() - exist, err := down.cli.GetBlob(ctx, rawrepo, io.Discard, digest) - if err != nil { - return err - } - if !exist { - err = errors.New("Layer not found") - return err - } - fmt.Printf("Layer type: %s\n", layer.MediaType) - - } - return err -} diff --git a/ociclient/pullimage_test.go b/ociclient/pullimage_test.go deleted file mode 100644 index 41aeb1f..0000000 --- a/ociclient/pullimage_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package repocli - -import ( - "github.com/stretchr/testify/require" - - //"fmt" - "context" - "testing" - "time" -) - -func TestPullImage(t *testing.T) { - - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - cli := NewClientWithTransport(nil, nil) - require.NotNil(t, cli) - - down := NewDownloader(cli) - require.NotNil(t, down) - - rawref := "mirror.gcr.io/alpine:3.20.0" - destdir := "qwert" - err := down.Pull(ctx, rawref, destdir, "linux", "amd64") - require.NoError(t, err) -} diff --git a/ociclient/putman.go b/ociclient/putman.go deleted file mode 100644 index e199cc2..0000000 --- a/ociclient/putman.go +++ /dev/null @@ -1,42 +0,0 @@ -package repocli - -import ( - "bytes" - "context" - "fmt" - "net/http" -) - -func (cli *Client) PutManifest(ctx context.Context, rawrepo, tag string, man []byte, mime string) error { - var err error - - ref, err := NewRepository(rawrepo) - if err != nil { - return err - } - uri := ref.Manifest(tag) - - buffer := bytes.NewBuffer(man) - req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, buffer) - if err != nil { - return err - } - req.Header.Set("User-Agent", cli.userAgent) - req.Header.Set("Docker-Content-Digest", SHA256Digest(man)) - req.Header.Set("Content-Type", mime) - resp, err := cli.httpClient.Do(req) - if err != nil { - return err - } - resp.Body.Close() - if resp.StatusCode != http.StatusAccepted { - err = fmt.Errorf("Manifest not accepted, code %d", resp.StatusCode) - return err - } - loc := resp.Header.Get("Location") - if loc == "" { - err := fmt.Errorf("Empty manifest location declaration") - return err - } - return err -} diff --git a/ociclient/putupload.go b/ociclient/putupload.go deleted file mode 100644 index 31065ab..0000000 --- a/ociclient/putupload.go +++ /dev/null @@ -1,45 +0,0 @@ -package repocli - -import ( - "context" - "fmt" - "io" - "net/http" - "strconv" -) - -func (cli *Client) PutUpload(ctx context.Context, rawrepo string, src io.Reader, uploc, digest string, size int64) (string, error) { - var err error - var bloc string - - ref, err := NewRepository(rawrepo) - if err != nil { - return bloc, err - } - uri, err := ref.Put(uploc, digest) - if err != nil { - return bloc, err - } - req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, src) - if err != nil { - return bloc, err - } - req.Header.Set("User-Agent", cli.userAgent) - req.Header.Set("Content-Type", "application/octet-stream") - req.Header.Set("Content-Length", strconv.FormatInt(size, 10)) - resp, err := cli.httpClient.Do(req) - if err != nil { - return bloc, err - } - resp.Body.Close() - if resp.StatusCode != http.StatusCreated { - err = fmt.Errorf("Upload not accepted, code %d", resp.StatusCode) - return bloc, err - } - bloc = resp.Header.Get("Location") - if bloc == "" { - err := fmt.Errorf("Empty blob location declaration") - return bloc, err - } - return bloc, err -} diff --git a/ociclient/reference.go b/ociclient/reference.go deleted file mode 100644 index a08a749..0000000 --- a/ociclient/reference.go +++ /dev/null @@ -1,56 +0,0 @@ -package repocli - -import ( - "errors" - "net/url" - "path" - "strings" -) - -type Reference struct { - urlobj *url.URL - user, pass string - base, tag string -} - -func NewReference(rawref string) (*Reference, error) { - ref := &Reference{} - if !strings.Contains(rawref, "://") { - rawref = "https://" + rawref - } - urlobj, err := url.Parse(rawref) - if err != nil { - return ref, err - } - if urlobj.User != nil { - ref.user = urlobj.User.Username() - ref.pass, _ = urlobj.User.Password() - urlobj.User = nil - } - ref.urlobj = urlobj - - repotag := strings.SplitN(ref.urlobj.Path, ":", 2) - if len(repotag) != 2 { - err = errors.New("Incorrect reference format") - return ref, err - } - ref.base = repotag[0] - ref.tag = repotag[1] - - ref.urlobj.Path = "/" - ref.urlobj = urlobj - - return ref, err -} - -func (ref *Reference) String() string { - return path.Join(ref.urlobj.Host, ref.base+":"+ref.tag) -} - -func (ref *Reference) Repo() string { - return path.Join(ref.urlobj.Host, ref.base) -} - -func (ref *Reference) Tag() string { - return ref.tag -} diff --git a/ociclient/repo.go b/ociclient/repo.go deleted file mode 100644 index 17d4cfa..0000000 --- a/ociclient/repo.go +++ /dev/null @@ -1,100 +0,0 @@ -package repocli - -import ( - "net/url" - "strings" -) - -type Repository struct { - urlobj *url.URL - user, pass string - base string -} - -func NewRepository(rawrepo string) (*Repository, error) { - repo := &Repository{} - if !strings.Contains(rawrepo, "://") { - rawrepo = "https://" + rawrepo - } - urlobj, err := url.Parse(rawrepo) - if err != nil { - return repo, err - } - if urlobj.User != nil { - repo.user = urlobj.User.Username() - repo.pass, _ = urlobj.User.Password() - urlobj.User = nil - } - repo.urlobj = urlobj - repo.base = repo.urlobj.Path - repo.urlobj.Path = "/" - repo.urlobj = urlobj - - return repo, err -} - -func (repo *Repository) String() string { - curl := repo.urlobj.JoinPath(repo.base) - return curl.String() -} - -func (repo *Repository) Manifest(tag string) string { - curl := repo.urlobj.JoinPath("/v2", repo.base, "/manifests", tag) - return curl.String() -} - -func (repo *Repository) Blob(digest string) string { - curl := repo.urlobj.JoinPath("/v2", repo.base, "/blobs", digest) - return curl.String() -} - -func (repo *Repository) Upload() string { - curl := repo.urlobj.JoinPath("/v2", repo.base, "/blobs/uploads/") - return curl.String() -} - -func (repo *Repository) Patch(loc string) (string, error) { - var curl *url.URL - var out string - var err error - if isUUID(loc) { - curl = repo.urlobj.JoinPath("/v2/", repo.base, "/blobs/uploads/", loc) - return curl.String(), nil - } - if strings.Contains(loc, "://") { - curl, err = url.Parse(loc) - if err != nil { - return out, err - } - } else { - curl = repo.urlobj.JoinPath(loc) - } - out = curl.String() - return out, err -} - -func (repo *Repository) Put(loc, digest string) (string, error) { - var curl *url.URL - var out string - var err error - - if isUUID(loc) { - curl = repo.urlobj.JoinPath("/v2/", repo.base, "/blobs/uploads/", loc) - } else if strings.Contains(loc, "://") { - curl, err = url.Parse(loc) - if err != nil { - return out, err - } - } else { - curl = repo.urlobj.JoinPath(loc) - } - query := curl.Query() - query.Set("digest", digest) - curl.RawQuery = query.Encode() - out = curl.String() - return out, err -} - -func (repo *Repository) Userinfo() (string, string) { - return repo.user, repo.pass -} diff --git a/ociclient/repo_test.go b/ociclient/repo_test.go deleted file mode 100644 index 9d930a3..0000000 --- a/ociclient/repo_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package repocli - -import ( - "github.com/stretchr/testify/require" - - "fmt" - "testing" -) - -func xxxTestResrerer(t *testing.T) { - ref, err := NewRepository("registry.example.com/lib/alpine") - require.NoError(t, err) - - fmt.Printf("Manifest:\t%s\n", ref.Manifest("3.30.0")) - - digest := SHA256Digest([]byte("qwerty")) - fmt.Printf("Blob:\t\t%s\n", ref.Blob(digest)) - fmt.Printf("POST:\t\t%s\n", ref.Upload()) - uuid := "8be4df61-93ca-11d2-aa0d-00e098032b8c" - rawurl, err := ref.Patch(uuid) - require.NoError(t, err) - fmt.Printf("PATH:\t\t%s\n", rawurl) - rawurl, err = ref.Put(uuid, digest) - fmt.Printf("PUT:\t\t%s\n", rawurl) -} diff --git a/ociclient/uuid.go b/ociclient/uuid.go deleted file mode 100644 index d79621f..0000000 --- a/ociclient/uuid.go +++ /dev/null @@ -1,12 +0,0 @@ -package repocli - -import ( - "regexp" -) - -const uuidRegex = `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$` - -func isUUID(src string) bool { - re := regexp.MustCompile(uuidRegex) - return re.MatchString(src) -}