diff --git a/docs/config.go b/docs/config.go index d2108894..95f73129 100644 --- a/docs/config.go +++ b/docs/config.go @@ -38,8 +38,8 @@ const ( IndexServer = DefaultV1Registry + "/v1/" // IndexName is the name of the index IndexName = "docker.io" - - // IndexServer = "https://registry-stage.hub.docker.com/v1/" + // NotaryServer is the endpoint serving the Notary trust server + NotaryServer = "https://notary.docker.io" ) var ( diff --git a/docs/reference.go b/docs/reference.go new file mode 100644 index 00000000..e15f83ee --- /dev/null +++ b/docs/reference.go @@ -0,0 +1,68 @@ +package registry + +import ( + "strings" + + "github.com/docker/distribution/digest" +) + +// Reference represents a tag or digest within a repository +type Reference interface { + // HasDigest returns whether the reference has a verifiable + // content addressable reference which may be considered secure. + HasDigest() bool + + // ImageName returns an image name for the given repository + ImageName(string) string + + // Returns a string representation of the reference + String() string +} + +type tagReference struct { + tag string +} + +func (tr tagReference) HasDigest() bool { + return false +} + +func (tr tagReference) ImageName(repo string) string { + return repo + ":" + tr.tag +} + +func (tr tagReference) String() string { + return tr.tag +} + +type digestReference struct { + digest digest.Digest +} + +func (dr digestReference) HasDigest() bool { + return true +} + +func (dr digestReference) ImageName(repo string) string { + return repo + "@" + dr.String() +} + +func (dr digestReference) String() string { + return dr.digest.String() +} + +// ParseReference parses a reference into either a digest or tag reference +func ParseReference(ref string) Reference { + if strings.Contains(ref, ":") { + dgst, err := digest.ParseDigest(ref) + if err == nil { + return digestReference{digest: dgst} + } + } + return tagReference{tag: ref} +} + +// DigestReference creates a digest reference using a digest +func DigestReference(dgst digest.Digest) Reference { + return digestReference{digest: dgst} +} diff --git a/docs/registry.go b/docs/registry.go index fd85c21c..09143ba8 100644 --- a/docs/registry.go +++ b/docs/registry.go @@ -2,10 +2,14 @@ package registry import ( "crypto/tls" + "crypto/x509" "errors" + "fmt" + "io/ioutil" "net" "net/http" "os" + "path/filepath" "runtime" "strings" "time" @@ -54,6 +58,54 @@ func hasFile(files []os.FileInfo, name string) bool { return false } +// ReadCertsDirectory reads the directory for TLS certificates +// including roots and certificate pairs and updates the +// provided TLS configuration. +func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error { + fs, err := ioutil.ReadDir(directory) + if err != nil && !os.IsNotExist(err) { + return err + } + + for _, f := range fs { + if strings.HasSuffix(f.Name(), ".crt") { + if tlsConfig.RootCAs == nil { + // TODO(dmcgowan): Copy system pool + tlsConfig.RootCAs = x509.NewCertPool() + } + logrus.Debugf("crt: %s", filepath.Join(directory, f.Name())) + data, err := ioutil.ReadFile(filepath.Join(directory, f.Name())) + if err != nil { + return err + } + tlsConfig.RootCAs.AppendCertsFromPEM(data) + } + if strings.HasSuffix(f.Name(), ".cert") { + certName := f.Name() + keyName := certName[:len(certName)-5] + ".key" + logrus.Debugf("cert: %s", filepath.Join(directory, f.Name())) + if !hasFile(fs, keyName) { + return fmt.Errorf("Missing key %s for certificate %s", keyName, certName) + } + cert, err := tls.LoadX509KeyPair(filepath.Join(directory, certName), filepath.Join(directory, keyName)) + if err != nil { + return err + } + tlsConfig.Certificates = append(tlsConfig.Certificates, cert) + } + if strings.HasSuffix(f.Name(), ".key") { + keyName := f.Name() + certName := keyName[:len(keyName)-4] + ".cert" + logrus.Debugf("key: %s", filepath.Join(directory, f.Name())) + if !hasFile(fs, certName) { + return fmt.Errorf("Missing certificate %s for key %s", certName, keyName) + } + } + } + + return nil +} + // DockerHeaders returns request modifiers that ensure requests have // the User-Agent header set to dockerUserAgent and that metaHeaders // are added. diff --git a/docs/service.go b/docs/service.go index 274dfeb2..fa35e313 100644 --- a/docs/service.go +++ b/docs/service.go @@ -2,12 +2,9 @@ package registry import ( "crypto/tls" - "crypto/x509" "fmt" - "io/ioutil" "net/http" "net/url" - "os" "path/filepath" "strings" @@ -110,57 +107,11 @@ func (s *Service) TLSConfig(hostname string) (*tls.Config, error) { tlsConfig.InsecureSkipVerify = !isSecure if isSecure { - hasFile := func(files []os.FileInfo, name string) bool { - for _, f := range files { - if f.Name() == name { - return true - } - } - return false - } - hostDir := filepath.Join(CertsDir, hostname) logrus.Debugf("hostDir: %s", hostDir) - fs, err := ioutil.ReadDir(hostDir) - if err != nil && !os.IsNotExist(err) { + if err := ReadCertsDirectory(&tlsConfig, hostDir); err != nil { return nil, err } - - for _, f := range fs { - if strings.HasSuffix(f.Name(), ".crt") { - if tlsConfig.RootCAs == nil { - // TODO(dmcgowan): Copy system pool - tlsConfig.RootCAs = x509.NewCertPool() - } - logrus.Debugf("crt: %s", filepath.Join(hostDir, f.Name())) - data, err := ioutil.ReadFile(filepath.Join(hostDir, f.Name())) - if err != nil { - return nil, err - } - tlsConfig.RootCAs.AppendCertsFromPEM(data) - } - if strings.HasSuffix(f.Name(), ".cert") { - certName := f.Name() - keyName := certName[:len(certName)-5] + ".key" - logrus.Debugf("cert: %s", filepath.Join(hostDir, f.Name())) - if !hasFile(fs, keyName) { - return nil, fmt.Errorf("Missing key %s for certificate %s", keyName, certName) - } - cert, err := tls.LoadX509KeyPair(filepath.Join(hostDir, certName), filepath.Join(hostDir, keyName)) - if err != nil { - return nil, err - } - tlsConfig.Certificates = append(tlsConfig.Certificates, cert) - } - if strings.HasSuffix(f.Name(), ".key") { - keyName := f.Name() - certName := keyName[:len(keyName)-4] + ".cert" - logrus.Debugf("key: %s", filepath.Join(hostDir, f.Name())) - if !hasFile(fs, certName) { - return nil, fmt.Errorf("Missing certificate %s for key %s", certName, keyName) - } - } - } } return &tlsConfig, nil