summaryrefslogtreecommitdiffstats
path: root/pkg/name/registry.go
blob: 2a26b66d046dedb5882e0b87bf848c2f8ebaf48b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright 2018 Google LLC All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package name

import (
	"net"
	"net/url"
	"regexp"
	"strings"
)

// Detect more complex forms of local references.
var reLocal = regexp.MustCompile(`.*\.local(?:host)?(?::\d{1,5})?$`)

// Detect the loopback IP (127.0.0.1)
var reLoopback = regexp.MustCompile(regexp.QuoteMeta("127.0.0.1"))

// Detect the loopback IPV6 (::1)
var reipv6Loopback = regexp.MustCompile(regexp.QuoteMeta("::1"))

// Registry stores a docker registry name in a structured form.
type Registry struct {
	insecure bool
	registry string
}

// RegistryStr returns the registry component of the Registry.
func (r Registry) RegistryStr() string {
	return r.registry
}

// Name returns the name from which the Registry was derived.
func (r Registry) Name() string {
	return r.RegistryStr()
}

func (r Registry) String() string {
	return r.Name()
}

// Scope returns the scope required to access the registry.
func (r Registry) Scope(string) string {
	// The only resource under 'registry' is 'catalog'. http://goo.gl/N9cN9Z
	return "registry:catalog:*"
}

func (r Registry) isRFC1918() bool {
	ipStr := strings.Split(r.Name(), ":")[0]
	ip := net.ParseIP(ipStr)
	if ip == nil {
		return false
	}
	for _, cidr := range []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"} {
		_, block, _ := net.ParseCIDR(cidr)
		if block.Contains(ip) {
			return true
		}
	}
	return false
}

// Scheme returns https scheme for all the endpoints except localhost or when explicitly defined.
func (r Registry) Scheme() string {
	if r.insecure {
		return "http"
	}
	if r.isRFC1918() {
		return "http"
	}
	if strings.HasPrefix(r.Name(), "localhost:") {
		return "http"
	}
	if reLocal.MatchString(r.Name()) {
		return "http"
	}
	if reLoopback.MatchString(r.Name()) {
		return "http"
	}
	if reipv6Loopback.MatchString(r.Name()) {
		return "http"
	}
	return "https"
}

func checkRegistry(name string) error {
	// Per RFC 3986, registries (authorities) are required to be prefixed with "//"
	// url.Host == hostname[:port] == authority
	if url, err := url.Parse("//" + name); err != nil || url.Host != name {
		return newErrBadName("registries must be valid RFC 3986 URI authorities: %s", name)
	}
	return nil
}

// NewRegistry returns a Registry based on the given name.
// Strict validation requires explicit, valid RFC 3986 URI authorities to be given.
func NewRegistry(name string, opts ...Option) (Registry, error) {
	opt := makeOptions(opts...)
	if opt.strict && len(name) == 0 {
		return Registry{}, newErrBadName("strict validation requires the registry to be explicitly defined")
	}

	if err := checkRegistry(name); err != nil {
		return Registry{}, err
	}

	if name == "" {
		name = opt.defaultRegistry
	}
	// Rewrite "docker.io" to "index.docker.io".
	// See: https://github.com/google/go-containerregistry/issues/68
	if name == defaultRegistryAlias {
		name = DefaultRegistry
	}

	return Registry{registry: name, insecure: opt.insecure}, nil
}

// NewInsecureRegistry returns an Insecure Registry based on the given name.
//
// Deprecated: Use the Insecure Option with NewRegistry instead.
func NewInsecureRegistry(name string, opts ...Option) (Registry, error) {
	opts = append(opts, Insecure)
	return NewRegistry(name, opts...)
}