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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +459 -0
- data/VERSION +1 -1
- data/lib/aws-defaults/default_configuration.rb +4 -4
- data/lib/aws-sdk-core/arn.rb +13 -0
- data/lib/aws-sdk-core/binary/encode_handler.rb +12 -1
- data/lib/aws-sdk-core/credential_provider.rb +3 -0
- data/lib/aws-sdk-core/credential_provider_chain.rb +8 -5
- data/lib/aws-sdk-core/ecs_credentials.rb +177 -53
- data/lib/aws-sdk-core/endpoints/condition.rb +41 -0
- data/lib/aws-sdk-core/endpoints/endpoint.rb +17 -0
- data/lib/aws-sdk-core/endpoints/endpoint_rule.rb +75 -0
- data/lib/aws-sdk-core/endpoints/error_rule.rb +42 -0
- data/lib/aws-sdk-core/endpoints/function.rb +80 -0
- data/lib/aws-sdk-core/endpoints/matchers.rb +131 -0
- data/lib/aws-sdk-core/endpoints/reference.rb +31 -0
- data/lib/aws-sdk-core/endpoints/rule.rb +25 -0
- data/lib/aws-sdk-core/endpoints/rule_set.rb +52 -0
- data/lib/aws-sdk-core/endpoints/rules_provider.rb +37 -0
- data/lib/aws-sdk-core/endpoints/templater.rb +58 -0
- data/lib/aws-sdk-core/endpoints/tree_rule.rb +45 -0
- data/lib/aws-sdk-core/endpoints/url.rb +60 -0
- data/lib/aws-sdk-core/endpoints.rb +78 -0
- data/lib/aws-sdk-core/errors.rb +14 -1
- data/lib/aws-sdk-core/ini_parser.rb +7 -0
- data/lib/aws-sdk-core/instance_profile_credentials.rb +52 -30
- data/lib/aws-sdk-core/json/error_handler.rb +20 -1
- data/lib/aws-sdk-core/json/handler.rb +8 -1
- data/lib/aws-sdk-core/json/parser.rb +27 -2
- data/lib/aws-sdk-core/log/formatter.rb +6 -0
- data/lib/aws-sdk-core/pageable_response.rb +10 -1
- data/lib/aws-sdk-core/param_validator.rb +2 -2
- data/lib/aws-sdk-core/plugins/bearer_authorization.rb +67 -0
- data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +1 -1
- data/lib/aws-sdk-core/plugins/credentials_configuration.rb +24 -0
- data/lib/aws-sdk-core/plugins/endpoint_discovery.rb +6 -2
- data/lib/aws-sdk-core/plugins/jsonvalue_converter.rb +34 -6
- data/lib/aws-sdk-core/plugins/recursion_detection.rb +14 -3
- data/lib/aws-sdk-core/plugins/regional_endpoint.rb +111 -30
- data/lib/aws-sdk-core/plugins/request_compression.rb +217 -0
- data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +2 -1
- data/lib/aws-sdk-core/plugins/sign.rb +201 -0
- data/lib/aws-sdk-core/plugins/signature_v2.rb +1 -0
- data/lib/aws-sdk-core/plugins/signature_v4.rb +13 -7
- data/lib/aws-sdk-core/plugins/user_agent.rb +117 -14
- data/lib/aws-sdk-core/refreshing_credentials.rb +0 -6
- data/lib/aws-sdk-core/refreshing_token.rb +71 -0
- data/lib/aws-sdk-core/rest/handler.rb +1 -1
- data/lib/aws-sdk-core/rest/request/headers.rb +2 -6
- data/lib/aws-sdk-core/rest/request/querystring_builder.rb +43 -29
- data/lib/aws-sdk-core/shared_config.rb +106 -6
- data/lib/aws-sdk-core/sso_credentials.rb +80 -45
- data/lib/aws-sdk-core/sso_token_provider.rb +135 -0
- data/lib/aws-sdk-core/static_token_provider.rb +14 -0
- data/lib/aws-sdk-core/structure.rb +6 -4
- data/lib/aws-sdk-core/stubbing/stub_data.rb +11 -0
- data/lib/aws-sdk-core/token.rb +31 -0
- data/lib/aws-sdk-core/token_provider.rb +15 -0
- data/lib/aws-sdk-core/token_provider_chain.rb +51 -0
- data/lib/aws-sdk-core/waiters/poller.rb +3 -1
- data/lib/aws-sdk-core/xml/error_handler.rb +7 -0
- data/lib/aws-sdk-core/xml/parser/engines/oga.rb +2 -0
- data/lib/aws-sdk-core.rb +14 -0
- data/lib/aws-sdk-sso/client.rb +71 -11
- data/lib/aws-sdk-sso/endpoint_parameters.rb +66 -0
- data/lib/aws-sdk-sso/endpoint_provider.rb +57 -0
- data/lib/aws-sdk-sso/endpoints.rb +72 -0
- data/lib/aws-sdk-sso/plugins/endpoints.rb +76 -0
- data/lib/aws-sdk-sso/types.rb +8 -43
- data/lib/aws-sdk-sso.rb +5 -1
- data/lib/aws-sdk-ssooidc/client.rb +935 -0
- data/lib/aws-sdk-ssooidc/client_api.rb +271 -0
- data/lib/aws-sdk-ssooidc/customizations.rb +1 -0
- data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +66 -0
- data/lib/aws-sdk-ssooidc/endpoint_provider.rb +57 -0
- data/lib/aws-sdk-ssooidc/endpoints.rb +72 -0
- data/lib/aws-sdk-ssooidc/errors.rb +321 -0
- data/lib/aws-sdk-ssooidc/plugins/endpoints.rb +76 -0
- data/lib/aws-sdk-ssooidc/resource.rb +26 -0
- data/lib/aws-sdk-ssooidc/types.rb +755 -0
- data/lib/aws-sdk-ssooidc.rb +59 -0
- data/lib/aws-sdk-sts/client.rb +298 -245
- data/lib/aws-sdk-sts/client_api.rb +12 -1
- data/lib/aws-sdk-sts/endpoint_parameters.rb +78 -0
- data/lib/aws-sdk-sts/endpoint_provider.rb +112 -0
- data/lib/aws-sdk-sts/endpoints.rb +136 -0
- data/lib/aws-sdk-sts/plugins/endpoints.rb +84 -0
- data/lib/aws-sdk-sts/presigner.rb +14 -16
- data/lib/aws-sdk-sts/types.rb +128 -197
- data/lib/aws-sdk-sts.rb +5 -1
- data/lib/seahorse/client/async_base.rb +0 -1
- data/lib/seahorse/client/configuration.rb +1 -5
- data/lib/seahorse/client/h2/connection.rb +12 -11
- data/lib/seahorse/client/net_http/patches.rb +1 -4
- data/lib/seahorse/client/plugins/h2.rb +3 -3
- data/lib/seahorse/client/plugins/request_callback.rb +40 -9
- data/lib/seahorse/client/response.rb +6 -0
- data/lib/seahorse/model/operation.rb +3 -0
- data/lib/seahorse/util.rb +4 -0
- 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  | 
| 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 | 
            -
                #  | 
| 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 | 
| 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  | 
| 84 | 
            -
                  else  | 
| 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 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 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 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 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(@ | 
| 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 | 
            -
                   | 
| 132 | 
            -
                   | 
| 133 | 
            -
             | 
| 134 | 
            -
                   | 
| 135 | 
            -
             | 
| 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 = {} | 
| 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  | 
| 145 | 
            -
                     | 
| 146 | 
            -
             | 
| 147 | 
            -
             | 
| 148 | 
            -
             | 
| 149 | 
            -
                     | 
| 150 | 
            -
             | 
| 151 | 
            -
                     | 
| 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
         |