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 +4 -4
- data/lib/aliquot/payment.rb +17 -1
- data/lib/aliquot/validator.rb +103 -48
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8e2a9a7e324874ed68aeaacd8a072ea00dedfce4e6022494f7333c94b55ec1d
|
4
|
+
data.tar.gz: 5bfc71f786436d227100470dc37a0d8715196b59d474d0b39b6dd3afa730ff61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c95f8f7f99e9bbb9dfa7685927521e135b480e8a9e098c265771d592e1ebbd9c16e75be9b11b03cb369d0290e6fbb5c860be7cfad2252543b84950448011e13b
|
7
|
+
data.tar.gz: 9983ede008609ae095ce8dc863e361c7f3c46e449efe59c7d0422331284b9e18ec8b1182d14da9a71b5361266435c68d6fb125750165968d82ea755365ec9ff3
|
data/lib/aliquot/payment.rb
CHANGED
@@ -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
|
##
|
data/lib/aliquot/validator.rb
CHANGED
@@ -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
|
-
|
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
|
151
|
-
|
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
|
-
|
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
|
-
|
170
|
+
end
|
186
171
|
|
187
|
-
|
188
|
-
|
189
|
-
|
172
|
+
class ECv1_PaymentMethodDetailsContract < CommonPaymentMethodDetailsContract
|
173
|
+
json(CommonPaymentMethodDetailsContract.schema) do
|
174
|
+
required(:pan).filled(:str?)
|
190
175
|
end
|
191
176
|
|
192
|
-
rule(:
|
193
|
-
|
194
|
-
|
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(:
|
198
|
-
|
199
|
-
|
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
|
-
|
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)
|
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
|
-
|
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)
|
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
|
245
|
-
node.
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
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 =
|
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 =
|
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 =
|
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 =
|
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:
|
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:
|
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: '
|
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: '
|
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.
|
126
|
+
rubygems_version: 3.1.6
|
127
127
|
signing_key:
|
128
128
|
specification_version: 4
|
129
129
|
summary: Validates Google Pay tokens
|