pedicel 0.1.0 → 1.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 74bf3607219c5927eb2c3409abb203f3e8db743ee8d7e264f10b5c801fc8fde3
4
- data.tar.gz: a1bc91e194a468eed00e996af0b149d784a801f3fa8608129696af26d1fc34bd
3
+ metadata.gz: 8effeb35a7193cf9470319b3666b17a7105e3abb94d404882ce5ca705feca4b3
4
+ data.tar.gz: 9586a185c9dd0c0ea2faeea433f938507391cc91c20e7000c1b1a60f47b70e52
5
5
  SHA512:
6
- metadata.gz: dd75b505a0eefefba6fa101e6fcd65e5274b495871a602f3f7b308df34a58ca9b10855b090344256658379c330e76a1658f002aa00e46c55bbe14f15c5f12087
7
- data.tar.gz: c3cf9f84d1e0fb73bfe0241a305c9bec64a5e75f84ea4c42a95303c88873de3eadd0890d511ca6a3cf45dfc20897b87ecb6981d74f70c5122d3342aa2a1df275
6
+ metadata.gz: f3ae4d8a50ec94b2f217a19c63aeeeeab150296d85b7716fe3b2ef2721839059eeb14c69e42c5f503f84f4662dec72e7b7e19292c40ccc2d7ef48eccf84a64fb
7
+ data.tar.gz: '091465c0bcdba0987a5cae1df961ae68f0c0f406278187072a9d7d980c2e20e51b419cd501924d96adfb4448917deaa5343465d69168d8fa0d80330ba1e23442'
data/lib/pedicel/ec.rb CHANGED
@@ -3,6 +3,8 @@ require 'pedicel/base'
3
3
  module Pedicel
4
4
  class EC < Base
5
5
  def ephemeral_public_key
6
+ @token[:header].transform_keys!(&:to_sym)
7
+
6
8
  Base64.decode64(@token[:header][:ephemeralPublicKey])
7
9
  end
8
10
 
@@ -1,4 +1,6 @@
1
- require 'dry-validation'
1
+ require 'dry/validation'
2
+ require 'dry/schema'
3
+ require 'dry/logic'
2
4
  require 'base64'
3
5
  require 'openssl'
4
6
 
@@ -8,140 +10,275 @@ module Pedicel
8
10
  # https://developer.apple.com/library/content/documentation/PassKit/Reference/PaymentTokenJSON/PaymentTokenJSON.html
9
11
  # This purposefully only does syntactic validation (as opposed to semantic).
10
12
  module Validator
13
+ CUSTOM_ERRORS = {
14
+ is_base64: 'must be Base64',
15
+ is_hex: 'must be hex',
16
+ is_pan: 'must be a pan',
17
+ is_yymmdd: 'must be formatted YYMMDD',
18
+ is_ec_public_key: 'must be an EC public key',
19
+ is_pkcs7_signature: 'must be a PKCS7 Signature',
20
+ is_eci: 'must be an ECI',
21
+ is_hex_sha256: 'must be a hex-encoded SHA-256',
22
+ is_base64_sha256: 'must be a Base64-encoded SHA-256',
23
+ is_iso4217_numeric: 'must be an ISO 4217 numeric code',
24
+ }.freeze
25
+
26
+ Dry::Validation.register_macro(:is_hex) do
27
+ if key?
28
+ unless /\A[a-f0-9]*\z/i.match?(value)
29
+ key.failure(CUSTOM_ERRORS[:is_hex])
30
+ end
31
+ end
32
+ end
11
33
 
