aws-sdk-core 3.131.1 → 3.188.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +459 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-defaults/default_configuration.rb +4 -4
  5. data/lib/aws-sdk-core/arn.rb +13 -0
  6. data/lib/aws-sdk-core/binary/encode_handler.rb +12 -1
  7. data/lib/aws-sdk-core/credential_provider.rb +3 -0
  8. data/lib/aws-sdk-core/credential_provider_chain.rb +8 -5
  9. data/lib/aws-sdk-core/ecs_credentials.rb +177 -53
  10. data/lib/aws-sdk-core/endpoints/condition.rb +41 -0
  11. data/lib/aws-sdk-core/endpoints/endpoint.rb +17 -0
  12. data/lib/aws-sdk-core/endpoints/endpoint_rule.rb +75 -0
  13. data/lib/aws-sdk-core/endpoints/error_rule.rb +42 -0
  14. data/lib/aws-sdk-core/endpoints/function.rb +80 -0
  15. data/lib/aws-sdk-core/endpoints/matchers.rb +131 -0
  16. data/lib/aws-sdk-core/endpoints/reference.rb +31 -0
  17. data/lib/aws-sdk-core/endpoints/rule.rb +25 -0
  18. data/lib/aws-sdk-core/endpoints/rule_set.rb +52 -0
  19. data/lib/aws-sdk-core/endpoints/rules_provider.rb +37 -0
  20. data/lib/aws-sdk-core/endpoints/templater.rb +58 -0
  21. data/lib/aws-sdk-core/endpoints/tree_rule.rb +45 -0
  22. data/lib/aws-sdk-core/endpoints/url.rb +60 -0
  23. data/lib/aws-sdk-core/endpoints.rb +78 -0
  24. data/lib/aws-sdk-core/errors.rb +14 -1
  25. data/lib/aws-sdk-core/ini_parser.rb +7 -0
  26. data/lib/aws-sdk-core/instance_profile_credentials.rb +52 -30
  27. data/lib/aws-sdk-core/json/error_handler.rb +20 -1
  28. data/lib/aws-sdk-core/json/handler.rb +8 -1
  29. data/lib/aws-sdk-core/json/parser.rb +27 -2
  30. data/lib/aws-sdk-core/log/formatter.rb +6 -0
  31. data/lib/aws-sdk-core/pageable_response.rb +10 -1
  32. data/lib/aws-sdk-core/param_validator.rb +2 -2
  33. data/lib/aws-sdk-core/plugins/bearer_authorization.rb +67 -0
  34. data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +1 -1
  35. data/lib/aws-sdk-core/plugins/credentials_configuration.rb +24 -0
  36. data/lib/aws-sdk-core/plugins/endpoint_discovery.rb +6 -2
  37. data/lib/aws-sdk-core/plugins/jsonvalue_converter.rb +34 -6
  38. data/lib/aws-sdk-core/plugins/recursion_detection.rb +14 -3
  39. data/lib/aws-sdk-core/plugins/regional_endpoint.rb +111 -30
  40. data/lib/aws-sdk-core/plugins/request_compression.rb +217 -0
  41. data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +2 -1
  42. data/lib/aws-sdk-core/plugins/sign.rb +201 -0
  43. data/lib/aws-sdk-core/plugins/signature_v2.rb +1 -0
  44. data/lib/aws-sdk-core/plugins/signature_v4.rb +13 -7
  45. data/lib/aws-sdk-core/plugins/user_agent.rb +117 -14
  46. data/lib/aws-sdk-core/refreshing_credentials.rb +0 -6
  47. data/lib/aws-sdk-core/refreshing_token.rb +71 -0
  48. data/lib/aws-sdk-core/rest/handler.rb +1 -1
  49. data/lib/aws-sdk-core/rest/request/headers.rb +2 -6
  50. data/lib/aws-sdk-core/rest/request/querystring_builder.rb +43 -29
  51. data/lib/aws-sdk-core/shared_config.rb +106 -6
  52. data/lib/aws-sdk-core/sso_credentials.rb +80 -45
  53. data/lib/aws-sdk-core/sso_token_provider.rb +135 -0
  54. data/lib/aws-sdk-core/static_token_provider.rb +14 -0
  55. data/lib/aws-sdk-core/structure.rb +6 -4
  56. data/lib/aws-sdk-core/stubbing/stub_data.rb +11 -0
  57. data/lib/aws-sdk-core/token.rb +31 -0
  58. data/lib/aws-sdk-core/token_provider.rb +15 -0
  59. data/lib/aws-sdk-core/token_provider_chain.rb +51 -0
  60. data/lib/aws-sdk-core/waiters/poller.rb +3 -1
  61. data/lib/aws-sdk-core/xml/error_handler.rb +7 -0
  62. data/lib/aws-sdk-core/xml/parser/engines/oga.rb +2 -0
  63. data/lib/aws-sdk-core.rb +14 -0
  64. data/lib/aws-sdk-sso/client.rb +71 -11
  65. data/lib/aws-sdk-sso/endpoint_parameters.rb +66 -0
  66. data/lib/aws-sdk-sso/endpoint_provider.rb +57 -0
  67. data/lib/aws-sdk-sso/endpoints.rb +72 -0
  68. data/lib/aws-sdk-sso/plugins/endpoints.rb +76 -0
  69. data/lib/aws-sdk-sso/types.rb +8 -43
  70. data/lib/aws-sdk-sso.rb +5 -1
  71. data/lib/aws-sdk-ssooidc/client.rb +935 -0
  72. data/lib/aws-sdk-ssooidc/client_api.rb +271 -0
  73. data/lib/aws-sdk-ssooidc/customizations.rb +1 -0
  74. data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +66 -0
  75. data/lib/aws-sdk-ssooidc/endpoint_provider.rb +57 -0
  76. data/lib/aws-sdk-ssooidc/endpoints.rb +72 -0
  77. data/lib/aws-sdk-ssooidc/errors.rb +321 -0
  78. data/lib/aws-sdk-ssooidc/plugins/endpoints.rb +76 -0
  79. data/lib/aws-sdk-ssooidc/resource.rb +26 -0
  80. data/lib/aws-sdk-ssooidc/types.rb +755 -0
  81. data/lib/aws-sdk-ssooidc.rb +59 -0
  82. data/lib/aws-sdk-sts/client.rb +298 -245
  83. data/lib/aws-sdk-sts/client_api.rb +12 -1
  84. data/lib/aws-sdk-sts/endpoint_parameters.rb +78 -0
  85. data/lib/aws-sdk-sts/endpoint_provider.rb +112 -0
  86. data/lib/aws-sdk-sts/endpoints.rb +136 -0
  87. data/lib/aws-sdk-sts/plugins/endpoints.rb +84 -0
  88. data/lib/aws-sdk-sts/presigner.rb +14 -16
  89. data/lib/aws-sdk-sts/types.rb +128 -197
  90. data/lib/aws-sdk-sts.rb +5 -1
  91. data/lib/seahorse/client/async_base.rb +0 -1
  92. data/lib/seahorse/client/configuration.rb +1 -5
  93. data/lib/seahorse/client/h2/connection.rb +12 -11
  94. data/lib/seahorse/client/net_http/patches.rb +1 -4
  95. data/lib/seahorse/client/plugins/h2.rb +3 -3
  96. data/lib/seahorse/client/plugins/request_callback.rb +40 -9
  97. data/lib/seahorse/client/response.rb +6 -0
  98. data/lib/seahorse/model/operation.rb +3 -0
  99. data/lib/seahorse/util.rb +4 -0
  100. metadata +49 -7
