aliquot 2.3.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2770596cedb5e18b0d1abd71b16081826a9f78668a8b04994913a31f21c593ca
4
- data.tar.gz: 3b4525df139a05d3a963fb06eae0881d833b686a45a6bf06707ad6ff44b98b0d
3
+ metadata.gz: f8e2a9a7e324874ed68aeaacd8a072ea00dedfce4e6022494f7333c94b55ec1d
4
+ data.tar.gz: 5bfc71f786436d227100470dc37a0d8715196b59d474d0b39b6dd3afa730ff61
5
5
  SHA512:
6
- metadata.gz: 5e50437ca7ad2733ca13f8bfb4448fba30b8187a01f304b213da5d6261b485af2ca8aff141031c3d7ab031d8a25f7b295e863c582fa9a8de7112865d0d9e8d5a
7
- data.tar.gz: 23af415ed4ac86e67932d26220f9cbbe5664f4966db378aefc4bd563c521a399fa4659930b3c7f44a698baf574be10b12f6606a5d80a1b1aa85deeb63d0ad2b5
6
+ metadata.gz: c95f8f7f99e9bbb9dfa7685927521e135b480e8a9e098c265771d592e1ebbd9c16e75be9b11b03cb369d0290e6fbb5c860be7cfad2252543b84950448011e13b
7
+ data.tar.gz: 9983ede008609ae095ce8dc863e361c7f3c46e449efe59c7d0422331284b9e18ec8b1182d14da9a71b5361266435c68d6fb125750165968d82ea755365ec9ff3
@@ -66,6 +66,9 @@ module Aliquot
66
66
 
67
67
  begin
68
68
  @message = JSON.parse(decrypt(aes_key, @signed_message[:encryptedMessage]))
69
+ @message['paymentMethodDetails'].merge!(
70
+ 'threedsCryptogram' => @message['paymentMethodDetails']
71
+ .delete('3dsCryptogram')) if @message['paymentMethodDetails']['3dsCryptogram']
69
72
  rescue JSON::JSONError => e
70
73
  raise InputError, "encryptedMessage JSON is invalid, #{e.message}"
71
74
  rescue => e
@@ -221,7 +224,20 @@ module Aliquot
221
224
  validator.validate
222
225
 
223
226
  # Output is hashed with symbolized keys.
224
- validator.output
227
+ message_hash = validator.output
228
+
229
+ payment_method_details_message = message_hash[:paymentMethodDetails]
230
+ message_details_validator =
231
+ if message_hash[:paymentMethod] == 'TOKENIZED_CARD' ||
232
+ message_hash[:paymentMethodDetails]['authMethod'] == 'CRYPTOGRAM_3DS'
233
+ Aliquot::Validator::PaymentMethodDetailsValidator.new(payment_method_details_message, protocol_version, true)
234
+ else
235
+ Aliquot::Validator::PaymentMethodDetailsValidator.new(payment_method_details_message, protocol_version, false)
236
+ end
237
+ message_details_validator.validate
238
+ message_hash[:paymentMethodDetails] = message_details_validator.output
239
+
240
+ message_hash
225
241
  end
226
242
 
227
243
  ##
@@ -21,8 +21,8 @@ module Aliquot
21
21
  base64_asn1?: 'must be base64-encoded ANS.1 value',
22
22
  json?: 'must be valid JSON',
23
23
 
24
- is_authMethodCryptogram3DS: 'authMethod CRYPTOGRAM_3DS requires eciIndicator',
25
- is_authMethodCard: 'eciIndicator/cryptogram must be omitted when PAN_ONLY',
24
+ is_authMethodCryptogram3DS: 'authMethod CRYPTOGRAM_3DS or 3DS requires eciIndicator',
25
+ is_authMethodCard: 'eciIndicator/cryptogram/3dsCryptogram must be omitted when PAN_ONLY',
26
26
  }.freeze
27
27
 
28
28
  def self.base64_check(value)
@@ -118,8 +118,6 @@ module Aliquot
118
118
  rule(:keyValue).validate(:ec_public_key?)
119
119
  end
120
120
 
121
- SignedKeySchema = SignedKeyContract.new
122
-
123
121
  # Schema used for the 'intermediateSigningKey' hash included in ECv2.
124
122
  class IntermediateSigningKeyContract < Dry::Validation::Contract
125
123
  json do
@@ -129,12 +127,10 @@ module Aliquot
129
127
  rule(:signedKey).validate(:json?)
130
128
  rule(:signatures).each do
131
129
  key.failure('must be Base64') unless Aliquot::Validator.base64_check(value) &&
132
- Aliquot::Validator.ans1_check(value)
130
+ Aliquot::Validator.ans1_check(value)
133
131
  end
134
132
  end
135
133
 
136
- IntermediateSigningKeySchema = IntermediateSigningKeyContract.new
137
-
138
134
  # DRY-Validation schema for Google Pay token
139
135
  class TokenContract < Dry::Validation::Contract
140
136
  json do
@@ -147,13 +143,11 @@ module Aliquot
147
143
  rule(:signedMessage).validate(:json?)
148
144
 
149
145
  rule(:intermediateSigningKey) do