12
- module Predicates
13
- include Dry::Logic::Predicates
14
-
15
- CUSTOM_PREDICATE_ERRORS = {
16
- base64?: 'must be Base64',
17
- hex?: 'must be hex',
18
- pan?: 'must be a pan',
19
- yymmdd?: 'must be formatted YYMMDD',
20
- ec_public_key?: 'must be an EC public key',
21
- pkcs7_signature?: 'must be a PKCS7 Signature',
22
- eci?: 'must be an ECI',
23
- hex_sha256?: 'must be a hex-encoded SHA-256',
24
- base64_sha256?: 'must be a Base64-encoded SHA-256',
25
- iso4217_numeric?: 'must be an ISO 4217 numeric code',
26
- }.freeze
34
+ Dry::Validation.register_macro(:is_hex_sha256) do
35
+ if key?
36
+ unless :is_hex && value.length == 64
37
+ key.failure(CUSTOM_ERRORS[:is_hex_sha256])
38
+ end
39
+ end
40
+ end
27
41
 
28
- # Support Ruby 2.3, but use the faster #match? when available.
29
- match_b = String.new.respond_to?(:match?) ? ->(s, re) { s.match?(re) } : ->(s, re) { !!(s =~ re) }
42
+ Dry::Validation.register_macro(:is_base64) do
43
+ if key?
44
+ unless /\A[=A-Za-z0-9+\/]*\z/.match?(value) &&
45
+ value.length.remainder(4).zero? &&
46
+ !/=[^$=]/.match?(value) &&
47
+ !/===/.match?(value)
48
+ key.failure(CUSTOM_ERRORS[:is_base64])
49
+ end
50
+ end
51
+ end
30
52
 
31
- predicate(:base64?) do |x|
32
- str?(x) &&
33
- match_b.(x, /\A[=A-Za-z0-9+\/]*\z/) && # allowable chars
34
- x.length.remainder(4).zero? && # multiple of 4
35
- !match_b.(x, /=[^$=]/) && # may only end with ='s
36
- !match_b.(x, /===/) # at most 2 ='s
53
+ Dry::Validation.register_macro(:is_base64_sha256) do
54
+ if key?
55
+ unless :is_base64 && Base64.decode64(value).length == 32
56
+ key.failure(CUSTOM_ERRORS[:is_base64_sha256])
57
+ end
37
58
  end
59
+ end
38
60
 
39
- # We should figure out how strict we should be. Hopefully we can discard
40
- # the above Base64? predicate and use the following simpler one:
41
- #predicate(:strict_base64?) { |x| !!Base64.strict_decode64(x) rescue false }
61
+ Dry::Validation.register_macro(:is_ec_public_key) do
62
+ if key?
63
+ ec = lambda {OpenSSL::PKey::EC.new(Base64.decode64(value)).check_key rescue false}.()
64
+ unless :is_base64 && ec
65
+ key.failure(CUSTOM_ERRORS[:is_ec_public_key])
66
+ end
67
+ end
68
+ end
42
69
 
43
- predicate(:base64_sha256?) { |x| base64?(x) && Base64.decode64(x).length == 32 }
70
+ Dry::Validation.register_macro(:is_pkcs7_signature) do
71
+ if key?
72
+ pkcs7 = lambda {!!OpenSSL::PKCS7.new(Base64.decode64(value)) rescue false}.()
73
+ unless :is_base64 && pkcs7
74
+ key.failure(CUSTOM_ERRORS[:is_pkcs7_signature])
75
+ end
76
+ end
77
+ end
44
78
 
45
- predicate(:hex?) { |x| str?(x) && match_b.(x, /\A[a-f0-9]*\z/i) }
79
+ Dry::Validation.register_macro(:is_eci) do
80
+ if key?
81
+ unless /\A\d{1,2}\z/.match?(value)
82
+ key.failure(CUSTOM_ERRORS[:is_eci])
83
+ end
84
+ end
85
+ end
46
86
 
47
- predicate(:hex_sha256?) { |x| hex?(x) && x.length == 64 }
87
+ Dry::Validation.register_macro(:is_pan) do
88
+ if key?
89
+ unless /\A[1-9][0-9]{11,18}\z/.match?(value)
90
+ key.failure(CUSTOM_ERRORS[:is_pan])
91
+ end
92
+ end
93
+ end
48
94
 
