aws-sdk-sns 1.0.0.rc1

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.
@@ -0,0 +1,2 @@
1
+ # utility classes
2
+ require 'aws-sdk-sns/message_verifier'
@@ -0,0 +1,23 @@
1
+ # WARNING ABOUT GENERATED CODE
2
+ #
3
+ # This file is generated. See the contributing for info on making contributions:
4
+ # https://github.com/aws/aws-sdk-ruby/blob/master/CONTRIBUTING.md
5
+ #
6
+ # WARNING ABOUT GENERATED CODE
7
+
8
+ module Aws
9
+ module SNS
10
+ module Errors
11
+
12
+ extend Aws::Errors::DynamicErrors
13
+
14
+ # Raised when calling #load or #data on a resource class that can not be
15
+ # loaded. This can happen when:
16
+ #
17
+ # * A resource class has identifiers, but no data attributes.
18
+ # * Resource data is only available when making an API call that
19
+ # enumerates all resources of that type.
20
+ class ResourceNotLoadable < RuntimeError; end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,157 @@
1
+ require 'net/http'
2
+ require 'openssl'
3
+ require 'base64'
4
+
5
+ module Aws
6
+ module SNS
7
+
8
+ # A utility class that can be used to verify the authenticity of messages
9
+ # sent by Amazon SNS.
10
+ #
11
+ # verifier = Aws::SNS::MessageVerifier.new
12
+ #
13
+ # # returns true/false
14
+ # verifier.authentic?(message_body)
15
+ #
16
+ # # raises a Aws::SNS::MessageVerifier::VerificationError on failure
17
+ # verifier.authenticate!(message_body)
18
+ #
19
+ # You can re-use a single {MessageVerifier} instance to authenticate
20
+ # multiple SNS messages.
21
+ class MessageVerifier
22
+
23
+ class VerificationError < StandardError; end
24
+
25
+ # @api private
26
+ SIGNABLE_KEYS = [
27
+ 'Message',
28
+ 'MessageId',
29
+ 'Subject',
30
+ 'SubscribeURL',
31
+ 'Timestamp',
32
+ 'Token',
33
+ 'TopicArn',
34
+ 'Type',
35
+ ].freeze
36
+
37
+ # @api private
38
+ AWS_HOSTNAMES = [
39
+ /^sns\.[a-zA-Z0-9\-]{3,}\.amazonaws\.com(\.cn)?$/
40
+ ]
41
+
42
+ def initialize
43
+ @cached_pems = {}
44
+ end
45
+
46
+ # @param [String<JSON>] message_body
47
+ # @return [Boolean] Returns `true` if the given message has been
48
+ # successfully verified. Returns `false` otherwise.
49
+ def authentic?(message_body)
50
+ authenticate!(message_body)
51
+ rescue VerificationError
52
+ false
53
+ end
54
+
55
+ # @param [String<JSON>] message_body
56
+ # @return [Boolean] Returns `true` when the given message has been
57
+ # successfully verified.
58
+ # @raise [VerificationError] Raised when the given message has failed
59
+ # verification.
60
+ def authenticate!(message_body)
61
+ msg = Json.load(message_body)
62
+ if public_key(msg).verify(sha1, signature(msg), canonical_string(msg))
63
+ true
64
+ else
65
+ msg = 'the authenticity of the message cannot be verified'
66
+ raise VerificationError, msg
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def sha1
73
+ OpenSSL::Digest::SHA1.new
74
+ end
75
+
76
+ def signature(message)
77
+ Base64.decode64(message['Signature'])
78
+ end
79
+
80
+ def canonical_string(message)
81
+ parts = []
82
+ SIGNABLE_KEYS.each do |key|
83
+ value = message[key]
84
+ unless value.nil? or value.empty?
85
+ parts << "#{key}\n#{value}\n"
86
+ end
87
+ end
88
+ parts.join
89
+ end
90
+
91
+ def public_key(message)
92
+ x509_url = URI.parse(message['SigningCertURL'])
93
+ x509 = OpenSSL::X509::Certificate.new(pem(x509_url))
94
+ OpenSSL::PKey::RSA.new(x509.public_key)
95
+ end
96
+
97
+ def pem(uri)
98
+ if @cached_pems[uri.to_s]
99
+ @cached_pems[uri.to_s]
100
+ else
101
+ @cached_pems[uri.to_s] = download_pem(uri)
102
+ end
103
+ end
104
+
105
+ def download_pem(uri)
106
+ verify_uri!(uri)
107
+ https_get(uri)
108
+ end
109
+
110
+ def verify_uri!(uri)
111
+ verify_https!(uri)
112
+ verify_hosted_by_aws!(uri)
113
+ verify_pem!(uri)
114
+ end
115
+
116
+ def verify_https!(uri)
117
+ unless uri.scheme == 'https'
118
+ msg = "the SigningCertURL must be https, got: #{uri}"
119
+ raise VerificationError, msg
120
+ end
121
+ end
122
+
123
+ def verify_hosted_by_aws!(uri)
124
+ unless AWS_HOSTNAMES.any? { |pattern| pattern.match(uri.host) }
125
+ msg = "signing cert is not hosted by AWS: #{uri}"
126
+ raise VerificationError, msg
127
+ end
128
+ end
129
+
130
+ def verify_pem!(uri)
131
+ unless File.extname(uri.path) == '.pem'
132
+ msg = "the SigningCertURL must link to a .pem file"
133
+ raise VerificationError, msg
134
+ end
135
+ end
136
+
137
+ def https_get(uri, failed_attempts = 0)
138
+ http = Net::HTTP.new(uri.host, uri.port)
139
+ http.use_ssl = true
140
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
141
+ http.start
142
+ resp = http.request(Net::HTTP::Get.new(uri.request_uri))
143
+ http.finish
144
+ if resp.code == '200'
145
+ resp.body
146
+ else
147
+ raise VerificationError, resp.body
148
+ end
149
+ rescue => error
150
+ failed_attempts += 1
151
+ retry if failed_attempts < 3
152
+ raise VerificationError, error.message
153
+ end
154
+
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,235 @@
1
+ # WARNING ABOUT GENERATED CODE
2
+ #
3
+ # This file is generated. See the contributing for info on making contributions:
4
+ # https://github.com/aws/aws-sdk-ruby/blob/master/CONTRIBUTING.md
5
+ #
6
+ # WARNING ABOUT GENERATED CODE
7
+
8
+ module Aws
9
+ module SNS
10
+ class PlatformApplication
11
+
12
+ extend Aws::Deprecations
13
+
14
+ # @overload def initialize(arn, options = {})
15
+ # @param [String] arn
16
+ # @option options [Client] :client
17
+ # @overload def initialize(options = {})
18
+ # @option options [required, String] :arn
19
+ # @option options [Client] :client
20
+ def initialize(*args)
21
+ options = Hash === args.last ? args.pop.dup : {}
22
+ @arn = extract_arn(args, options)
23
+ @data = options.delete(:data)
24
+ @client = options.delete(:client) || Client.new(options)
25
+ end
26
+
27
+ # @!group Read-Only Attributes
28
+
29
+ # @return [String]
30
+ def arn
31
+ @arn
32
+ end
33
+
34
+ # Attributes include the following:
35
+ #
36
+ # * `EventEndpointCreated` -- Topic ARN to which EndpointCreated event
37
+ # notifications should be sent.
38
+ #
39
+ # * `EventEndpointDeleted` -- Topic ARN to which EndpointDeleted event
40
+ # notifications should be sent.
41
+ #
42
+ # * `EventEndpointUpdated` -- Topic ARN to which EndpointUpdate event
43
+ # notifications should be sent.
44
+ #
45
+ # * `EventDeliveryFailure` -- Topic ARN to which DeliveryFailure event
46
+ # notifications should be sent upon Direct Publish delivery failure
47
+ # (permanent) to one of the application's endpoints.
48
+ # @return [Hash<String,String>]
49
+ def attributes
50
+ data.attributes
51
+ end
52
+
53
+ # @!endgroup
54
+
55
+ # @return [Client]
56
+ def client
57
+ @client
58
+ end
59
+
60
+ # Loads, or reloads {#data} for the current {PlatformApplication}.
61
+ # Returns `self` making it possible to chain methods.
62
+ #
63
+ # platform_application.reload.data
64
+ #
65
+ # @return [self]
66
+ def load
67
+ resp = @client.get_platform_application_attributes(platform_application_arn: @arn)
68
+ @data = resp.data
69
+ self
70
+ end
71
+ alias :reload :load
72
+
73
+ # @return [Types::GetPlatformApplicationAttributesResponse]
74
+ # Returns the data for this {PlatformApplication}. Calls
75
+ # {Client#get_platform_application_attributes} if {#data_loaded?} is `false`.
76
+ def data
77
+ load unless @data
78
+ @data
79
+ end
80
+
81
+ # @return [Boolean]
82
+ # Returns `true` if this resource is loaded. Accessing attributes or
83
+ # {#data} on an unloaded resource will trigger a call to {#load}.
84
+ def data_loaded?
85
+ !!@data
86
+ end
87
+
88
+ # @!group Actions
89
+
90
+ # @example Request syntax with placeholder values
91
+ #
92
+ # platformendpoint = platform_application.create_platform_endpoint({
93
+ # token: "String", # required
94
+ # custom_user_data: "String",
95
+ # attributes: {
96
+ # "String" => "String",
97
+ # },
98
+ # })
99
+ # @param [Hash] options ({})
100
+ # @option options [required, String] :token
101
+ # Unique identifier created by the notification service for an app on a
102
+ # device. The specific name for Token will vary, depending on which
103
+ # notification service is being used. For example, when using APNS as
104
+ # the notification service, you need the device token. Alternatively,
105
+ # when using GCM or ADM, the device token equivalent is called the
106
+ # registration ID.
107
+ # @option options [String] :custom_user_data
108
+ # Arbitrary user data to associate with the endpoint. Amazon SNS does
109
+ # not use this data. The data must be in UTF-8 format and less than 2KB.
110
+ # @option options [Hash<String,String>] :attributes
111
+ # For a list of attributes, see [SetEndpointAttributes][1].
112
+ #
113
+ #
114
+ #
115
+ # [1]: http://docs.aws.amazon.com/sns/latest/api/API_SetEndpointAttributes.html
116
+ # @return [PlatformEndpoint]
117
+ def create_platform_endpoint(options = {})
118
+ options = options.merge(platform_application_arn: @arn)
119
+ resp = @client.create_platform_endpoint(options)
120
+ PlatformEndpoint.new(
121
+ arn: resp.data.endpoint_arn,
122
+ client: @client
123
+ )
124
+ end
125
+
126
+ # @example Request syntax with placeholder values
127
+ #
128
+ # platform_application.delete()
129
+ # @param [Hash] options ({})
130
+ # @return [EmptyStructure]
131
+ def delete(options = {})
132
+ options = options.merge(platform_application_arn: @arn)
133
+ resp = @client.delete_platform_application(options)
134
+ resp.data
135
+ end
136
+
137
+ # @example Request syntax with placeholder values
138
+ #
139
+ # platform_application.set_attributes({
140
+ # attributes: { # required
141
+ # "String" => "String",
142
+ # },
143
+ # })
144
+ # @param [Hash] options ({})
145
+ # @option options [required, Hash<String,String>] :attributes
146
+ # A map of the platform application attributes. Attributes in this map
147
+ # include the following:
148
+ #
149
+ # * `PlatformCredential` -- The credential received from the
150
+ # notification service. For APNS/APNS\_SANDBOX, PlatformCredential is
151
+ # private key. For GCM, PlatformCredential is "API key". For ADM,
152
+ # PlatformCredential is "client secret".
153
+ #
154
+ # * `PlatformPrincipal` -- The principal received from the notification
155
+ # service. For APNS/APNS\_SANDBOX, PlatformPrincipal is SSL
156
+ # certificate. For GCM, PlatformPrincipal is not applicable. For ADM,
157
+ # PlatformPrincipal is "client id".
158
+ #
159
+ # * `EventEndpointCreated` -- Topic ARN to which EndpointCreated event
160
+ # notifications should be sent.
161
+ #
162
+ # * `EventEndpointDeleted` -- Topic ARN to which EndpointDeleted event
163
+ # notifications should be sent.
164
+ #
165
+ # * `EventEndpointUpdated` -- Topic ARN to which EndpointUpdate event
166
+ # notifications should be sent.
167
+ #
168
+ # * `EventDeliveryFailure` -- Topic ARN to which DeliveryFailure event
169
+ # notifications should be sent upon Direct Publish delivery failure
170
+ # (permanent) to one of the application's endpoints.
171
+ #
172
+ # * `SuccessFeedbackRoleArn` -- IAM role ARN used to give Amazon SNS
173
+ # write access to use CloudWatch Logs on your behalf.
174
+ #
175
+ # * `FailureFeedbackRoleArn` -- IAM role ARN used to give Amazon SNS
176
+ # write access to use CloudWatch Logs on your behalf.
177
+ #
178
+ # * `SuccessFeedbackSampleRate` -- Sample rate percentage (0-100) of
179
+ # successfully delivered messages.
180
+ # @return [EmptyStructure]
181
+ def set_attributes(options = {})
182
+ options = options.merge(platform_application_arn: @arn)
183
+ resp = @client.set_platform_application_attributes(options)
184
+ resp.data
185
+ end
186
+
187
+ # @!group Associations
188
+
189
+ # @example Request syntax with placeholder values
190
+ #
191
+ # endpoints = platform_application.endpoints()
192
+ # @param [Hash] options ({})
193
+ # @return [PlatformEndpoint::Collection]
194
+ def endpoints(options = {})
195
+ batches = Enumerator.new do |y|
196
+ options = options.merge(platform_application_arn: @arn)
197
+ resp = @client.list_endpoints_by_platform_application(options)
198
+ resp.each_page do |page|
199
+ batch = []
200
+ page.data.endpoints.each do |e|
201
+ batch << PlatformEndpoint.new(
202
+ arn: e.endpoint_arn,
203
+ client: @client
204
+ )
205
+ end
206
+ y.yield(batch)
207
+ end
208
+ end
209
+ PlatformEndpoint::Collection.new(batches)
210
+ end
211
+
212
+ # @deprecated
213
+ # @api private
214
+ def identifiers
215
+ { arn: @arn }
216
+ end
217
+ deprecated(:identifiers)
218
+
219
+ private
220
+
221
+ def extract_arn(args, options)
222
+ value = args[0] || options.delete(:arn)
223
+ case value
224
+ when String then value
225
+ when nil then raise ArgumentError, "missing required option :arn"
226
+ else
227
+ msg = "expected :arn to be a String, got #{value.class}"
228
+ raise ArgumentError, msg
229
+ end
230
+ end
231
+
232
+ class Collection < Aws::Resources::Collection; end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,266 @@
1
+ # WARNING ABOUT GENERATED CODE
2
+ #
3
+ # This file is generated. See the contributing for info on making contributions:
4
+ # https://github.com/aws/aws-sdk-ruby/blob/master/CONTRIBUTING.md
5
+ #
6
+ # WARNING ABOUT GENERATED CODE
7
+
8
+ module Aws
9
+ module SNS
10
+ class PlatformEndpoint
11
+
12
+ extend Aws::Deprecations
13
+
14
+ # @overload def initialize(arn, options = {})
15
+ # @param [String] arn
16
+ # @option options [Client] :client
17
+ # @overload def initialize(options = {})
18
+ # @option options [required, String] :arn
19
+ # @option options [Client] :client
20
+ def initialize(*args)
21
+ options = Hash === args.last ? args.pop.dup : {}
22
+ @arn = extract_arn(args, options)
23
+ @data = options.delete(:data)
24
+ @client = options.delete(:client) || Client.new(options)
25
+ end
26
+
27
+ # @!group Read-Only Attributes
28
+
29
+ # @return [String]
30
+ def arn
31
+ @arn
32
+ end
33
+
34
+ # Attributes include the following:
35
+ #
36
+ # * `CustomUserData` -- arbitrary user data to associate with the
37
+ # endpoint. Amazon SNS does not use this data. The data must be in
38
+ # UTF-8 format and less than 2KB.
39
+ #
40
+ # * `Enabled` -- flag that enables/disables delivery to the endpoint.
41
+ # Amazon SNS will set this to false when a notification service
42
+ # indicates to Amazon SNS that the endpoint is invalid. Users can set
43
+ # it back to true, typically after updating Token.
44
+ #
45
+ # * `Token` -- device token, also referred to as a registration id, for
46
+ # an app and mobile device. This is returned from the notification
47
+ # service when an app and mobile device are registered with the
48
+ # notification service.
49
+ # @return [Hash<String,String>]
50
+ def attributes
51
+ data.attributes
52
+ end
53
+
54
+ # @!endgroup
55
+
56
+ # @return [Client]
57
+ def client
58
+ @client
59
+ end
60
+
61
+ # Loads, or reloads {#data} for the current {PlatformEndpoint}.
62
+ # Returns `self` making it possible to chain methods.
63
+ #
64
+ # platform_endpoint.reload.data
65
+ #
66
+ # @return [self]
67
+ def load
68
+ resp = @client.get_endpoint_attributes(endpoint_arn: @arn)
69
+ @data = resp.data
70
+ self
71
+ end
72
+ alias :reload :load
73
+
74
+ # @return [Types::GetEndpointAttributesResponse]
75
+ # Returns the data for this {PlatformEndpoint}. Calls
76
+ # {Client#get_endpoint_attributes} if {#data_loaded?} is `false`.
77
+ def data
78
+ load unless @data
79
+ @data
80
+ end
81
+
82
+ # @return [Boolean]
83
+ # Returns `true` if this resource is loaded. Accessing attributes or
84
+ # {#data} on an unloaded resource will trigger a call to {#load}.
85
+ def data_loaded?
86
+ !!@data
87
+ end
88
+
89
+ # @!group Actions
90
+
91
+ # @example Request syntax with placeholder values
92
+ #
93
+ # platform_endpoint.delete()
94
+ # @param [Hash] options ({})
95
+ # @return [EmptyStructure]
96
+ def delete(options = {})
97
+ options = options.merge(endpoint_arn: @arn)
98
+ resp = @client.delete_endpoint(options)
99
+ resp.data
100
+ end
101
+
102
+ # @example Request syntax with placeholder values
103
+ #
104
+ # platform_endpoint.publish({
105
+ # topic_arn: "topicARN",
106
+ # phone_number: "String",
107
+ # message: "message", # required
108
+ # subject: "subject",
109
+ # message_structure: "messageStructure",
110
+ # message_attributes: {
111
+ # "String" => {
112
+ # data_type: "String", # required
113
+ # string_value: "String",
114
+ # binary_value: "data",
115
+ # },
116
+ # },
117
+ # })
118
+ # @param [Hash] options ({})
119
+ # @option options [String] :topic_arn
120
+ # The topic you want to publish to.
121
+ #
122
+ # If you don't specify a value for the `TopicArn` parameter, you must
123
+ # specify a value for the `PhoneNumber` or `TargetArn` parameters.
124
+ # @option options [String] :phone_number
125
+ # The phone number to which you want to deliver an SMS message. Use
126
+ # E.164 format.
127
+ #
128
+ # If you don't specify a value for the `PhoneNumber` parameter, you
129
+ # must specify a value for the `TargetArn` or `TopicArn` parameters.
130
+ # @option options [required, String] :message
131
+ # The message you want to send to the topic.
132
+ #
133
+ # If you want to send the same message to all transport protocols,
134
+ # include the text of the message as a String value.
135
+ #
136
+ # If you want to send different messages for each transport protocol,
137
+ # set the value of the `MessageStructure` parameter to `json` and use a
138
+ # JSON object for the `Message` parameter.
139
+ #
140
+ # Constraints: Messages must be UTF-8 encoded strings at most 256 KB in
141
+ # size (262144 bytes, not 262144 characters).
142
+ #
143
+ # JSON-specific constraints:
144
+ #
145
+ # * Keys in the JSON object that correspond to supported transport
146
+ # protocols must have simple JSON string values.
147
+ #
148
+ # * The values will be parsed (unescaped) before they are used in
149
+ # outgoing messages.
150
+ #
151
+ # * Outbound notifications are JSON encoded (meaning that the characters
152
+ # will be reescaped for sending).
153
+ #
154
+ # * Values have a minimum length of 0 (the empty string, "", is
155
+ # allowed).
156
+ #
157
+ # * Values have a maximum length bounded by the overall message size
158
+ # (so, including multiple protocols may limit message sizes).
159
+ #
160
+ # * Non-string values will cause the key to be ignored.
161
+ #
162
+ # * Keys that do not correspond to supported transport protocols are
163
+ # ignored.
164
+ #
165
+ # * Duplicate keys are not allowed.
166
+ #
167
+ # * Failure to parse or validate any key or value in the message will
168
+ # cause the `Publish` call to return an error (no partial delivery).
169
+ # @option options [String] :subject
170
+ # Optional parameter to be used as the "Subject" line when the message
171
+ # is delivered to email endpoints. This field will also be included, if
172
+ # present, in the standard JSON messages delivered to other endpoints.
173
+ #
174
+ # Constraints: Subjects must be ASCII text that begins with a letter,
175
+ # number, or punctuation mark; must not include line breaks or control
176
+ # characters; and must be less than 100 characters long.
177
+ # @option options [String] :message_structure
178
+ # Set `MessageStructure` to `json` if you want to send a different
179
+ # message for each protocol. For example, using one publish action, you
180
+ # can send a short message to your SMS subscribers and a longer message
181
+ # to your email subscribers. If you set `MessageStructure` to `json`,
182
+ # the value of the `Message` parameter must:
183
+ #
184
+ # * be a syntactically valid JSON object; and
185
+ #
186
+ # * contain at least a top-level JSON key of "default" with a value
187
+ # that is a string.
188
+ #
189
+ # You can define other top-level keys that define the message you want
190
+ # to send to a specific transport protocol (e.g., "http").
191
+ #
192
+ # For information about sending different messages for each protocol
193
+ # using the AWS Management Console, go to [Create Different Messages for
194
+ # Each Protocol][1] in the *Amazon Simple Notification Service Getting
195
+ # Started Guide*.
196
+ #
197
+ # Valid value: `json`
198
+ #
199
+ #
200
+ #
201
+ # [1]: http://docs.aws.amazon.com/sns/latest/gsg/Publish.html#sns-message-formatting-by-protocol
202
+ # @option options [Hash<String,Types::MessageAttributeValue>] :message_attributes
203
+ # Message attributes for Publish action.
204
+ # @return [Types::PublishResponse]
205
+ def publish(options = {})
206
+ options = options.merge(target_arn: @arn)
207
+ resp = @client.publish(options)
208
+ resp.data
209
+ end
210
+
211
+ # @example Request syntax with placeholder values
212
+ #
213
+ # platform_endpoint.set_attributes({
214
+ # attributes: { # required
215
+ # "String" => "String",
216
+ # },
217
+ # })
218
+ # @param [Hash] options ({})
219
+ # @option options [required, Hash<String,String>] :attributes
220
+ # A map of the endpoint attributes. Attributes in this map include the
221
+ # following:
222
+ #
223
+ # * `CustomUserData` -- arbitrary user data to associate with the
224
+ # endpoint. Amazon SNS does not use this data. The data must be in
225
+ # UTF-8 format and less than 2KB.
226
+ #
227
+ # * `Enabled` -- flag that enables/disables delivery to the endpoint.
228
+ # Amazon SNS will set this to false when a notification service
229
+ # indicates to Amazon SNS that the endpoint is invalid. Users can set
230
+ # it back to true, typically after updating Token.
231
+ #
232
+ # * `Token` -- device token, also referred to as a registration id, for
233
+ # an app and mobile device. This is returned from the notification
234
+ # service when an app and mobile device are registered with the
235
+ # notification service.
236
+ # @return [EmptyStructure]
237
+ def set_attributes(options = {})
238
+ options = options.merge(endpoint_arn: @arn)
239
+ resp = @client.set_endpoint_attributes(options)
240
+ resp.data
241
+ end
242
+
243
+ # @deprecated
244
+ # @api private
245
+ def identifiers
246
+ { arn: @arn }
247
+ end
248
+ deprecated(:identifiers)
249
+
250
+ private
251
+
252
+ def extract_arn(args, options)
253
+ value = args[0] || options.delete(:arn)
254
+ case value
255
+ when String then value
256
+ when nil then raise ArgumentError, "missing required option :arn"
257
+ else
258
+ msg = "expected :arn to be a String, got #{value.class}"
259
+ raise ArgumentError, msg
260
+ end
261
+ end
262
+
263
+ class Collection < Aws::Resources::Collection; end
264
+ end
265
+ end
266
+ end