150
- key.failure('is missing') if 'ECv2'.eql?(values[:protocolVersion]) &&
151
- values[:intermediateSigningKey].nil?
146
+ key.failure('is missing') if values[:protocolVersion] == 'ECv2' &&
147
+ values[:intermediateSigningKey].nil?
152
148
  end
153
149
  end
154
150
 
155
- TokenSchema = TokenContract.new
156
-
157
151
  # DRY-Validation schema for signedMessage component Google Pay token
158
152
  class SignedMessageContract < Dry::Validation::Contract
159
153
  json do
@@ -166,41 +160,55 @@ module Aliquot
166
160
  rule(:tag).validate(:base64?)
167
161
  end
168
162
 
169
- SignedMessageSchema = SignedMessageContract.new
170
-
171
- # DRY-Validation schema for paymentMethodDetails component Google Pay token
172
- class PaymentMethodDetailsContract < Dry::Validation::Contract
163
+ class CommonPaymentMethodDetailsContract < Dry::Validation::Contract
173
164
  json do
174
- required(:pan).filled(:str?)
175
165
  required(:expirationMonth).filled(:int?)
176
166
  required(:expirationYear).filled(:int?)
177
- required(:authMethod).filled(:str?, included_in?: %w[PAN_ONLY CRYPTOGRAM_3DS])
178
-
179
- optional(:cryptogram).filled(:str?)
180
- optional(:eciIndicator).filled(:str?)
181
167
  end
182
- rule(:pan).validate(:integer_string?, :pan?)
183
168
  rule(:expirationMonth).validate(:month?)
184
169
  rule(:expirationYear).validate(:year?)
185
- rule(:eciIndicator).validate(:eci?)
170
+ end
186
171
 
187
- rule(:cryptogram) do
188
- key.failure('is missing') if 'CRYPTOGRAM_3DS'.eql?(values[:authMethod]) &&
189
- values[:cryptogram].nil?
172
+ class ECv1_PaymentMethodDetailsContract < CommonPaymentMethodDetailsContract
173
+ json(CommonPaymentMethodDetailsContract.schema) do
174
+ required(:pan).filled(:str?)
190
175
  end
191
176
 
192
- rule(:cryptogram) do
193
- key.failure('cannot be defined') if 'PAN_ONLY'.eql?(values[:authMethod]) &&
194
- !values[:cryptogram].nil?
177
+ rule(:pan).validate(:integer_string?, :pan?)
178
+ end
179
+
180
+ class ECv1_TokenizedPaymentMethodDetailsContract < CommonPaymentMethodDetailsContract
181
+ json(CommonPaymentMethodDetailsContract.schema) do
182
+ required(:dpan).filled(:str?)
183
+ required(:threedsCryptogram).filled(:str?)
184
+ required(:eciIndicator).filled(:str?)
185
+ required(:authMethod).filled(:str?, included_in?: %w[3DS])
195
186
  end
196
187
 
197
- rule(:eciIndicator) do
198
- key.failure('cannot be defined') if 'PAN_ONLY'.eql?(values[:authMethod]) &&
199
- !values[:eciIndicator].nil?
188
+ rule(:dpan).validate(:integer_string?, :pan?)
189
+ rule(:eciIndicator).validate(:eci?)
190
+ end
191
+
192
+ class ECv2_PaymentMethodDetailsContract < CommonPaymentMethodDetailsContract
193
+ json(CommonPaymentMethodDetailsContract.schema) do
194
+ required(:pan).filled(:str?)
195
+ required(:authMethod).filled(:str?, included_in?: %w[PAN_ONLY])
200
196
  end
197
+
198
+ rule(:pan).validate(:integer_string?, :pan?)
201
199
  end
202
200
 
203
- PaymentMethodDetailsSchema = PaymentMethodDetailsContract.new
201
+ class ECv2_TokenizedPaymentMethodDetailsContract < CommonPaymentMethodDetailsContract
202
+ json(CommonPaymentMethodDetailsContract.schema) do
203
+ required(:pan).filled(:str?)
204
+ required(:cryptogram).filled(:str?)
205
+ required(:eciIndicator).filled(:str?)
206
+ required(:authMethod).filled(:str?, included_in?: %w[CRYPTOGRAM_3DS])
207
+ end
208
+
209
+ rule(:pan).validate(:integer_string?, :pan?)
210
+ rule(:eciIndicator).validate(:eci?)
211
+ end
204
212
 
205
213
  # DRY-Validation schema for encryptedMessage component Google Pay token
206
214
  class EncryptedMessageContract < Dry::Validation::Contract
@@ -208,17 +216,40 @@ module Aliquot
208
216
  required(:messageExpiration).filled(:str?)
209
217
  required(:messageId).filled(:str?)
210
218
  required(:paymentMethod).filled(:str?)
211
- required(:paymentMethodDetails).filled(:hash).schema(PaymentMethodDetailsContract.schema)
219
+ required(:paymentMethodDetails).filled(:hash)
212
220
  optional(:gatewayMerchantId).filled(:str?)
213
221
  end
214
222
  rule(:messageExpiration).validate(:integer_string?)