49
- predicate(:pan?) { |x| str?(x) && match_b.(x, /\A[1-9][0-9]{11,18}\z/) }
95
+ Dry::Validation.register_macro(:is_yymmdd) do
96
+ if key?
97
+ unless /\A\d{6}\z/.match?(value)
98
+ key.failure(CUSTOM_ERRORS[:is_yymmdd])
99
+ end
100
+ end
101
+ end
50
102
 
51
- predicate(:yymmdd?) { |x| str?(x) && match_b.(x, /\A\d{6}\z/) }
103
+ Dry::Validation.register_macro(:is_iso4217_numeric) do
104
+ if key?
105
+ unless /\A[0-9]{3}\z/.match?(value.rjust(3, "0"))
106
+ key.failure(CUSTOM_ERRORS[:is_iso4217_numeric])
107
+ end
108
+ end
109
+ end
52
110
 
53
- predicate(:eci?) { |x| str?(x) && match_b.(x, /\A\d{1,2}\z/) }
111
+ class TokenHeaderContract < Dry::Validation::Contract
112
+ json do
113
+ optional(:applicationData).filled(:str?)
54
114
 
55
- predicate(:ec_public_key?) { |x| base64?(x) && OpenSSL::PKey::EC.new(Base64.decode64(x)).check_key rescue false }
115
+ optional(:ephemeralPublicKey).filled(:str?)
56
116
 
57
- predicate(:pkcs7_signature?) { |x| base64?(x) && !!OpenSSL::PKCS7.new(Base64.decode64(x)) rescue false }
117
+ optional(:wrappedKey).filled(:str?)
58
118
 
59
- predicate(:iso4217_numeric?) { |x| match_b.(x, /\A[0-9]{3}\z/) }
60
- end
61
119
 
62
- class BaseSchema < Dry::Validation::Schema::JSON
63
- predicates(Predicates)
64
- def self.messages
65
- super.merge(en: { errors: Predicates::CUSTOM_PREDICATE_ERRORS })
120
+ required(:publicKeyHash).filled(:str?)
121
+ required(:transactionId).filled(:str?)
122
+ end
123
+ rule(:applicationData).validate(:is_hex, :is_hex_sha256)
124
+
125
+ rule(:ephemeralPublicKey).validate(:is_base64, :is_ec_public_key)
126
+ rule(:publicKeyHash).validate(:is_base64, :is_base64_sha256)
127
+ rule(:wrappedKey).validate(:is_base64)
128
+ rule(:transactionId).validate(:is_hex)
129
+ rule(:ephemeralPublicKey, :wrappedKey) do
130
+ key.failure('ephemeralPublicKey xor wrappedKey') unless values[:ephemeralPublicKey].nil? ^ values[:wrappedKey].nil?
66
131
  end
67
132
  end
68
133
 
69
- TokenHeaderSchema = Dry::Validation.Schema(BaseSchema) do
70
- optional(:applicationData).filled(:str?, :hex?, :hex_sha256?)
134
+ TokenHeaderSchema = TokenHeaderContract.new
71
135
 
72
- optional(:ephemeralPublicKey).filled(:str?, :base64?, :ec_public_key?)
136
+ class TokenContract < Dry::Validation::Contract
137
+ json do
138
+ required(:data).filled(:str?)
73
139
 
74
- optional(:wrappedKey).filled(:str?, :base64?)
140
+ required(:header).hash(TokenHeaderContract.schema)
75
141
 
76
- rule('ephemeralPublicKey xor wrappedKey': [:ephemeralPublicKey, :wrappedKey]) do |e, w|
77
- e.filled? ^ w.filled?
78
- end
142
+ required(:signature).filled(:str?)
79
143
 
80
- required(:publicKeyHash).filled(:str?, :base64?, :base64_sha256?)
144
+ required(:version).filled(:str?, included_in?: %w[EC_v1 RSA_v1])
81
145
 
82
- required(:transactionId).filled(:str?, :hex?)
146
+ end
147
+ rule(:data).validate(:is_base64)
148
+ rule(:signature).validate(:is_base64, :is_pkcs7_signature)
83
149
  end
