github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/distribution/registry.go (about)

     1  package distribution // import "github.com/Prakhar-Agarwal-byte/moby/distribution"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net"
     7  	"net/http"
     8  	"time"
     9  
    10  	"github.com/distribution/reference"
    11  	"github.com/docker/distribution"
    12  	"github.com/docker/distribution/manifest/schema2"
    13  	"github.com/docker/distribution/registry/client"
    14  	"github.com/docker/distribution/registry/client/auth"
    15  	"github.com/docker/distribution/registry/client/transport"
    16  	registrytypes "github.com/Prakhar-Agarwal-byte/moby/api/types/registry"
    17  	"github.com/Prakhar-Agarwal-byte/moby/dockerversion"
    18  	"github.com/Prakhar-Agarwal-byte/moby/registry"
    19  	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
    20  )
    21  
    22  var (
    23  	// supportedMediaTypes represents acceptable media-type(-prefixes)
    24  	// we use this list to prevent obscure errors when trying to pull
    25  	// OCI artifacts.
    26  	supportedMediaTypes = []string{
    27  		// valid prefixes
    28  		"application/vnd.oci.image",
    29  		"application/vnd.docker",
    30  
    31  		// these types may occur on old images, and are copied from
    32  		// defaultImageTypes below.
    33  		"application/octet-stream",
    34  		"application/json",
    35  		"text/html",
    36  		"",
    37  	}
    38  
    39  	// defaultImageTypes represents the schema2 config types for images
    40  	defaultImageTypes = []string{
    41  		schema2.MediaTypeImageConfig,
    42  		ocispec.MediaTypeImageConfig,
    43  		// Handle unexpected values from https://github.com/docker/distribution/issues/1621
    44  		// (see also https://github.com/Prakhar-Agarwal-byte/moby/issues/22378,
    45  		// https://github.com/Prakhar-Agarwal-byte/moby/issues/30083)
    46  		"application/octet-stream",
    47  		"application/json",
    48  		"text/html",
    49  		// Treat defaulted values as images, newer types cannot be implied
    50  		"",
    51  	}
    52  
    53  	// pluginTypes represents the schema2 config types for plugins
    54  	pluginTypes = []string{
    55  		schema2.MediaTypePluginConfig,
    56  	}
    57  
    58  	mediaTypeClasses map[string]string
    59  )
    60  
    61  func init() {
    62  	// initialize media type classes with all know types for images and plugins.
    63  	mediaTypeClasses = map[string]string{}
    64  	for _, t := range defaultImageTypes {
    65  		mediaTypeClasses[t] = "image"
    66  	}
    67  	for _, t := range pluginTypes {
    68  		mediaTypeClasses[t] = "plugin"
    69  	}
    70  }
    71  
    72  // newRepository returns a repository (v2 only). It creates an HTTP transport
    73  // providing timeout settings and authentication support, and also verifies the
    74  // remote API version.
    75  func newRepository(
    76  	ctx context.Context, repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint,
    77  	metaHeaders http.Header, authConfig *registrytypes.AuthConfig, actions ...string,
    78  ) (distribution.Repository, error) {
    79  	repoName := repoInfo.Name.Name()
    80  	// If endpoint does not support CanonicalName, use the RemoteName instead
    81  	if endpoint.TrimHostname {
    82  		repoName = reference.Path(repoInfo.Name)
    83  	}
    84  
    85  	direct := &net.Dialer{
    86  		Timeout:   30 * time.Second,
    87  		KeepAlive: 30 * time.Second,
    88  	}
    89  
    90  	// TODO(dmcgowan): Call close idle connections when complete, use keep alive
    91  	base := &http.Transport{
    92  		Proxy:               http.ProxyFromEnvironment,
    93  		DialContext:         direct.DialContext,
    94  		TLSHandshakeTimeout: 10 * time.Second,
    95  		TLSClientConfig:     endpoint.TLSConfig,
    96  		// TODO(dmcgowan): Call close idle connections when complete and use keep alive
    97  		DisableKeepAlives: true,
    98  	}
    99  
   100  	modifiers := registry.Headers(dockerversion.DockerUserAgent(ctx), metaHeaders)
   101  	authTransport := transport.NewTransport(base, modifiers...)
   102  
   103  	challengeManager, err := registry.PingV2Registry(endpoint.URL, authTransport)
   104  	if err != nil {
   105  		transportOK := false
   106  		if responseErr, ok := err.(registry.PingResponseError); ok {
   107  			transportOK = true
   108  			err = responseErr.Err
   109  		}
   110  		return nil, fallbackError{
   111  			err:         err,
   112  			transportOK: transportOK,
   113  		}
   114  	}
   115  
   116  	if authConfig.RegistryToken != "" {
   117  		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, &passThruTokenHandler{token: authConfig.RegistryToken}))
   118  	} else {
   119  		creds := registry.NewStaticCredentialStore(authConfig)
   120  		tokenHandler := auth.NewTokenHandlerWithOptions(auth.TokenHandlerOptions{
   121  			Transport:   authTransport,
   122  			Credentials: creds,
   123  			Scopes: []auth.Scope{auth.RepositoryScope{
   124  				Repository: repoName,
   125  				Actions:    actions,
   126  				Class:      repoInfo.Class,
   127  			}},
   128  			ClientID: registry.AuthClientID,
   129  		})
   130  		basicHandler := auth.NewBasicHandler(creds)
   131  		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
   132  	}
   133  	tr := transport.NewTransport(base, modifiers...)
   134  
   135  	repoNameRef, err := reference.WithName(repoName)
   136  	if err != nil {
   137  		return nil, fallbackError{
   138  			err:         err,
   139  			transportOK: true,
   140  		}
   141  	}
   142  
   143  	repo, err := client.NewRepository(repoNameRef, endpoint.URL.String(), tr)
   144  	if err != nil {
   145  		return nil, fallbackError{
   146  			err:         err,
   147  			transportOK: true,
   148  		}
   149  	}
   150  
   151  	return repo, nil
   152  }
   153  
   154  type passThruTokenHandler struct {
   155  	token string
   156  }
   157  
   158  func (th *passThruTokenHandler) Scheme() string {
   159  	return "bearer"
   160  }
   161  
   162  func (th *passThruTokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error {
   163  	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", th.token))
   164  	return nil
   165  }