223
+
224
+ rule(:paymentMethodDetails).validate do
225
+ contract =
226
+ if values[:protocolVersion] == 'ECv1'
227
+ if values[:paymentMethod] == 'TOKENIZED_CARD'
228
+ ECv1_TokenizedPaymentMethodDetailsContract.new
229
+ else
230
+ ECv1_PaymentMethodDetailsContract.new
231
+ end
232
+ else
233
+ if values[:authMethod] == 'CRYPTOGRAM_3DS'
234
+ ECv2_TokenizedPaymentMethodDetailsContract.new
235
+ else
236
+ ECv2_PaymentMethodDetailsContract.new
237
+ end
238
+ end
239
+ contract.call(values[:paymentMethodDetails])
240
+ end
241
+
215
242
  rule(:paymentMethod) do
216
- key.failure('must be equal to CARD') unless 'CARD'.eql?(value)
243
+ if values[:paymentMethodDetails].is_a?(Hash)
244
+ if '3DS'.eql?(values[:paymentMethodDetails]['authMethod']) # Tokenized ECv1
245
+ key.failure('must be equal to TOKENIZED_CARD') unless value == 'TOKENIZED_CARD'
246
+ else
247
+ key.failure('must be equal to CARD') unless value == 'CARD'
248
+ end
249
+ end
217
250
  end
218
251
  end
219
252
 
220
- EncryptedMessageSchema = EncryptedMessageContract.new
221
-
222
253
  module InstanceMethods
223
254
  attr_reader :output
224
255
 
@@ -226,7 +257,7 @@ module Aliquot
226
257
  @validation ||= @schema.call(@input)
227
258
  @output = @validation.to_h
228
259
  return true if @validation.success?
229
- raise Aliquot::ValidationError, "validation error(s), #{errors_formatted}"
260
+ raise Aliquot::ValidationError, "validation error(s): #{error_list.join(', ')}"
230
261
  end
231
262
 
232
263
  def valid?
@@ -241,13 +272,12 @@ module Aliquot
241
272
  @validation.errors
242
273
  end
243
274
 
244
- def errors_formatted(node = [errors])
245
- node.pop.flat_map do |key, value|
246
- if value.is_a?(Array)
247
- value.map { |error| "#{(node + [key]).join('.')} #{error}" }
248
- else
249
- errors_formatted(node + [key, value])
250
- end
275
+ def error_list(node = errors.to_h, path = '')
276
+ if node.is_a?(Array)
277
+ node.map { |error| "#{path} #{error}" }
278
+ elsif node.is_a?(Hash)
279
+ path = "#{path}." unless path.empty?
280
+ node.flat_map { |key, sub_node| error_list(sub_node, "#{path}#{key}") }
251
281
  end
252
282
  end
253
283
  end
@@ -260,7 +290,7 @@ module Aliquot
260
290
 
261
291
  def initialize(input)
262
292
  @input = input
263
- @schema = TokenSchema
293
+ @schema = TokenContract.new
264
294
  end
265
295
  end
266
296
 
@@ -272,7 +302,7 @@ module Aliquot
272
302
 
273
303
  def initialize(input)
274
304
  @input = input
275
- @schema = SignedMessageSchema
305
+ @schema = SignedMessageContract.new
276
306
  end
277
307
  end
278
308
 
@@ -284,7 +314,32 @@ module Aliquot
284
314
 
285
315
  def initialize(input)
286
316
  @input = input
287
- @schema = EncryptedMessageSchema
317
+ @schema = EncryptedMessageContract.new
318
+ end
319
+ end
320
+
321
+ # Class for validating the encryptedMessage component of a Google Pay token
322
+ class PaymentMethodDetailsValidator
323
+ include InstanceMethods
324
+
325
+ class Error < ::Aliquot::Error; end
326
+
327
+ def initialize(input, version, tokenized)
328
+ @input = input
329
+ @schema =
330
+ if version == 'ECv1'
331
+ if tokenized
332
+ Aliquot::Validator::ECv1_TokenizedPaymentMethodDetailsContract.new
333
+ else
334
+ Aliquot::Validator::ECv1_PaymentMethodDetailsContract.new
335
+ end
336
+ else
337
+ if tokenized
338
+ Aliquot::Validator::ECv2_TokenizedPaymentMethodDetailsContract.new
339
+ else
340
+ Aliquot::Validator::ECv2_PaymentMethodDetailsContract.new
341
+ end
342
+ end
288
343
  end
289
344
  end
290
345
 
@@ -295,7 +350,7 @@ module Aliquot
295
350
 
296
351
  def initialize(input)
297
352
  @input = input
298
- @schema = SignedKeySchema
353
+ @schema = SignedKeyContract.new
299
354
  end
300
355
  end
301
356
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aliquot
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clearhaus
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-05 00:00:00.000000000 Z
11
+ date: 2024-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-validation
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.0'
61
+ version: '4.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.0'
68
+ version: '4.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -123,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  requirements: []
126
- rubygems_version: 3.3.7
126
+ rubygems_version: 3.1.6
127
127
  signing_key:
128
128
  specification_version: 4
129
129
  summary: Validates Google Pay tokens