84
150
 
85
- TokenSchema = Dry::Validation.Schema(BaseSchema) do
86
- required(:data).filled(:str?, :base64?)
151
+ TokenSchema = TokenContract.new
87
152
 
88
- required(:header).schema(TokenHeaderSchema)
153
+ class TokenDataPaymentDataContract < Dry::Validation::Contract
154
+ json do
155
+ optional(:onlinePaymentCryptogram).filled(:str?)
156
+ optional(:eciIndicator).filled(:str?)
89
157
 
90
- required(:signature).filled(:str?, :base64?, :pkcs7_signature?)
158
+ optional(:emvData).filled(:str?)
159
+ optional(:encryptedPINData).filled(:str?)
160
+ end
161
+ rule(:onlinePaymentCryptogram).validate(:is_base64)
162
+ rule(:eciIndicator).validate(:is_eci)
91
163
 
92
- required(:version).filled(:str?, included_in?: %w[EC_v1 RSA_v1])
164
+ rule(:emvData).validate(:is_base64)
165
+ rule(:encryptedPINData).validate(:is_hex)
93
166
  end
94
167
 
95
- TokenDataPaymentDataSchema = Dry::Validation.Schema(BaseSchema) do
96
- optional(:onlinePaymentCryptogram).filled(:str?, :base64?)
97
- optional(:eciIndicator).filled(:str?, :eci?)
168
+ TokenDataPaymentDataSchema = TokenDataPaymentDataContract.new
98
169
 
99
- optional(:emvData).filled(:str?, :base64?)
100
- optional(:encryptedPINData).filled(:str?, :hex?)
101
- end
170
+ class TokenDataContract < Dry::Validation::Contract
171
+ json do
172
+ required(:applicationPrimaryAccountNumber).filled(:str?)
173
+
174
+ required(:applicationExpirationDate).filled(:str?)
102
175
 
103
- TokenDataSchema = Dry::Validation.Schema(BaseSchema) do
104
- required(:applicationPrimaryAccountNumber).filled(:str?, :pan?)
176
+ required(:currencyCode).filled(:str?)
105
177
 
106
- required(:applicationExpirationDate).filled(:str?, :yymmdd?)
178
+ required(:transactionAmount).filled(:int?)
107
179
 
108
- required(:currencyCode).filled(:str?, :iso4217_numeric?)
180
+ optional(:cardholderName).filled(:str?)
109
181
 
110
- required(:transactionAmount).filled(:int?)
182
+ required(:deviceManufacturerIdentifier).filled(:str?)
111
183
 
112
- optional(:cardholderName).filled(:str?)
184
+ required(:paymentDataType).filled(:str?, included_in?: %w[3DSecure EMV])
113
185
 
114
- required(:deviceManufacturerIdentifier).filled(:str?, :hex?)
186
+ required(:paymentData).hash(TokenDataPaymentDataContract.schema)
187
+ end
188
+ rule(:applicationPrimaryAccountNumber).validate(:is_pan)
115
189
 
116
- required(:paymentDataType).filled(:str?, included_in?: %w[3DSecure EMV])
190
+ rule(:applicationExpirationDate).validate(:is_yymmdd)
117
191
 
118
- required(:paymentData).schema(TokenDataPaymentDataSchema)
192
+ rule(:currencyCode).validate(:is_iso4217_numeric)
119
193
 