@@ -2,21 +2,27 @@
2
2
 
3
3
  require 'time'
4
4
  require 'net/http'
5
+ require 'resolv'
5
6
 
6
7
  module Aws
7
8
  # An auto-refreshing credential provider that loads credentials from
8
- # instances running in ECS.
9
+ # instances running in containers.
9
10
  #
10
11
  # ecs_credentials = Aws::ECSCredentials.new(retries: 3)
11
12
  # ec2 = Aws::EC2::Client.new(credentials: ecs_credentials)
12
13
  class ECSCredentials
13
-
14
14
  include CredentialProvider
15
15
  include RefreshingCredentials
16
16
 
17
17
  # @api private
18
18
  class Non200Response < RuntimeError; end
19
19
 
20
+ # Raised when the token file cannot be read.
21
+ class TokenFileReadError < RuntimeError; end
22
+
23
+ # Raised when the token file is invalid.
24
+ class InvalidTokenError < RuntimeError; end
25
+
20
26
  # These are the errors we trap when attempting to talk to the
21
27
  # instance metadata service. Any of these imply the service
22
28
  # is not present, no responding or some other non-recoverable
@@ -29,16 +35,22 @@ module Aws
29
35
  Errno::ENETUNREACH,
30
36
  SocketError,
31
37
  Timeout::Error,
