From 82550622beba050152d71d5b4bfa8454c4995478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9E=D0=BB=D0=B5=D0=B3=20=D0=91=D0=BE=D1=80=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 6 Mar 2026 16:26:24 +0200 Subject: [PATCH] working commit --- ...dfcdfa2c458c5218371f418dc136f2d19ac1fbe8a5 | 1 + pkg/repocli/a/index.json | 1 + pkg/repocli/a/oci-layout | 1 + pkg/repocli/blobexist_test.go | 26 ++++++++ pkg/repocli/copywctx.go | 39 +++++++++++ pkg/repocli/copywctx_test.go | 28 ++++++++ pkg/repocli/getblob_test.go | 27 ++++++++ pkg/repocli/getman_test.go | 33 ++++++++++ pkg/repocli/gettoken.go | 61 +++++++++++++++++ pkg/repocli/gettoken_test.go | 34 ++++++++++ pkg/repocli/getupload_test.go | 65 +++++++++++++++++++ pkg/repocli/manexist_test.go | 31 +++++++++ 12 files changed, 347 insertions(+) create mode 100644 pkg/repocli/a/blobs/sha256/03675ac53ff9cd1535ccc7dfcdfa2c458c5218371f418dc136f2d19ac1fbe8a5 create mode 100644 pkg/repocli/a/index.json create mode 100644 pkg/repocli/a/oci-layout create mode 100644 pkg/repocli/blobexist_test.go create mode 100644 pkg/repocli/copywctx.go create mode 100644 pkg/repocli/copywctx_test.go create mode 100644 pkg/repocli/getblob_test.go create mode 100644 pkg/repocli/getman_test.go create mode 100644 pkg/repocli/gettoken.go create mode 100644 pkg/repocli/gettoken_test.go create mode 100644 pkg/repocli/getupload_test.go create mode 100644 pkg/repocli/manexist_test.go diff --git a/pkg/repocli/a/blobs/sha256/03675ac53ff9cd1535ccc7dfcdfa2c458c5218371f418dc136f2d19ac1fbe8a5 b/pkg/repocli/a/blobs/sha256/03675ac53ff9cd1535ccc7dfcdfa2c458c5218371f418dc136f2d19ac1fbe8a5 new file mode 100644 index 0000000..1856e9b --- /dev/null +++ b/pkg/repocli/a/blobs/sha256/03675ac53ff9cd1535ccc7dfcdfa2c458c5218371f418dc136f2d19ac1fbe8a5 @@ -0,0 +1 @@ +Hello, World \ No newline at end of file diff --git a/pkg/repocli/a/index.json b/pkg/repocli/a/index.json new file mode 100644 index 0000000..507bb98 --- /dev/null +++ b/pkg/repocli/a/index.json @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.index.v1+json","manifests":[]} \ No newline at end of file diff --git a/pkg/repocli/a/oci-layout b/pkg/repocli/a/oci-layout new file mode 100644 index 0000000..1343d37 --- /dev/null +++ b/pkg/repocli/a/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion":"1.0.0"} \ No newline at end of file diff --git a/pkg/repocli/blobexist_test.go b/pkg/repocli/blobexist_test.go new file mode 100644 index 0000000..64356c6 --- /dev/null +++ b/pkg/repocli/blobexist_test.go @@ -0,0 +1,26 @@ +package repocli + +import ( + "github.com/stretchr/testify/require" + + "context" + "fmt" + "testing" + "time" +) + +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) + digstr := "sha256:3b8747b05489980f63da1d2b8e5a444c55777f69540394397b0bc1c76c3e41f2" + exist, size, err := cli.BlobExists(ctx, rawrepo, digstr) + require.NoError(t, err) + require.True(t, exist) + + fmt.Printf("Size: %d\n", size) + } +} diff --git a/pkg/repocli/copywctx.go b/pkg/repocli/copywctx.go new file mode 100644 index 0000000..b9a8acf --- /dev/null +++ b/pkg/repocli/copywctx.go @@ -0,0 +1,39 @@ +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/pkg/repocli/copywctx_test.go b/pkg/repocli/copywctx_test.go new file mode 100644 index 0000000..b6c991e --- /dev/null +++ b/pkg/repocli/copywctx_test.go @@ -0,0 +1,28 @@ +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/pkg/repocli/getblob_test.go b/pkg/repocli/getblob_test.go new file mode 100644 index 0000000..9d37305 --- /dev/null +++ b/pkg/repocli/getblob_test.go @@ -0,0 +1,27 @@ +package repocli + +import ( + "github.com/stretchr/testify/require" + + "bytes" + "context" + "fmt" + "testing" + "time" +) + +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) + digstr := "sha256:3b8747b05489980f63da1d2b8e5a444c55777f69540394397b0bc1c76c3e41f2" + exist, err := cli.GetBlob(ctx, rawrepo, buffer, digstr) + require.NoError(t, err) + require.True(t, exist) + fmt.Printf("Size: %d\n", len(buffer.Bytes())) + } +} diff --git a/pkg/repocli/getman_test.go b/pkg/repocli/getman_test.go new file mode 100644 index 0000000..394adde --- /dev/null +++ b/pkg/repocli/getman_test.go @@ -0,0 +1,33 @@ +package repocli + +import ( + "github.com/stretchr/testify/require" + + "bytes" + "context" + "encoding/json" + "fmt" + "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()) + } +} diff --git a/pkg/repocli/gettoken.go b/pkg/repocli/gettoken.go new file mode 100644 index 0000000..a6987a6 --- /dev/null +++ b/pkg/repocli/gettoken.go @@ -0,0 +1,61 @@ +package repocli + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "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/pkg/repocli/gettoken_test.go b/pkg/repocli/gettoken_test.go new file mode 100644 index 0000000..88b8d23 --- /dev/null +++ b/pkg/repocli/gettoken_test.go @@ -0,0 +1,34 @@ +package repocli + +import ( + "github.com/stretchr/testify/require" + + "context" + "fmt" + "testing" + "time" +) + +func xxxxTestClientGetToken(t *testing.T) { + var token string + var err error + { + cli := NewClient() + cli.UseMiddleware(NewBasicAuthMiddleware("xxxxxxx", "xxxxxxxxxx")) + 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/pkg/repocli/getupload_test.go b/pkg/repocli/getupload_test.go new file mode 100644 index 0000000..4b7cbdc --- /dev/null +++ b/pkg/repocli/getupload_test.go @@ -0,0 +1,65 @@ +package repocli + +import ( + "github.com/stretchr/testify/require" + + "bytes" + "context" + "fmt" + "math/rand" + "testing" + "time" + + "mstore/pkg/digest" +) + +func xxxTestClientGetUpload(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) + + reader := bytes.NewReader(srcdata) + + digobj := digest.NewDigest(digest.SHA256, srcdata) + digstr := digobj.Encoded() + size := int64(len(srcdata)) + + ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) + bloc, err := cli.PutUpload(ctx, rawrepo, reader, loc, digstr, size) + require.NoError(t, err) + fmt.Printf("Put blob Location: %s\n", bloc) + } + + } +} diff --git a/pkg/repocli/manexist_test.go b/pkg/repocli/manexist_test.go new file mode 100644 index 0000000..0e3c3b2 --- /dev/null +++ b/pkg/repocli/manexist_test.go @@ -0,0 +1,31 @@ +package repocli + +import ( + "github.com/stretchr/testify/require" + + "context" + "fmt" + "testing" + "time" +) + +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)) + } +}