github.com/simonferquel/app@v0.6.1-0.20181012141724-68b7cccf26ac/pkg/resto/registry.go (about) 1 package resto 2 3 import ( 4 "context" 5 "crypto/tls" 6 "net" 7 "net/http" 8 "net/url" 9 "strings" 10 "time" 11 12 "github.com/docker/distribution" 13 "github.com/docker/distribution/registry/client/auth" 14 "github.com/docker/distribution/registry/client/transport" 15 "github.com/docker/docker/api/types" 16 dd "github.com/docker/docker/distribution" 17 "github.com/docker/docker/registry" 18 digest "github.com/opencontainers/go-digest" 19 ) 20 21 type myreference string 22 23 func (m myreference) String() string { 24 return string(m) 25 } 26 27 func (m myreference) Name() string { 28 return string(m) 29 } 30 31 // MediaTypeConfig is the media type used for configuration files. 32 const MediaTypeConfig = "application/vndr.docker.config" 33 34 // ConfigManifest is a Manifest type holding arbitrary data. 35 type ConfigManifest struct { 36 mediaType string 37 payload []byte 38 } 39 40 // References returns the objects this Manifest refers to. 41 func (c *ConfigManifest) References() []distribution.Descriptor { 42 return nil 43 } 44 45 // Payload returns the mediatype and payload of this manifest. 46 func (c *ConfigManifest) Payload() (string, []byte, error) { 47 return c.mediaType, c.payload, nil 48 } 49 50 // NewConfigManifest creates and returns an new ConfigManifest. 51 func NewConfigManifest(mediaType string, payload []byte) *ConfigManifest { 52 return &ConfigManifest{mediaType, payload} 53 } 54 55 func init() { 56 distribution.RegisterManifestSchema(MediaTypeConfig, func(b []byte) (distribution.Manifest, distribution.Descriptor, error) { 57 return &ConfigManifest{ 58 mediaType: MediaTypeConfig, 59 payload: b, 60 }, 61 distribution.Descriptor{ 62 MediaType: MediaTypeConfig, 63 Size: int64(len(b)), 64 Digest: digest.SHA256.FromBytes(b), 65 }, nil 66 }) 67 } 68 69 // NewRepository instantiates a distribution.Repository pointing to the given target, with credentials 70 func NewRepository(ctx context.Context, endpoint string, repository string, opts RegistryOptions) (distribution.Repository, error) { 71 named := myreference(repository) 72 authConfig := &types.AuthConfig{ 73 Username: opts.Username, 74 Password: opts.Password, 75 } 76 url, err := url.Parse(endpoint) 77 if err != nil { 78 return nil, err 79 } 80 apiendpoint := registry.APIEndpoint{ 81 Mirror: false, 82 URL: url, 83 Version: 2, 84 TLSConfig: &tls.Config{InsecureSkipVerify: opts.Insecure}, 85 } 86 repoInfo, err := registry.ParseRepositoryInfo(named) 87 if err != nil { 88 return nil, err 89 } 90 repo, _, err := dd.NewV2Repository(ctx, repoInfo, apiendpoint, nil, authConfig, "push", "pull") 91 if err == nil { 92 return repo, nil 93 } 94 if !strings.Contains(err.Error(), "HTTP response to HTTPS client") { 95 return nil, err 96 } 97 if !opts.CleartextCredentials { 98 // Don't use credentials over insecure connection unless instnucted to 99 authConfig.Username = "" 100 authConfig.Password = "" 101 } 102 endpointHTTP := strings.Replace(endpoint, "https://", "http://", 1) 103 urlHTTP, err := url.Parse(endpointHTTP) 104 if err != nil { 105 return nil, err 106 } 107 apiendpoint.URL = urlHTTP 108 repo, _, err = dd.NewV2Repository(ctx, repoInfo, apiendpoint, nil, authConfig, "push", "pull") 109 return repo, err 110 } 111 112 // NewTransportCatalog returns a transport suitable for a catalog operation 113 func NewTransportCatalog(endpoint string, opts RegistryOptions) (http.RoundTripper, error) { 114 // taken from docker/distribution/registry.go 115 direct := &net.Dialer{ 116 Timeout: 30 * time.Second, 117 KeepAlive: 30 * time.Second, 118 DualStack: true, 119 } 120 base := &http.Transport{ 121 Proxy: http.ProxyFromEnvironment, 122 Dial: direct.Dial, 123 TLSHandshakeTimeout: 10 * time.Second, 124 TLSClientConfig: &tls.Config{InsecureSkipVerify: opts.Insecure}, 125 DisableKeepAlives: true, 126 } 127 128 authTransport := transport.NewTransport(base) 129 endpointURL, err := url.Parse(endpoint) 130 if err != nil { 131 return nil, err 132 } 133 challengeManager, _, err := registry.PingV2Registry(endpointURL, authTransport) 134 if err != nil { 135 return nil, err 136 } 137 scope := auth.RegistryScope{ 138 Name: "catalog", 139 Actions: []string{"*"}, 140 } 141 authConfig := &types.AuthConfig{ 142 Username: opts.Username, 143 Password: opts.Password, 144 } 145 creds := registry.NewStaticCredentialStore(authConfig) 146 tokenHandlerOptions := auth.TokenHandlerOptions{ 147 Transport: authTransport, 148 Credentials: creds, 149 Scopes: []auth.Scope{scope}, 150 ClientID: registry.AuthClientID, 151 } 152 tokenHandler := auth.NewTokenHandlerWithOptions(tokenHandlerOptions) 153 basicHandler := auth.NewBasicHandler(creds) 154 tr := transport.NewTransport(base, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler)) 155 return tr, nil 156 }