32
- Non200Response,
33
- ]
38
+ Non200Response
39
+ ].freeze
34
40
 
35
41
  # @param [Hash] options
36
42
  # @option options [Integer] :retries (5) Number of times to retry
37
43
  # when retrieving credentials.
38
- # @option options [String] :ip_address ('169.254.170.2')
39
- # @option options [Integer] :port (80)
44
+ # @option options [String] :ip_address ('169.254.170.2') This value is
45
+ # ignored if `endpoint` is set and `credential_path` is not set.
46
+ # @option options [Integer] :port (80) This value is ignored if `endpoint`
47
+ # is set and `credential_path` is not set.
40
48
  # @option options [String] :credential_path By default, the value of the
41
49
  # AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variable.
50
+ # @option options [String] :endpoint The container credential endpoint.
51
+ # By default, this is the value of the AWS_CONTAINER_CREDENTIALS_FULL_URI
52
+ # environment variable. This value is ignored if `credential_path` or
53
+ # ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'] is set.
42
54
  # @option options [Float] :http_open_timeout (5)
43
55
  # @option options [Float] :http_read_timeout (5)
44
56
  # @option options [Numeric, Proc] :delay By default, failures are retried
@@ -52,17 +64,14 @@ module Aws
52
64
  # credentials are refreshed. `before_refresh` is called
53
65
  # with an instance of this object when
54
66
  # AWS credentials are required and need to be refreshed.
55
- def initialize options = {}
67
+ def initialize(options = {})
68
+ credential_path = options[:credential_path] ||
69
+ ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI']
70
+ endpoint = options[:endpoint] ||
71
+ ENV['AWS_CONTAINER_CREDENTIALS_FULL_URI']
72
+ initialize_uri(options, credential_path, endpoint)
73
+
56
74
  @retries = options[:retries] || 5
57
- @ip_address = options[:ip_address] || '169.254.170.2'
58
- @port = options[:port] || 80
59
- @credential_path = options[:credential_path]
60
- @credential_path ||= ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI']
61
- unless @credential_path
62
- raise ArgumentError.new(
63
- "Cannot instantiate an ECS Credential Provider without a credential path."
64
- )
65
- end
66
75
  @http_open_timeout = options[:http_open_timeout] || 5
67
76
  @http_read_timeout = options[:http_read_timeout] || 5
68
77
  @http_debug_output = options[:http_debug_output]
@@ -77,11 +86,95 @@ module Aws
77
86
 
78
87
  private
79
88
 