120
- rule('when paymentDataType is 3DSecure, onlinePaymentCryptogram': [:paymentDataType, [:paymentData, :onlinePaymentCryptogram]]) do |type, cryptogram|
121
- type.eql?('3DSecure') > cryptogram.filled?
122
- end
123
- rule('when paymentDataType is 3DSecure, emvData': [:paymentDataType, [:paymentData, :emvData]]) do |type, emv|
124
- type.eql?('3DSecure') > emv.none?
194
+ rule(:deviceManufacturerIdentifier).validate(:is_hex)
195
+
196
+ rule(:paymentDataType, paymentData: :onlinePaymentCryptogram) do
197
+ # rule('when paymentDataType is 3DSecure, onlinePaymentCryptogram': [:paymentDataType, [:paymentData, :onlinePaymentCryptogram]]) do |type, cryptogram|
198
+ # type can only be 3DSecure if cryptogram is filled
199
+ # type.eql?('3DSecure') > cryptogram.filled?
200
+ # end
201
+ if values[:paymentDataType].eql?('3DSecure')
202
+ key.failure('when paymentDataType is 3DSecure, onlinePaymentCryptogram must be filled') unless
203
+ values[:paymentData] && values[:paymentData][:onlinePaymentCryptogram]
204
+ end
125
205
  end
126
- rule('when paymentDataType is 3DSecure, encryptedPINData': [:paymentDataType, [:paymentData, :encryptedPINData]]) do |type, pin|
127
- type.eql?('3DSecure') > pin.none?
206
+
207
+ rule(:paymentDataType, paymentData: :emvData) do
208
+ # type can only be 3DSecure if emvData is empty
209
+ # old rule:
210
+ # rule('when paymentDataType is 3DSecure, emvData': [:paymentDataType, [:paymentData, :emvData]]) do |type, emv|
211
+ # type.eql?('3DSecure') > emv.none?
212
+ # end
213
+ if values[:paymentDataType].eql?('3DSecure')
214
+ key.failure('when paymentDataType is 3DSecure, emvData cannot be defined') unless
215
+ values[:paymentData] && values[:paymentData][:emvData].nil?
216
+ end
128
217
  end
129
218
 
130
- rule('when paymentDataType is EMV, onlinePaymentCryptogram': [:paymentDataType, [:paymentData, :onlinePaymentCryptogram]]) do |type, cryptogram|
131
- type.eql?('EMV') > cryptogram.none?
219
+ rule(:paymentDataType, paymentData: :encryptedPINData) do
220
+ # type can only be 3DSecure if emvData is empty
221
+ # old rule:
222
+ # rule('when paymentDataType is 3DSecure, encryptedPINData': [:paymentDataType, [:paymentData, :encryptedPINData]]) do |type, pin|
223
+ # type.eql?('3DSecure') > pin.none?
224
+ # end
225
+ if values[:paymentDataType].eql?('3DSecure')
226
+ key.failure('when paymentDataType is 3DSecure, encryptedPINData cannot be defined') unless
227
+ values[:paymentData] && values[:paymentData][:encryptedPINData].nil?
228
+ end
132
229
  end
133
- rule('when paymentDataType is EMV, eciIndicator': [:paymentDataType, [:paymentData, :eciIndicator]]) do |type, eci|
134
- type.eql?('EMV') > eci.none?
230
+
231
+ rule(:paymentDataType, paymentData: :onlinePaymentCryptogram) do
232
+ # type can only be 3DSecure if emvData is empty
233
+ # old rule:
234
+ # rule('when paymentDataType is EMV, onlinePaymentCryptogram': [:paymentDataType, [:paymentData, :onlinePaymentCryptogram]]) do |type, cryptogram|
235
+ # type.eql?('EMV') > cryptogram.none?
236
+ # end
237
+ if values[:paymentDataType].eql?('EMV')
238
+ key.failure('when paymentDataType is EMV, onlinePaymentCryptogram cannot be defined') unless
239
+ values[:paymentData] && values[:paymentData][:onlinePaymentCryptogram].nil?
240
+ end
135
241
  end
136
- rule('when paymentDataType is EMV, emvData': [:paymentDataType, [:paymentData, :emvData]]) do |type, emv|
137
- type.eql?('EMV') > emv.filled?
242
+
243
+ rule(:paymentDataType, paymentData: :eciIndicator) do
244
+ # type can only be 3DSecure if emvData is empty
245
+ # old rule:
246
+ # rule('when paymentDataType is EMV, eciIndicator': [:paymentDataType, [:paymentData, :eciIndicator]]) do |type, eci|
247
+ # type.eql?('EMV') > eci.none?
248
+ # end
249
+ if values[:paymentDataType].eql?('EMV')
250
+ key.failure('when paymentDataType is EMV, eciIndicator cannot be defined') unless
251
+ values[:paymentData] && values[:paymentData][:eciIndicator].nil?
252
+ end
138
253
  end
