aliquot 1.0.0 → 2.1.2
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/error.rb +2 -1
- data/lib/aliquot/payment.rb +10 -9
- data/lib/aliquot/validator.rb +179 -93
- metadata +27 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: de89d0021775b3047c345d9d41bdb90855fe9fac9e1a663b83e5f865fc407edf
|
4
|
+
data.tar.gz: ac219aa43dc4924729d1f29013e25d1cedd616c3f086734607bc35006182be8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05102ee3be01374cd0b58d3dab85ddc6428d16df25a7dc7262989a3108691ab5c3c7e94b128f544c7d66be8f70cb428f8babc22d2fe805a31c1efb84912fcacc
|
7
|
+
data.tar.gz: 98a9aa9ae43295d177ed42c1d77f4e785f5eff0751c87fbf500fb52f48c98f684a9e9f331ad14e89dfd393b464585a61dc6b8c2377b2ebea7fa075b1f859fb59
|
data/lib/aliquot/error.rb
CHANGED
data/lib/aliquot/payment.rb
CHANGED
@@ -10,16 +10,16 @@ module Aliquot
|
|
10
10
|
##
|
11
11
|
# A Payment represents a single payment using Google Pay.
|
12
12
|
# It is used to verify/decrypt the supplied token by using the shared secret,
|
13
|
-
# thus avoiding having knowledge of
|
13
|
+
# thus avoiding having knowledge of any private keys involved.
|
14
14
|
class Payment
|
15
15
|
SUPPORTED_PROTOCOL_VERSIONS = %w[ECv1 ECv2].freeze
|
16
16
|
##
|
17
17
|
# Parameters:
|
18
18
|
# token_string:: Google Pay token (JSON string)
|
19
19
|
# shared_secret:: Base64 encoded shared secret
|
20
|
-
#
|
20
|
+
# recipient_id:: Google Pay recipient ID
|
21
21
|
# signing_keys:: Signing keys fetched from Google
|
22
|
-
def initialize(token_string, shared_secret,
|
22
|
+
def initialize(token_string, shared_secret, recipient_id,
|
23
23
|
signing_keys: ENV['GOOGLE_SIGNING_KEYS'])
|
24
24
|
|
25
25
|
begin
|
@@ -32,7 +32,7 @@ module Aliquot
|
|
32
32
|
@token = validation.output
|
33
33
|
|
34
34
|
@shared_secret = shared_secret
|
35
|
-
@
|
35
|
+
@recipient_id = recipient_id
|
36
36
|
@signing_keys = signing_keys
|
37
37
|
end
|
38
38
|
|
@@ -43,7 +43,7 @@ module Aliquot
|
|
43
43
|
raise Error, "supported protocol versions are #{SUPPORTED_PROTOCOL_VERSIONS.join(', ')}"
|
44
44
|
end
|
45
45
|
|
46
|
-
@recipient_id =
|
46
|
+
@recipient_id = validate_recipient_id
|
47
47
|
|
48
48
|
check_shared_secret
|
49
49
|
|
@@ -102,9 +102,10 @@ module Aliquot
|
|
102
102
|
@intermediate_key[:keyExpiration].to_i < cur_millis
|
103
103
|
end
|
104
104
|
|
105
|
-
def
|
106
|
-
raise
|
107
|
-
|
105
|
+
def validate_recipient_id
|
106
|
+
raise InvalidRecipientIDError, 'recipient_id must be alphanumeric and punctuation' unless /\A[[:graph:]]+\z/ =~ @recipient_id
|
107
|
+
|
108
|
+
@recipient_id
|
108
109
|
end
|
109
110
|
|
110
111
|
def check_shared_secret
|
@@ -209,8 +210,8 @@ module Aliquot
|
|
209
210
|
|
210
211
|
def decrypt(key, encrypted)
|
211
212
|
c = new_cipher
|
212
|
-
c.key = key
|
213
213
|
c.decrypt
|
214
|
+
c.key = key
|
214
215
|
|
215
216
|
c.update(Base64.strict_decode64(encrypted)) + c.final
|
216
217
|
end
|
data/lib/aliquot/validator.rb
CHANGED
@@ -9,143 +9,221 @@ module Aliquot
|
|
9
9
|
module Validator
|
10
10
|
# Verified according to:
|
11
11
|
# https://developers.google.com/pay/api/web/guides/resources/payment-data-cryptography#payment-method-token-structure
|
12
|
-
module Predicates
|
13
|
-
include Dry::Logic::Predicates
|
14
|
-
|
15
|
-
CUSTOM_PREDICATE_ERRORS = {
|
16
|
-
base64?: 'must be Base64',
|
17
|
-
pan?: 'must be a pan',
|
18
|
-
ec_public_key?: 'must be an EC public key',
|
19
|
-
eci?: 'must be an ECI',
|
20
|
-
json_string?: 'must be valid JSON',
|
21
|
-
integer_string?: 'must be string encoded integer',
|
22
|
-
month?: 'must be a month (1..12)',
|
23
|
-
year?: 'must be a year (2000..3000)',
|
24
|
-
base64_asn1?: 'must be base64 encoded asn1 value',
|
25
|
-
json_object?: 'must be a JSON object',
|
26
|
-
|
27
|
-
authMethodCryptogram3DS: 'authMethod CRYPTOGRAM_3DS requires eciIndicator',
|
28
|
-
authMethodCard: 'eciIndicator/cryptogram must be omitted when PAN_ONLY',
|
29
|
-
}.freeze
|
30
|
-
|
31
|
-
# Support Ruby 2.3, but use the faster #match? when available.
|
32
|
-
match_b = ''.respond_to?(:match?) ? ->(s, re) { s.match?(re) } : ->(s, re) { !!(s =~ re) }
|
33
|
-
|
34
|
-
def self.to_bool(lbd)
|
35
|
-
lbd.call
|
36
|
-
true
|
37
|
-
rescue
|
38
|
-
false
|
39
|
-
end
|
40
12
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
13
|
+
CUSTOM_ERRORS = {
|
14
|
+
base64?: 'must be Base64',
|
15
|
+
pan?: 'must be a PAN',
|
16
|
+
ec_public_key?: 'must be an EC public key',
|
17
|
+
eci?: 'must be an ECI',
|
18
|
+
integer_string?: 'must be string encoded integer',
|
19
|
+
month?: 'must be a month (1..12)',
|
20
|
+
year?: 'must be a year (2000..3000)',
|
21
|
+
base64_asn1?: 'must be base64-encoded ANS.1 value',
|
22
|
+
json?: 'must be valid JSON',
|
23
|
+
|
24
|
+
is_authMethodCryptogram3DS: 'authMethod CRYPTOGRAM_3DS requires eciIndicator',
|
25
|
+
is_authMethodCard: 'eciIndicator/cryptogram must be omitted when PAN_ONLY',
|
26
|
+
}.freeze
|
27
|
+
|
28
|
+
def self.base64_check(value)
|
29
|
+
/\A[=A-Za-z0-9+\/]*\z/.match?(value) && # allowable chars
|
30
|
+
value.length.remainder(4).zero? && # multiple of 4
|
31
|
+
!/=[^$=]/.match?(value) && # may only end with ='s
|
32
|
+
!/===/.match?(value) # at most 2 ='s
|
33
|
+
end
|
48
34
|
|
49
|
-
|
50
|
-
|
51
|
-
|
35
|
+
Dry::Validation.register_macro(:base64?) do
|
36
|
+
if key?
|
37
|
+
unless Aliquot::Validator.base64_check(value)
|
38
|
+
key.failure(CUSTOM_ERRORS[:base64?])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
52
42
|
|
53
|
-
|
43
|
+
def self.ans1_check(value)
|
44
|
+
OpenSSL::ASN1.decode(Base64.strict_decode64(value)) rescue false
|
45
|
+
end
|
54
46
|
|
55
|
-
|
47
|
+
Dry::Validation.register_macro(:base64_asn1?) do
|
48
|
+
if key?
|
49
|
+
unless Aliquot::Validator.ans1_check(value)
|
50
|
+
key.failure(CUSTOM_ERRORS[:base64_asn1?])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
56
54
|
|
57
|
-
|
55
|
+
Dry::Validation.register_macro(:pan?) do
|
56
|
+
if key?
|
57
|
+
unless /\A[1-9][0-9]{11,18}\z/.match?(value)
|
58
|
+
key.failure(CUSTOM_ERRORS[:pan?])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
58
62
|
|
59
|
-
|
63
|
+
Dry::Validation.register_macro(:ec_public_key?) do
|
64
|
+
if key?
|
65
|
+
begin
|
66
|
+
OpenSSL::PKey::EC.new(Base64.decode64(value)).check_key
|
67
|
+
rescue
|
68
|
+
key.failure(CUSTOM_ERRORS[:ec_public_key?])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
60
72
|
|
61
|
-
|
73
|
+
Dry::Validation.register_macro(:eci?) do
|
74
|
+
if key?
|
75
|
+
unless /\A\d{1,2}\z/.match?(value)
|
76
|
+
key.failure(CUSTOM_ERRORS[:eci?])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
62
80
|
|
63
|
-
|
81
|
+
Dry::Validation.register_macro(:integer_string?) do
|
82
|
+
if key?
|
83
|
+
unless /\A\d+\z/.match?(value)
|
84
|
+
key.failure(CUSTOM_ERRORS[:integer_string?])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
64
88
|
|
65
|
-
|
89
|
+
Dry::Validation.register_macro(:json?) do
|
90
|
+
if key?
|
91
|
+
json = JSON.parse(value) rescue false
|
92
|
+
key.failure(CUSTOM_ERRORS[:json?]) unless json
|
93
|
+
end
|
94
|
+
end
|
66
95
|
|
67
|
-
|
96
|
+
Dry::Validation.register_macro(:month?) do
|
97
|
+
if key?
|
98
|
+
unless value.between?(1, 12)
|
99
|
+
key.failure(CUSTOM_ERRORS[:month?])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
68
103
|
|
69
|
-
|
104
|
+
Dry::Validation.register_macro(:year?) do
|
105
|
+
if key?
|
106
|
+
unless value.between?(2000, 3000)
|
107
|
+
key.failure(CUSTOM_ERRORS[:year?])
|
108
|
+
end
|
109
|
+
end
|
70
110
|
end
|
71
111
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
super.merge(en: { errors: Predicates::CUSTOM_PREDICATE_ERRORS })
|
112
|
+
class SignedKeyContract < Dry::Validation::Contract
|
113
|
+
json do
|
114
|
+
required(:keyExpiration).filled(:str?)
|
115
|
+
required(:keyValue).filled(:str?)
|
77
116
|
end
|
117
|
+
rule(:keyExpiration).validate(:integer_string?)
|
118
|
+
rule(:keyValue).validate(:ec_public_key?)
|
78
119
|
end
|
79
120
|
|
80
|
-
|
81
|
-
IntermediateSigningKeySchema = Dry::Validation.Schema(BaseSchema) do
|
82
|
-
required(:signedKey).filled(:str?, :json_string?)
|
121
|
+
SignedKeySchema = SignedKeyContract.new
|
83
122
|
|
84
|
-
|
123
|
+
# Schema used for the 'intermediateSigningKey' hash included in ECv2.
|
124
|
+
class IntermediateSigningKeyContract < Dry::Validation::Contract
|
125
|
+
json do
|
126
|
+
required(:signedKey).filled(:str?)
|
127
|
+
required(:signatures).array(:str?)
|
128
|
+
end
|
129
|
+
rule(:signedKey).validate(:json?)
|
130
|
+
rule(:signatures).each do
|
131
|
+
key.failure('must be Base64') unless Aliquot::Validator.base64_check(value) &&
|
132
|
+
Aliquot::Validator.ans1_check(value)
|
133
|
+
end
|
85
134
|
end
|
86
135
|
|
87
|
-
|
88
|
-
required(:keyExpiration).filled(:integer_string?)
|
89
|
-
required(:keyValue).filled(:ec_public_key?)
|
90
|
-
end
|
136
|
+
IntermediateSigningKeySchema = IntermediateSigningKeyContract.new
|
91
137
|
|
92
138
|
# DRY-Validation schema for Google Pay token
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
required(:
|
139
|
+
class TokenContract < Dry::Validation::Contract
|
140
|
+
json do
|
141
|
+
required(:signature).filled(:str?)
|
142
|
+
required(:signedMessage).filled(:str?)
|
143
|
+
required(:protocolVersion).filled(:str?)
|
144
|
+
optional(:intermediateSigningKey).hash(IntermediateSigningKeyContract.new.schema)
|
98
145
|
end
|
146
|
+
rule(:signature).validate(:base64?, :base64_asn1?)
|
147
|
+
rule(:signedMessage).validate(:json?)
|
99
148
|
|
100
|
-
|
101
|
-
|
102
|
-
|
149
|
+
rule(:intermediateSigningKey) do
|
150
|
+
key.failure('is missing') if 'ECv2'.eql?(values[:protocolVersion]) &&
|
151
|
+
values[:intermediateSigningKey].nil?
|
152
|
+
end
|
103
153
|
end
|
104
154
|
|
155
|
+
TokenSchema = TokenContract.new
|
156
|
+
|
105
157
|
# DRY-Validation schema for signedMessage component Google Pay token
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
158
|
+
class SignedMessageContract < Dry::Validation::Contract
|
159
|
+
json do
|
160
|
+
required(:encryptedMessage).filled(:str?)
|
161
|
+
required(:ephemeralPublicKey).filled(:str?)
|
162
|
+
required(:tag).filled(:str?)
|
163
|
+
end
|
164
|
+
rule(:encryptedMessage).validate(:base64?)
|
165
|
+
rule(:ephemeralPublicKey).validate(:base64?)
|
166
|
+
rule(:tag).validate(:base64?)
|
110
167
|
end
|
111
168
|
|
112
|
-
|
113
|
-
PaymentMethodDetailsSchema = Dry::Validation.Schema(BaseSchema) do
|
114
|
-
required(:pan).filled(:integer_string?, :pan?)
|
115
|
-
required(:expirationMonth).filled(:int?, :month?)
|
116
|
-
required(:expirationYear).filled(:int?, :year?)
|
117
|
-
required(:authMethod).filled(:str?, included_in?: %w[PAN_ONLY CRYPTOGRAM_3DS])
|
118
|
-
|
119
|
-
optional(:cryptogram).filled(:str?)
|
120
|
-
optional(:eciIndicator).filled(:str?, :eci?)
|
169
|
+
SignedMessageSchema = SignedMessageContract.new
|
121
170
|
|
122
|
-
|
123
|
-
|
171
|
+
# DRY-Validation schema for paymentMethodDetails component Google Pay token
|
172
|
+
class PaymentMethodDetailsContract < Dry::Validation::Contract
|
173
|
+
json do
|
174
|
+
required(:pan).filled(:str?)
|
175
|
+
required(:expirationMonth).filled(:int?)
|
176
|
+
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
|
+
end
|
182
|
+
rule(:pan).validate(:integer_string?, :pan?)
|
183
|
+
rule(:expirationMonth).validate(:month?)
|
184
|
+
rule(:expirationYear).validate(:year?)
|
185
|
+
rule(:eciIndicator).validate(:eci?)
|
186
|
+
|
187
|
+
rule(:cryptogram) do
|
188
|
+
key.failure('is missing') if 'CRYPTOGRAM_3DS'.eql?(values[:authMethod]) &&
|
189
|
+
values[:cryptogram].nil?
|
124
190
|
end
|
125
191
|
|
126
|
-
rule(
|
127
|
-
|
192
|
+
rule(:cryptogram) do
|
193
|
+
key.failure('cannot be defined') if 'PAN_ONLY'.eql?(values[:authMethod]) &&
|
194
|
+
!values[:cryptogram].nil?
|
128
195
|
end
|
129
196
|
|
130
|
-
rule(
|
131
|
-
|
197
|
+
rule(:eciIndicator) do
|
198
|
+
key.failure('cannot be defined') if 'PAN_ONLY'.eql?(values[:authMethod]) &&
|
199
|
+
!values[:eciIndicator].nil?
|
132
200
|
end
|
133
201
|
end
|
134
202
|
|
203
|
+
PaymentMethodDetailsSchema = PaymentMethodDetailsContract.new
|
204
|
+
|
135
205
|
# DRY-Validation schema for encryptedMessage component Google Pay token
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
206
|
+
class EncryptedMessageContract < Dry::Validation::Contract
|
207
|
+
json do
|
208
|
+
required(:messageExpiration).filled(:str?)
|
209
|
+
required(:messageId).filled(:str?)
|
210
|
+
required(:paymentMethod).filled(:str?)
|
211
|
+
required(:paymentMethodDetails).filled(:hash).schema(PaymentMethodDetailsContract.schema)
|
212
|
+
end
|
213
|
+
rule(:messageExpiration).validate(:integer_string?)
|
214
|
+
rule(:paymentMethod) do
|
215
|
+
key.failure('must be equal to CARD') unless 'CARD'.eql?(value)
|
216
|
+
end
|
141
217
|
end
|
142
218
|
|
219
|
+
EncryptedMessageSchema = EncryptedMessageContract.new
|
220
|
+
|
143
221
|
module InstanceMethods
|
144
222
|
attr_reader :output
|
145
223
|
|
146
224
|
def validate
|
147
225
|
@validation ||= @schema.call(@input)
|
148
|
-
@output = @validation.
|
226
|
+
@output = @validation.to_h
|
149
227
|
return true if @validation.success?
|
150
228
|
raise Aliquot::ValidationError, "validation error(s), #{errors_formatted}"
|
151
229
|
end
|
@@ -176,7 +254,9 @@ module Aliquot
|
|
176
254
|
# Class for validating a Google Pay token
|
177
255
|
class Token
|
178
256
|
include InstanceMethods
|
257
|
+
|
179
258
|
class Error < ::Aliquot::Error; end
|
259
|
+
|
180
260
|
def initialize(input)
|
181
261
|
@input = input
|
182
262
|
@schema = TokenSchema
|
@@ -186,7 +266,9 @@ module Aliquot
|
|
186
266
|
# Class for validating the SignedMessage component of a Google Pay token
|
187
267
|
class SignedMessage
|
188
268
|
include InstanceMethods
|
269
|
+
|
189
270
|
class Error < ::Aliquot::Error; end
|
271
|
+
|
190
272
|
def initialize(input)
|
191
273
|
@input = input
|
192
274
|
@schema = SignedMessageSchema
|
@@ -196,7 +278,9 @@ module Aliquot
|
|
196
278
|
# Class for validating the encryptedMessage component of a Google Pay token
|
197
279
|
class EncryptedMessageValidator
|
198
280
|
include InstanceMethods
|
281
|
+
|
199
282
|
class Error < ::Aliquot::Error; end
|
283
|
+
|
200
284
|
def initialize(input)
|
201
285
|
@input = input
|
202
286
|
@schema = EncryptedMessageSchema
|
@@ -205,7 +289,9 @@ module Aliquot
|
|
205
289
|
|
206
290
|
class SignedKeyValidator
|
207
291
|
include InstanceMethods
|
292
|
+
|
208
293
|
class Error < ::Aliquot::Error; end
|
294
|
+
|
209
295
|
def initialize(input)
|
210
296
|
@input = input
|
211
297
|
@schema = SignedKeySchema
|
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: 1.
|
4
|
+
version: 2.1.2
|
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: 2022-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-validation
|
@@ -16,56 +16,56 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '1.8'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '1.8'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: excon
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.71.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.71.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: hkdf
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
47
|
+
version: '0.3'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
54
|
+
version: '0.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: aliquot-pay
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 1.
|
61
|
+
version: 2.1.1
|
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: 1.
|
68
|
+
version: 2.1.1
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '3'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.14.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.14.1
|
83
97
|
description:
|
84
98
|
email: hello@clearhaus.com
|
85
99
|
executables: []
|
@@ -100,16 +114,16 @@ require_paths:
|
|
100
114
|
- lib
|
101
115
|
required_ruby_version: !ruby/object:Gem::Requirement
|
102
116
|
requirements:
|
103
|
-
- - "
|
117
|
+
- - "~>"
|
104
118
|
- !ruby/object:Gem::Version
|
105
|
-
version: '
|
119
|
+
version: '2.7'
|
106
120
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - ">="
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '0'
|
111
125
|
requirements: []
|
112
|
-
rubygems_version: 3.
|
126
|
+
rubygems_version: 3.1.6
|
113
127
|
signing_key:
|
114
128
|
specification_version: 4
|
115
129
|
summary: Validates Google Pay tokens
|