89
+ def initialize_uri(options, credential_path, endpoint)
90
+ if credential_path
91
+ initialize_relative_uri(options, credential_path)
92
+ # Use FULL_URI/endpoint only if RELATIVE_URI/path is not set
93
+ elsif endpoint
94
+ initialize_full_uri(endpoint)
95
+ else
96
+ raise ArgumentError,
97
+ 'Cannot instantiate an ECS Credential Provider '\
98
+ 'without a credential path or endpoint.'
99
+ end
100
+ end
101
+
102
+ def initialize_relative_uri(options, path)
103
+ @host = options[:ip_address] || '169.254.170.2'
104
+ @port = options[:port] || 80
105
+ @scheme = 'http'
106
+ @credential_path = path
107
+ end
108
+
109
+ def initialize_full_uri(endpoint)
110
+ uri = URI.parse(endpoint)
111
+ validate_full_uri_scheme!(uri)
112
+ validate_full_uri!(uri)
113
+ @host = uri.hostname
114
+ @port = uri.port
115
+ @scheme = uri.scheme
116
+ @credential_path = uri.request_uri
117
+ end
118
+
119
+ def validate_full_uri_scheme!(full_uri)
120
+ return if full_uri.is_a?(URI::HTTP) || full_uri.is_a?(URI::HTTPS)
121
+
122
+ raise ArgumentError, "'#{full_uri}' must be a valid HTTP or HTTPS URI"
123
+ end
124
+
125
+ # Validate that the full URI is using a loopback address if scheme is http.
126
+ def validate_full_uri!(full_uri)
127
+ return unless full_uri.scheme == 'http'
128
+
129
+ begin
130
+ return if valid_ip_address?(IPAddr.new(full_uri.host))
131
+ rescue IPAddr::InvalidAddressError
132
+ addresses = Resolv.getaddresses(full_uri.host)
133
+ return if addresses.all? { |addr| valid_ip_address?(IPAddr.new(addr)) }
134
+ end
135
+
136
+ raise ArgumentError,
137
+ 'AWS_CONTAINER_CREDENTIALS_FULL_URI must use a local loopback '\
138
+ 'or an ECS or EKS link-local address when using the http scheme.'
139
+ end
140
+
141
+ def valid_ip_address?(ip_address)
142
+ ip_loopback?(ip_address) || ecs_or_eks_ip?(ip_address)
143
+ end
144
+
145
+ # loopback? method is available in Ruby 2.5+
146
+ # Replicate the logic here.
147
+ # loopback (IPv4 127.0.0.0/8, IPv6 ::1/128)
148
+ def ip_loopback?(ip_address)
149
+ case ip_address.family
150
+ when Socket::AF_INET
151
+ ip_address & 0xff000000 == 0x7f000000
152
+ when Socket::AF_INET6
153
+ ip_address == 1
154
+ else
155
+ false
156
+ end
157
+ end
158
+
159
+ # Verify that the IP address is a link-local address from ECS or EKS.
160
+ # ECS container host (IPv4 `169.254.170.2`)
161
+ # EKS container host (IPv4 `169.254.170.23`, IPv6 `fd00:ec2::23`)
162
+ def ecs_or_eks_ip?(ip_address)
163
+ case ip_address.family
164
+ when Socket::AF_INET
165
+ [0xa9feaa02, 0xa9feaa17].include?(ip_address)
166
+ when Socket::AF_INET6
167
+ ip_address == 0xfd00_0ec2_0000_0000_0000_0000_0000_0023
168
+ else
169
+ false
170
+ end
171
+ end
172
+
80
173
  def backoff(backoff)
81
174
  case backoff
82
175
  when Proc then backoff
83
- when Numeric then lambda { |_| sleep(backoff) }
84
- else lambda { |num_failures| Kernel.sleep(1.2 ** num_failures) }
176
+ when Numeric then ->(_) { sleep(backoff) }
177
+ else ->(num_failures) { Kernel.sleep(1.2**num_failures) }
85
178
  end
86
179
  end
87
180
 
@@ -89,68 +182,99 @@ module Aws
89
182
  # Retry loading credentials up to 3 times is the instance metadata
90
183
  # service is responding but is returning invalid JSON documents
91
184
  # in response to the GET profile credentials call.
92
- begin
93
- retry_errors([Aws::Json::ParseError, StandardError], max_retries: 3) do
94
- c = Aws::Json.load(get_credentials.to_s)
95
- @credentials = Credentials.new(
96
- c['AccessKeyId'],
97
- c['SecretAccessKey'],
98
- c['Token']
99
- )
100
- @expiration = c['Expiration'] ? Time.iso8601(c['Expiration']) : nil
101
- end
102
- rescue Aws::Json::ParseError
103
- raise Aws::Errors::MetadataParserError.new
185
+
186
+ retry_errors([Aws::Json::ParseError, StandardError], max_retries: 3) do
187
+ c = Aws::Json.load(get_credentials.to_s)
188
+ @credentials = Credentials.new(
189
+ c['AccessKeyId'],
190
+ c['SecretAccessKey'],
191
+ c['Token']
192
+ )
193
+ @expiration = c['Expiration'] ? Time.iso8601(c['Expiration']) : nil
104
194
  end
