aliquot 2.3.0 → 3.0.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/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
|