1 package endpoints
2
3 import (
4 "fmt"
5 "regexp"
6 "strings"
7
8 "github.com/aws/aws-sdk-go-v2/aws"
9 )
10
11 const (
12 defaultProtocol = "https"
13 defaultSigner = "v4"
14 )
15
16 var (
17 protocolPriority = []string{"https", "http"}
18 signerPriority = []string{"v4"}
19 )
20
21
22 type Options struct {
23
24 DisableHTTPS bool
25 }
26
27
28 type Partitions []Partition
29
30
31 func (ps Partitions) ResolveEndpoint(region string, opts Options) (aws.Endpoint, error) {
32 if len(ps) == 0 {
33 return aws.Endpoint{}, fmt.Errorf("no partitions found")
34 }
35
36 for i := 0; i < len(ps); i++ {
37 if !ps[i].canResolveEndpoint(region) {
38 continue
39 }
40
41 return ps[i].ResolveEndpoint(region, opts)
42 }
43
44
45 return ps[0].ResolveEndpoint(region, opts)
46 }
47
48
49 type Partition struct {
50 ID string
51 RegionRegex *regexp.Regexp
52 PartitionEndpoint string
53 IsRegionalized bool
54 Defaults Endpoint
55 Endpoints Endpoints
56 }
57
58 func (p Partition) canResolveEndpoint(region string) bool {
59 _, ok := p.Endpoints[region]
60 return ok || p.RegionRegex.MatchString(region)
61 }
62
63
64 func (p Partition) ResolveEndpoint(region string, options Options) (resolved aws.Endpoint, err error) {
65 if len(region) == 0 && len(p.PartitionEndpoint) != 0 {
66 region = p.PartitionEndpoint
67 }
68
69 e, _ := p.endpointForRegion(region)
70
71 return e.resolve(p.ID, region, p.Defaults, options), nil
72 }
73
74 func (p Partition) endpointForRegion(region string) (Endpoint, bool) {
75 if e, ok := p.Endpoints[region]; ok {
76 return e, true
77 }
78
79 if !p.IsRegionalized {
80 return p.Endpoints[p.PartitionEndpoint], region == p.PartitionEndpoint
81 }
82
83
84
85 return Endpoint{}, false
86 }
87
88
89 type Endpoints map[string]Endpoint
90
91
92 type CredentialScope struct {
93 Region string
94 Service string
95 }
96
97
98 type Endpoint struct {
99
100 Unresolveable aws.Ternary
101
102 Hostname string
103 Protocols []string
104
105 CredentialScope CredentialScope
106
107 SignatureVersions []string `json:"signatureVersions"`
108 }
109
110 func (e Endpoint) resolve(partition, region string, def Endpoint, options Options) aws.Endpoint {
111 var merged Endpoint
112 merged.mergeIn(def)
113 merged.mergeIn(e)
114 e = merged
115
116 var u string
117 if e.Unresolveable != aws.TrueTernary {
118
119 hostname := strings.Replace(e.Hostname, "{region}", region, 1)
120
121 scheme := getEndpointScheme(e.Protocols, options.DisableHTTPS)
122 u = scheme + "://" + hostname
123 }
124
125 signingRegion := e.CredentialScope.Region
126 if len(signingRegion) == 0 {
127 signingRegion = region
128 }
129 signingName := e.CredentialScope.Service
130
131 return aws.Endpoint{
132 URL: u,
133 PartitionID: partition,
134 SigningRegion: signingRegion,
135 SigningName: signingName,
136 SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner),
137 }
138 }
139
140 func (e *Endpoint) mergeIn(other Endpoint) {
141 if other.Unresolveable != aws.UnknownTernary {
142 e.Unresolveable = other.Unresolveable
143 }
144 if len(other.Hostname) > 0 {
145 e.Hostname = other.Hostname
146 }
147 if len(other.Protocols) > 0 {
148 e.Protocols = other.Protocols
149 }
150 if len(other.CredentialScope.Region) > 0 {
151 e.CredentialScope.Region = other.CredentialScope.Region
152 }
153 if len(other.CredentialScope.Service) > 0 {
154 e.CredentialScope.Service = other.CredentialScope.Service
155 }
156 if len(other.SignatureVersions) > 0 {
157 e.SignatureVersions = other.SignatureVersions
158 }
159 }
160
161 func getEndpointScheme(protocols []string, disableHTTPS bool) string {
162 if disableHTTPS {
163 return "http"
164 }
165
166 return getByPriority(protocols, protocolPriority, defaultProtocol)
167 }
168
169 func getByPriority(s []string, p []string, def string) string {
170 if len(s) == 0 {
171 return def
172 }
173
174 for i := 0; i < len(p); i++ {
175 for j := 0; j < len(s); j++ {
176 if s[j] == p[i] {
177 return s[j]
178 }
179 }
180 }
181
182 return s[0]
183 }
184
185
186
187 func MapFIPSRegion(region string) string {
188 const fipsInfix = "-fips-"
189 const fipsPrefix = "fips-"
190 const fipsSuffix = "-fips"
191
192 if strings.Contains(region, fipsInfix) ||
193 strings.Contains(region, fipsPrefix) ||
194 strings.Contains(region, fipsSuffix) {
195 region = strings.ReplaceAll(region, fipsInfix, "-")
196 region = strings.ReplaceAll(region, fipsPrefix, "")
197 region = strings.ReplaceAll(region, fipsSuffix, "")
198 }
199
200 return region
201 }
202
View as plain text