195
+ rescue Aws::Json::ParseError
196
+ raise Aws::Errors::MetadataParserError
105
197
  end
106
198
 
107
199
  def get_credentials
108
200
  # Retry loading credentials a configurable number of times if
109
201
  # the instance metadata service is not responding.
110
- begin
111
- retry_errors(NETWORK_ERRORS, max_retries: @retries) do
112
- open_connection do |conn|
113
- http_get(conn, @credential_path)
114
- end
202
+
203
+ retry_errors(NETWORK_ERRORS, max_retries: @retries) do
204
+ open_connection do |conn|
205
+ http_get(conn, @credential_path)
115
206
  end
116
- rescue
117
- '{}'
118
207
  end
208
+ rescue TokenFileReadError, InvalidTokenError
209
+ raise
210
+ rescue StandardError
211
+ '{}'
212
+ end
213
+
214
+ def fetch_authorization_token
215
+ if (path = ENV['AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE'])
216
+ fetch_authorization_token_file(path)
217
+ elsif (token = ENV['AWS_CONTAINER_AUTHORIZATION_TOKEN'])
218
+ token
219
+ end
220
+ end
221
+
222
+ def fetch_authorization_token_file(path)
223
+ File.read(path).strip
224
+ rescue Errno::ENOENT
225
+ raise TokenFileReadError,
226
+ 'AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE is set '\
227
+ "but the file doesn't exist: #{path}"
228
+ end
229
+
230
+ def validate_authorization_token!(token)
231
+ return unless token.include?("\r\n")
232
+
233
+ raise InvalidTokenError,
234
+ 'Invalid Authorization token: token contains '\
235
+ 'a newline and carriage return character.'
119
236
  end
120
237
 
121
238
  def open_connection
122
- http = Net::HTTP.new(@ip_address, @port, nil)
239
+ http = Net::HTTP.new(@host, @port, nil)
123
240
  http.open_timeout = @http_open_timeout
124
241
  http.read_timeout = @http_read_timeout
125
242
  http.set_debug_output(@http_debug_output) if @http_debug_output
243
+ http.use_ssl = @scheme == 'https'
126
244
  http.start
127
245
  yield(http).tap { http.finish }
128
246
  end
129
247
 
130
248
  def http_get(connection, path)
131
- response = connection.request(Net::HTTP::Get.new(path))
132
- if response.code.to_i == 200
133
- response.body
134
- else
135
- raise Non200Response
249
+ request = Net::HTTP::Get.new(path)
250
+ set_authorization_token(request)
251
+ response = connection.request(request)
252
+ raise Non200Response unless response.code.to_i == 200
253
+
254
+ response.body
255
+ end
256
+
257
+ def set_authorization_token(request)
258
+ if (authorization_token = fetch_authorization_token)
259
+ validate_authorization_token!(authorization_token)
260
+ request['Authorization'] = authorization_token
136
261
  end
137
262
  end
138
263
 
139
- def retry_errors(error_classes, options = {}, &block)
264
+ def retry_errors(error_classes, options = {})
140
265
  max_retries = options[:max_retries]
141
266
  retries = 0
142
267
  begin
143
268
  yield
144
- rescue *error_classes => _error
145
- if retries < max_retries
146
- @backoff.call(retries)
147
- retries += 1
148
- retry
149
- else
150
- raise
151
- end
269
+ rescue TokenFileReadError, InvalidTokenError
270
+ raise
271
+ rescue *error_classes => _e
272
+ raise unless retries < max_retries
273
+
274
+ @backoff.call(retries)
275
+ retries += 1
276
+ retry
152
277
  end
153
278
  end
154
-
155
279
  end