139
- rule('when paymentDataType is EMV, encryptedPINData': [:paymentDataType, [:paymentData, :encryptedPINData]]) do |type, pin|
140
- type.eql?('EMV') > pin.filled?
254
+
255
+ rule(:paymentDataType, paymentData: :emvData) do
256
+ # type can only be 3DSecure if emvData is empty
257
+ # old rule:
258
+ # rule('when paymentDataType is EMV, emvData': [:paymentDataType, [:paymentData, :emvData]]) do |type, emv|
259
+ # type.eql?('EMV') > emv.filled?
260
+ # end
261
+ if values[:paymentDataType].eql?('EMV')
262
+ key.failure('when paymentDataType is EMV, emvData must be filled') unless
263
+ values[:paymentData] && values[:paymentData][:emvData]
264
+ end
141
265
  end
142
266
 
267
+ rule(:paymentDataType, paymentData: :encryptedPINData) do
268
+ # type can only be 3DSecure if emvData is empty
269
+ # old rule:
270
+ # rule('when paymentDataType is EMV, encryptedPINData': [:paymentDataType, [:paymentData, :encryptedPINData]]) do |type, pin|
271
+ # type.eql?('EMV') > pin.filled?
272
+ # end
273
+ if values[:paymentDataType].eql?('EMV')
274
+ key.failure('when paymentDataType is EMV, encryptedPINData must be filled') unless
275
+ values[:paymentData] && values[:paymentData][:encryptedPINData]
276
+ end
277
+ end
143
278
  end
144
279
 
280
+ TokenDataSchema = TokenDataContract.new
281
+
145
282
  class Error < StandardError; end
146
283
 
147
284
  module InstanceMethods
@@ -150,11 +287,11 @@ module Pedicel
150
287
  def validate
151
288
  @validation ||= @schema.call(@input)
152
289
 
153
- @output = @validation.output
290
+ @output = @validation.to_h
154
291
 
155
292
  return true if @validation.success?
156
293
 
157
- raise Error, "validation error: #{@validation.errors.keys.join(', ')}"
294
+ raise Error, "validation error: #{@validation.errors.to_h.keys.join(', ')}"
158
295
  end
159
296
 
160
297
  def valid?
@@ -166,7 +303,7 @@ module Pedicel
166
303
  def errors
167
304
  valid? unless @validation
168
305
 
169
- @validation.errors
306
+ @validation.errors.to_h.sort
170
307
  end
171
308
 
172
309
  def errors_formatted(node = [errors])
@@ -1,3 +1,3 @@
1
1
  module Pedicel
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '1.0.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,29 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pedicel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clearhaus
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-17 00:00:00.000000000 Z
11
+ date: 2023-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-validation
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: '1.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dry-schema
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: 0.11.1
33
+ version: '1.9'
20
34
  type: :runtime
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: 0.11.1
40
+ version: '1.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dry-logic
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: rake
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +94,20 @@ dependencies:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
96
  version: '0.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.0'
69
111
  description:
70
112
  email: hello@clearhaus.com
71
113
  executables: []
@@ -90,14 +132,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
90
132
  requirements:
91
133
  - - "~>"
92
134
  - !ruby/object:Gem::Version
93
- version: 2.5.5
135
+ version: 2.7.4
94
136
  required_rubygems_version: !ruby/object:Gem::Requirement
95
137
  requirements:
96
138
  - - ">="
97
139
  - !ruby/object:Gem::Version
98
140
  version: '0'
99
141
  requirements: []
100
- rubygems_version: 3.0.8
142
+ rubygems_version: 3.1.6
101
143
  signing_key:
102
144
  specification_version: 4
103
145
  summary: Decryption of Apple Pay payment tokens