github.com/docker/cnab-to-oci@v0.3.0-beta4/remotes/resolver.go (about) 1 package remotes 2 3 import ( 4 "context" 5 "crypto/tls" 6 "fmt" 7 "net/http" 8 9 "github.com/containerd/containerd/remotes" 10 "github.com/containerd/containerd/remotes/docker" 11 "github.com/docker/cli/cli/config/configfile" 12 "github.com/docker/distribution/reference" 13 "github.com/docker/docker/registry" 14 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 15 ) 16 17 type multiRegistryResolver struct { 18 plainHTTP remotes.Resolver 19 secure remotes.Resolver 20 skipTLS remotes.Resolver 21 plainHTTPRegistries map[string]struct{} 22 skipTLSRegistries map[string]struct{} 23 } 24 25 func (r *multiRegistryResolver) resolveImplementation(image string) (remotes.Resolver, error) { 26 ref, err := reference.ParseNormalizedNamed(image) 27 if err != nil { 28 return nil, err 29 } 30 repoInfo, err := registry.ParseRepositoryInfo(ref) 31 if err != nil { 32 return nil, err 33 } 34 if _, plainHTTP := r.plainHTTPRegistries[repoInfo.Index.Name]; plainHTTP { 35 return r.plainHTTP, nil 36 } 37 if _, skipTLS := r.skipTLSRegistries[repoInfo.Index.Name]; skipTLS { 38 return r.skipTLS, nil 39 } 40 return r.secure, nil 41 } 42 43 func (r *multiRegistryResolver) Resolve(ctx context.Context, ref string) (name string, desc ocispec.Descriptor, err error) { 44 impl, err := r.resolveImplementation(ref) 45 if err != nil { 46 return "", ocispec.Descriptor{}, err 47 } 48 return impl.Resolve(ctx, ref) 49 } 50 51 func (r *multiRegistryResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) { 52 impl, err := r.resolveImplementation(ref) 53 if err != nil { 54 return nil, err 55 } 56 return impl.Fetcher(ctx, ref) 57 } 58 59 func (r *multiRegistryResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher, error) { 60 impl, err := r.resolveImplementation(ref) 61 if err != nil { 62 return nil, err 63 } 64 return impl.Pusher(ctx, ref) 65 } 66 67 // CreateResolver creates a docker registry resolver, using the local docker CLI credentials 68 func CreateResolver(cfg *configfile.ConfigFile, plainHTTPRegistries ...string) remotes.Resolver { 69 authorizer := docker.NewAuthorizer(nil, func(hostName string) (string, string, error) { 70 if hostName == registry.DefaultV2Registry.Host { 71 hostName = registry.IndexServer 72 } 73 a, err := cfg.GetAuthConfig(hostName) 74 if err != nil { 75 return "", "", err 76 } 77 if a.IdentityToken != "" { 78 return "", a.IdentityToken, nil 79 } 80 return a.Username, a.Password, nil 81 }) 82 83 clientSkipTLS := &http.Client{ 84 Transport: &http.Transport{ 85 TLSClientConfig: &tls.Config{ 86 InsecureSkipVerify: true, 87 }, 88 }, 89 } 90 91 skipTLSAuthorizer := docker.NewAuthorizer(clientSkipTLS, func(hostName string) (string, string, error) { 92 if hostName == registry.DefaultV2Registry.Host { 93 hostName = registry.IndexServer 94 } 95 a, err := cfg.GetAuthConfig(hostName) 96 if err != nil { 97 return "", "", err 98 } 99 if a.IdentityToken != "" { 100 return "", a.IdentityToken, nil 101 } 102 return a.Username, a.Password, nil 103 }) 104 105 result := &multiRegistryResolver{ 106 plainHTTP: docker.NewResolver(docker.ResolverOptions{ 107 Authorizer: authorizer, 108 PlainHTTP: true, 109 }), 110 secure: docker.NewResolver(docker.ResolverOptions{ 111 Authorizer: authorizer, 112 PlainHTTP: false, 113 }), 114 skipTLS: docker.NewResolver(docker.ResolverOptions{ 115 Authorizer: skipTLSAuthorizer, 116 PlainHTTP: false, 117 Client: clientSkipTLS, 118 }), 119 plainHTTPRegistries: make(map[string]struct{}), 120 skipTLSRegistries: make(map[string]struct{}), 121 } 122 123 for _, r := range plainHTTPRegistries { 124 pingURL := fmt.Sprintf("https://%s/v2/", r) 125 resp, err := clientSkipTLS.Get(pingURL) 126 if err == nil { 127 resp.Body.Close() 128 result.skipTLSRegistries[r] = struct{}{} 129 } else { 130 result.plainHTTPRegistries[r] = struct{}{} 131 } 132 } 133 134 return result 135 }