156
280
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # This class is deprecated. It is used by the Runtime endpoint
6
+ # resolution approach. It has been replaced by a code generated
7
+ # approach in each service gem. It can be removed in a new
8
+ # major version. It has to exist because
9
+ # old service gems can use a new core version.
10
+ # @api private
11
+ class Condition
12
+ def initialize(fn:, argv:, assign: nil)
13
+ @fn = Function.new(fn: fn, argv: argv)
14
+ @assign = assign
15
+ @assigned = {}
16
+ end
17
+
18
+ attr_reader :fn
19
+ attr_reader :argv
20
+ attr_reader :assign
21
+
22
+ attr_reader :assigned
23
+
24
+ def match?(parameters, assigns)
25
+ output = @fn.call(parameters, assigns)
26
+ @assigned = @assigned.merge({ @assign => output }) if @assign
27
+ output
28
+ end
29
+
30
+ def self.from_json(conditions_json)
31
+ conditions_json.each.with_object([]) do |condition, conditions|
32
+ conditions << new(
33
+ fn: condition['fn'],
34
+ argv: condition['argv'],
35
+ assign: condition['assign']
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ class Endpoint
6
+ def initialize(url:, properties: {}, headers: {})
7
+ @url = url
8
+ @properties = properties
9
+ @headers = headers
10
+ end
11
+
12
+ attr_reader :url
13
+ attr_reader :properties
14
+ attr_reader :headers
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # This class is deprecated. It is used by the Runtime endpoint
6
+ # resolution approach. It has been replaced by a code generated
7
+ # approach in each service gem. It can be removed in a new
8
+ # major version. It has to exist because
9
+ # old service gems can use a new core version. # @api private
10
+ class EndpointRule < Rule
11
+ def initialize(type: 'endpoint', conditions:, endpoint:,
12
+ documentation: nil)
13
+ @type = type
14
+ @conditions = Condition.from_json(conditions)
15
+ @endpoint = endpoint
16
+ @documentation = documentation
17
+ end
18
+
19
+ attr_reader :type
20
+ attr_reader :conditions
21
+ attr_reader :endpoint
22
+ attr_reader :documentation
23
+
24
+ def match(parameters, assigned = {})
25
+ assigns = assigned.dup
26
+ matched = conditions.all? do |condition|
27
+ output = condition.match?(parameters, assigns)
28
+ assigns = assigns.merge(condition.assigned) if condition.assign
29
+ output
30
+ end
31
+ resolved_endpoint(parameters, assigns) if matched
32
+ end
33
+
34
+ def resolved_endpoint(parameters, assigns)
35
+ Endpoint.new(
36
+ url: resolve_value(@endpoint['url'], parameters, assigns),
37
+ properties: resolve_properties(
38
+ @endpoint['properties'] || {},
39
+ parameters,
40
+ assigns
41
+ ),
42
+ headers: resolve_headers(parameters, assigns)
43
+ )
44
+ end
45
+
46
+ private
47
+
48
+ def resolve_headers(parameters, assigns)
49
+ (@endpoint['headers'] || {}).each.with_object({}) do |(key, arr), headers|
50
+ headers[key] = []
51
+ arr.each do |value|
52
+ headers[key] << resolve_value(value, parameters, assigns)
53
+ end
54
+ end
55
+ end
56
+
57
+ def resolve_properties(obj, parameters, assigns)
58
+ case obj
59
+ when Hash
60
+ obj.each.with_object({}) do |(key, value), hash|
61
+ hash[key] = resolve_properties(value, parameters, assigns)
62
+ end
63
+ when Array
64
+ obj.collect { |value| resolve_properties(value, parameters, assigns) }
65
+ else
66
+ if obj.is_a?(String)
67
+ Templater.resolve(obj, parameters, assigns)
68
+ else
69
+ obj
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # This class is deprecated. It is used by the Runtime endpoint
6
+ # resolution approach. It has been replaced by a code generated
7
+ # approach in each service gem. It can be removed in a new
8
+ # major version. It has to exist because
9
+ # old service gems can use a new core version.
10
+ # @api private
11
+ class ErrorRule < Rule
12
+ def initialize(type: 'error', conditions:, error: nil, documentation: nil)
13
+ @type = type
14
+ @conditions = Condition.from_json(conditions)
15
+ @error = error
16
+ @documentation = documentation
17
+ end
18
+
19
+ attr_reader :type
20
+ attr_reader :conditions
21
+ attr_reader :error
22
+ attr_reader :documentation
23
+
24
+ def match(parameters, assigned = {})
25
+ assigns = assigned.dup
26
+ matched = conditions.all? do |condition|
27
+ output = condition.match?(parameters, assigns)
28
+ assigns = assigns.merge(condition.assigned) if condition.assign
29
+ output
30
+ end
31
+ resolved_error(parameters, assigns) if matched
32
+ end
33
+
34
+ private
35
+
36
+ def resolved_error(parameters, assigns)
37
+ error = resolve_value(@error, parameters, assigns)
38
+ ArgumentError.new(error)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # This class is deprecated. It is used by the Runtime endpoint
6
+ # resolution approach. It has been replaced by a code generated
7
+ # approach in each service gem. It can be removed in a new
8
+ # major version. It has to exist because
9
+ # old service gems can use a new core version.
10
+ # @api private
11
+ class Function
12
+ def initialize(fn:, argv:)
13
+ @fn = fn
14
+ @argv = build_argv(argv)
15
+ end
16
+
17
+ attr_reader :fn
18
+ attr_reader :argv
19
+
20
+ def call(parameters, assigns)
21
+ args = []
22
+ @argv.each do |arg|
23
+ if arg.is_a?(Reference)
24
+ args << arg.resolve(parameters, assigns)
25
+ elsif arg.is_a?(Function)
26
+ args << arg.call(parameters, assigns)
27
+ else
28
+ if arg.is_a?(String)
29
+ arg = Templater.resolve(arg, parameters, assigns)
30
+ end
31
+ args << arg
32
+ end
33
+ end
34
+
35
+ case @fn
36
+ when 'isSet'
37
+ Matchers.set?(*args)
38
+ when 'not'
39
+ Matchers.not(*args)
40
+ when 'getAttr'
41
+ Matchers.attr(*args)
42
+ when 'substring'
43
+ Matchers.substring(*args)
44
+ when 'stringEquals'
45
+ Matchers.string_equals?(*args)
46
+ when 'booleanEquals'
47
+ Matchers.boolean_equals?(*args)
48
+ when 'uriEncode'
49
+ Matchers.uri_encode(*args)
50
+ when 'parseURL'
51
+ Matchers.parse_url(*args)
52
+ when 'isValidHostLabel'
53
+ Matchers.valid_host_label?(*args)
54
+ when 'aws.partition'
55
+ Matchers.aws_partition(*args)
56
+ when 'aws.parseArn'
57
+ Matchers.aws_parse_arn(*args)
58
+ when 'aws.isVirtualHostableS3Bucket'
59
+ Matchers.aws_virtual_hostable_s3_bucket?(*args)
60
+ else
61
+ raise "Function not found: #{@fn}"
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def build_argv(argv_json)
68
+ argv_json.each.with_object([]) do |arg, argv|
69
+ argv << if arg.is_a?(Hash) && arg['ref']
70
+ Reference.new(ref: arg['ref'])
71
+ elsif arg.is_a?(Hash) && arg['fn']
72
+ Function.new(fn: arg['fn'], argv: arg['argv'])
73
+ else
74
+ arg
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cgi'
4
+
5
+ module Aws
6
+ module Endpoints
7
+ # generic matcher functions for service endpoints
8
+ # @api private
9
+ module Matchers
10
+ # Regex that extracts anything in square brackets
11
+ BRACKET_REGEX = /\[(.*?)\]/.freeze
12
+
13
+ # CORE
14
+
15
+ # isSet(value: Option<T>) bool
16
+ def self.set?(value)
17
+ !value.nil?
18
+ end
19
+
20
+ # not(value: bool) bool
21
+ def self.not(bool)
22
+ !bool
23
+ end
24
+
25
+ # getAttr(value: Object | Array, path: string) Document
26
+ def self.attr(value, path)
27
+ parts = path.split('.')
28
+
29
+ val = if (index = parts.first[BRACKET_REGEX, 1])
30
+ # remove brackets and index from part before indexing
31
+ value[parts.first.gsub(BRACKET_REGEX, '')][index.to_i]
32
+ else
33
+ value[parts.first]
34
+ end
35
+
36
+ if parts.size == 1
37
+ val
38
+ else
39
+ attr(val, parts.slice(1..-1).join('.'))
40
+ end
41
+ end
42
+
43
+ def self.substring(input, start, stop, reverse)
44
+ return nil if start >= stop || input.size < stop
45
+
46
+ return nil if input.chars.any? { |c| c.ord > 127 }
47
+
48
+ return input[start...stop] unless reverse
49
+
50
+ r_start = input.size - stop
51
+ r_stop = input.size - start
52
+ input[r_start...r_stop]
53
+ end
54
+
55
+ # stringEquals(value1: string, value2: string) bool
56
+ def self.string_equals?(value1, value2)
57
+ value1 == value2
58
+ end
59
+
60
+ # booleanEquals(value1: bool, value2: bool) bool
61
+ def self.boolean_equals?(value1, value2)
62
+ value1 == value2
63
+ end
64
+
65
+ # uriEncode(value: string) string
66
+ def self.uri_encode(value)
67
+ CGI.escape(value.encode('UTF-8')).gsub('+', '%20').gsub('%7E', '~')
68
+ end
69
+
70
+ # parseUrl(value: string) Option<URL>
71
+ def self.parse_url(value)
72
+ URL.new(value).as_json
73
+ rescue ArgumentError, URI::InvalidURIError
74
+ nil
75
+ end
76
+
77
+ # isValidHostLabel(value: string, allowSubDomains: bool) bool
78
+ def self.valid_host_label?(value, allow_sub_domains = false)
79
+ return false if value.empty?
80
+
81
+ if allow_sub_domains
82
+ labels = value.split('.', -1)
83
+ return labels.all? { |l| valid_host_label?(l) }
84
+ end
85
+
86
+ !!(value =~ /\A(?!-)[a-zA-Z0-9-]{1,63}(?<!-)\z/)
87
+ end
88
+
89
+ # AWS
90
+
91
+ # aws.partition(value: string) Option<Partition>
92
+ def self.aws_partition(value)
93
+ partition =
94
+ Aws::Partitions.find { |p| p.region?(value) } ||
95
+ Aws::Partitions.find { |p| value.match(p.region_regex) } ||
96
+ Aws::Partitions.find { |p| p.name == 'aws' }
97
+
98
+ return nil unless partition
99
+
100
+ partition.metadata
101
+ end
102
+
103
+ # aws.parseArn(value: string) Option<ARN>
104
+ def self.aws_parse_arn(value)
105
+ arn = Aws::ARNParser.parse(value)
106
+ json = arn.as_json
107
+ # HACK: because of poor naming and also requirement of splitting
108
+ resource = json.delete('resource')
109
+ json['resourceId'] = resource.split(%r{[:\/]}, -1)
110
+ json
111
+ rescue Aws::Errors::InvalidARNError
112
+ nil
113
+ end
114
+
115
+ # aws.isVirtualHostableS3Bucket(value: string, allowSubDomains: bool) bool
116
+ def self.aws_virtual_hostable_s3_bucket?(value, allow_sub_domains = false)
117
+ return false if value.empty?
118
+
119
+ if allow_sub_domains
120
+ labels = value.split('.', -1)
121
+ return labels.all? { |l| aws_virtual_hostable_s3_bucket?(l) }
122
+ end
123
+
124
+ # must be between 3 and 63 characters long, no uppercase
125
+ value =~ /\A(?!-)[a-z0-9-]{3,63}(?<!-)\z/ &&
126
+ # not an IP address
127
+ value !~ /(\d+\.){3}\d+/
128
+ end
129
+ end
130
+ end
131
+ end