...
1 package storage
2
3 import (
4 "context"
5 "fmt"
6 "net/url"
7
8 "github.com/docker/distribution"
9 dcontext "github.com/docker/distribution/context"
10 "github.com/docker/distribution/manifest/ocischema"
11 "github.com/opencontainers/go-digest"
12 v1 "github.com/opencontainers/image-spec/specs-go/v1"
13 )
14
15
16 type ocischemaManifestHandler struct {
17 repository distribution.Repository
18 blobStore distribution.BlobStore
19 ctx context.Context
20 manifestURLs manifestURLs
21 }
22
23 var _ ManifestHandler = &ocischemaManifestHandler{}
24
25 func (ms *ocischemaManifestHandler) Unmarshal(ctx context.Context, dgst digest.Digest, content []byte) (distribution.Manifest, error) {
26 dcontext.GetLogger(ms.ctx).Debug("(*ocischemaManifestHandler).Unmarshal")
27
28 m := &ocischema.DeserializedManifest{}
29 if err := m.UnmarshalJSON(content); err != nil {
30 return nil, err
31 }
32
33 return m, nil
34 }
35
36 func (ms *ocischemaManifestHandler) Put(ctx context.Context, manifest distribution.Manifest, skipDependencyVerification bool) (digest.Digest, error) {
37 dcontext.GetLogger(ms.ctx).Debug("(*ocischemaManifestHandler).Put")
38
39 m, ok := manifest.(*ocischema.DeserializedManifest)
40 if !ok {
41 return "", fmt.Errorf("non-ocischema manifest put to ocischemaManifestHandler: %T", manifest)
42 }
43
44 if err := ms.verifyManifest(ms.ctx, *m, skipDependencyVerification); err != nil {
45 return "", err
46 }
47
48 mt, payload, err := m.Payload()
49 if err != nil {
50 return "", err
51 }
52
53 revision, err := ms.blobStore.Put(ctx, mt, payload)
54 if err != nil {
55 dcontext.GetLogger(ctx).Errorf("error putting payload into blobstore: %v", err)
56 return "", err
57 }
58
59 return revision.Digest, nil
60 }
61
62
63
64
65 func (ms *ocischemaManifestHandler) verifyManifest(ctx context.Context, mnfst ocischema.DeserializedManifest, skipDependencyVerification bool) error {
66 var errs distribution.ErrManifestVerification
67
68 if mnfst.Manifest.SchemaVersion != 2 {
69 return fmt.Errorf("unrecognized manifest schema version %d", mnfst.Manifest.SchemaVersion)
70 }
71
72 if skipDependencyVerification {
73 return nil
74 }
75
76 manifestService, err := ms.repository.Manifests(ctx)
77 if err != nil {
78 return err
79 }
80
81 blobsService := ms.repository.Blobs(ctx)
82
83 for _, descriptor := range mnfst.References() {
84 var err error
85
86 switch descriptor.MediaType {
87 case v1.MediaTypeImageLayer, v1.MediaTypeImageLayerGzip, v1.MediaTypeImageLayerNonDistributable, v1.MediaTypeImageLayerNonDistributableGzip:
88 allow := ms.manifestURLs.allow
89 deny := ms.manifestURLs.deny
90 for _, u := range descriptor.URLs {
91 var pu *url.URL
92 pu, err = url.Parse(u)
93 if err != nil || (pu.Scheme != "http" && pu.Scheme != "https") || pu.Fragment != "" || (allow != nil && !allow.MatchString(u)) || (deny != nil && deny.MatchString(u)) {
94 err = errInvalidURL
95 break
96 }
97 }
98 if err == nil && len(descriptor.URLs) == 0 {
99
100 _, err = blobsService.Stat(ctx, descriptor.Digest)
101 }
102
103 case v1.MediaTypeImageManifest:
104 var exists bool
105 exists, err = manifestService.Exists(ctx, descriptor.Digest)
106 if err != nil || !exists {
107 err = distribution.ErrBlobUnknown
108 }
109
110 fallthrough
111 default:
112
113 if len(descriptor.URLs) == 0 {
114 _, err = blobsService.Stat(ctx, descriptor.Digest)
115 }
116 }
117
118 if err != nil {
119 if err != distribution.ErrBlobUnknown {
120 errs = append(errs, err)
121 }
122
123
124 errs = append(errs, distribution.ErrManifestBlobUnknown{Digest: descriptor.Digest})
125 }
126 }
127
128 if len(errs) != 0 {
129 return errs
130 }
131
132 return nil
133 }
134
View as plain text