identisure-client 0.1.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 +7 -0
- data/LICENSE +19 -0
- data/README.md +105 -0
- data/lib/identisure/age_verification.rb +87 -0
- data/lib/identisure/bank_id_no.rb +219 -0
- data/lib/identisure/bank_id_se.rb +338 -0
- data/lib/identisure/callback.rb +15 -0
- data/lib/identisure/client.rb +77 -0
- data/lib/identisure/document.rb +31 -0
- data/lib/identisure/environment.rb +17 -0
- data/lib/identisure/error.rb +21 -0
- data/lib/identisure/freja.rb +224 -0
- data/lib/identisure/ftn.rb +168 -0
- data/lib/identisure/mit_id.rb +205 -0
- data/lib/identisure/poll_options.rb +12 -0
- data/lib/identisure/transport.rb +90 -0
- data/lib/identisure/version.rb +5 -0
- data/lib/identisure/vipps.rb +153 -0
- metadata +75 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Identisure
|
|
4
|
+
module BankIdSe
|
|
5
|
+
# --- Requests ---
|
|
6
|
+
|
|
7
|
+
class AuthRequest
|
|
8
|
+
attr_reader :ssn, :ip_address, :callback_url, :pin_required, :intent,
|
|
9
|
+
:org_number, :request_address, :ref_id
|
|
10
|
+
|
|
11
|
+
def initialize(ssn: nil, ip_address: nil, callback_url: nil, pin_required: nil,
|
|
12
|
+
intent: nil, org_number: nil, request_address: nil, ref_id: nil)
|
|
13
|
+
@ssn = ssn
|
|
14
|
+
@ip_address = ip_address
|
|
15
|
+
@callback_url = callback_url
|
|
16
|
+
@pin_required = pin_required
|
|
17
|
+
@intent = intent
|
|
18
|
+
@org_number = org_number
|
|
19
|
+
@request_address = request_address
|
|
20
|
+
@ref_id = ref_id
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_h
|
|
24
|
+
{
|
|
25
|
+
ssn: @ssn, ipAddress: @ip_address, callbackUrl: @callback_url,
|
|
26
|
+
pinRequired: @pin_required, intent: @intent, orgNumber: @org_number,
|
|
27
|
+
requestAddress: @request_address, refId: @ref_id
|
|
28
|
+
}.compact
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class PhoneAuthRequest
|
|
33
|
+
attr_reader :ssn, :call_initiator, :callback_url, :pin_required, :intent,
|
|
34
|
+
:org_number, :request_address, :ref_id
|
|
35
|
+
|
|
36
|
+
def initialize(ssn:, call_initiator:, callback_url: nil, pin_required: nil,
|
|
37
|
+
intent: nil, org_number: nil, request_address: nil, ref_id: nil)
|
|
38
|
+
@ssn = ssn
|
|
39
|
+
@call_initiator = call_initiator
|
|
40
|
+
@callback_url = callback_url
|
|
41
|
+
@pin_required = pin_required
|
|
42
|
+
@intent = intent
|
|
43
|
+
@org_number = org_number
|
|
44
|
+
@request_address = request_address
|
|
45
|
+
@ref_id = ref_id
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def to_h
|
|
49
|
+
{
|
|
50
|
+
ssn: @ssn, callInitiator: @call_initiator, callbackUrl: @callback_url,
|
|
51
|
+
pinRequired: @pin_required, intent: @intent, orgNumber: @org_number,
|
|
52
|
+
requestAddress: @request_address, refId: @ref_id
|
|
53
|
+
}.compact
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class SignRequest
|
|
58
|
+
attr_reader :text, :ssn, :ip_address, :callback_url, :pin_required, :digest,
|
|
59
|
+
:org_number, :request_address, :ref_id
|
|
60
|
+
|
|
61
|
+
def initialize(text:, ssn: nil, ip_address: nil, callback_url: nil, pin_required: nil,
|
|
62
|
+
digest: nil, org_number: nil, request_address: nil, ref_id: nil)
|
|
63
|
+
@text = text; @ssn = ssn; @ip_address = ip_address; @callback_url = callback_url
|
|
64
|
+
@pin_required = pin_required; @digest = digest; @org_number = org_number
|
|
65
|
+
@request_address = request_address; @ref_id = ref_id
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def to_h
|
|
69
|
+
{
|
|
70
|
+
text: @text, ssn: @ssn, ipAddress: @ip_address, callbackUrl: @callback_url,
|
|
71
|
+
pinRequired: @pin_required, digest: @digest, orgNumber: @org_number,
|
|
72
|
+
requestAddress: @request_address, refId: @ref_id
|
|
73
|
+
}.compact
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class PhoneSignRequest
|
|
78
|
+
attr_reader :ssn, :call_initiator, :text, :callback_url, :pin_required, :digest,
|
|
79
|
+
:org_number, :request_address, :ref_id
|
|
80
|
+
|
|
81
|
+
def initialize(ssn:, call_initiator:, text:, callback_url: nil, pin_required: nil,
|
|
82
|
+
digest: nil, org_number: nil, request_address: nil, ref_id: nil)
|
|
83
|
+
@ssn = ssn; @call_initiator = call_initiator; @text = text
|
|
84
|
+
@callback_url = callback_url; @pin_required = pin_required; @digest = digest
|
|
85
|
+
@org_number = org_number; @request_address = request_address; @ref_id = ref_id
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def to_h
|
|
89
|
+
{
|
|
90
|
+
ssn: @ssn, callInitiator: @call_initiator, text: @text,
|
|
91
|
+
callbackUrl: @callback_url, pinRequired: @pin_required, digest: @digest,
|
|
92
|
+
orgNumber: @org_number, requestAddress: @request_address, refId: @ref_id
|
|
93
|
+
}.compact
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
class VerifyRequest
|
|
98
|
+
attr_reader :qr_code
|
|
99
|
+
|
|
100
|
+
def initialize(qr_code:) = @qr_code = qr_code
|
|
101
|
+
def to_h = { qrCode: @qr_code }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
class VerifyResponse
|
|
105
|
+
attr_reader :ssn, :name, :given_name, :surname, :age, :verified_at
|
|
106
|
+
|
|
107
|
+
def initialize(ssn:, name:, given_name:, surname:, age: nil, verified_at: nil)
|
|
108
|
+
@ssn = ssn; @name = name; @given_name = given_name; @surname = surname
|
|
109
|
+
@age = age; @verified_at = verified_at
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def deconstruct_keys(_)
|
|
113
|
+
{ ssn: @ssn, name: @name, given_name: @given_name, surname: @surname,
|
|
114
|
+
age: @age, verified_at: @verified_at }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def self.from_json(d)
|
|
118
|
+
new(ssn: d['ssn'], name: d['name'], given_name: d['givenName'],
|
|
119
|
+
surname: d['surname'], age: d['age'], verified_at: d['verifiedAt'])
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# --- Status variants ---
|
|
124
|
+
|
|
125
|
+
class Pending
|
|
126
|
+
attr_reader :id, :ref_id, :auto_start_token, :qr_start_token, :qr_start_secret, :hint_code
|
|
127
|
+
|
|
128
|
+
def initialize(id:, ref_id: nil, auto_start_token: nil, qr_start_token: nil,
|
|
129
|
+
qr_start_secret: nil, hint_code: nil)
|
|
130
|
+
@id = id; @ref_id = ref_id; @auto_start_token = auto_start_token
|
|
131
|
+
@qr_start_token = qr_start_token; @qr_start_secret = qr_start_secret
|
|
132
|
+
@hint_code = hint_code
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def deconstruct_keys(_)
|
|
136
|
+
{ id: @id, ref_id: @ref_id, auto_start_token: @auto_start_token,
|
|
137
|
+
qr_start_token: @qr_start_token, qr_start_secret: @qr_start_secret,
|
|
138
|
+
hint_code: @hint_code }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def self.from_json(d)
|
|
142
|
+
new(id: d['id'], ref_id: d['refId'], auto_start_token: d['autoStartToken'],
|
|
143
|
+
qr_start_token: d['qrStartToken'], qr_start_secret: d['qrStartSecret'],
|
|
144
|
+
hint_code: d['hintCode'])
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
class PendingPhone
|
|
149
|
+
attr_reader :id, :ref_id, :hint_code
|
|
150
|
+
|
|
151
|
+
def initialize(id:, ref_id: nil, hint_code: nil)
|
|
152
|
+
@id = id; @ref_id = ref_id; @hint_code = hint_code
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def deconstruct_keys(_) = { id: @id, ref_id: @ref_id, hint_code: @hint_code }
|
|
156
|
+
|
|
157
|
+
def self.from_json(d)
|
|
158
|
+
new(id: d['id'], ref_id: d['refId'], hint_code: d['hintCode'])
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
class Device
|
|
163
|
+
attr_reader :ip_address, :uhi
|
|
164
|
+
|
|
165
|
+
def initialize(ip_address: nil, uhi: nil)
|
|
166
|
+
@ip_address = ip_address; @uhi = uhi
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def deconstruct_keys(_) = { ip_address: @ip_address, uhi: @uhi }
|
|
170
|
+
|
|
171
|
+
def self.from_json(d) = new(ip_address: d['ipAddress'], uhi: d['uhi'])
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
class StepUp
|
|
175
|
+
attr_reader :mrtd, :face
|
|
176
|
+
|
|
177
|
+
def initialize(mrtd: nil, face: nil)
|
|
178
|
+
@mrtd = mrtd; @face = face
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def deconstruct_keys(_) = { mrtd: @mrtd, face: @face }
|
|
182
|
+
|
|
183
|
+
def self.from_json(d) = new(mrtd: d['mrtd'], face: d['face'])
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
class Completed
|
|
187
|
+
attr_reader :id, :ref_id, :ssn, :name, :given_name, :surname,
|
|
188
|
+
:cert_start_date, :ocsp_response, :risk, :device, :step_up,
|
|
189
|
+
:address, :company_signatory_text,
|
|
190
|
+
:authenticated_at, :signed_at
|
|
191
|
+
|
|
192
|
+
def initialize(id:, ssn:, name:, given_name:, surname:, ocsp_response:,
|
|
193
|
+
ref_id: nil, cert_start_date: nil, risk: nil, device: nil, step_up: nil,
|
|
194
|
+
address: nil, company_signatory_text: nil,
|
|
195
|
+
authenticated_at: nil, signed_at: nil)
|
|
196
|
+
@id = id; @ref_id = ref_id; @ssn = ssn; @name = name
|
|
197
|
+
@given_name = given_name; @surname = surname
|
|
198
|
+
@cert_start_date = cert_start_date; @ocsp_response = ocsp_response
|
|
199
|
+
@risk = risk; @device = device; @step_up = step_up; @address = address
|
|
200
|
+
@company_signatory_text = company_signatory_text
|
|
201
|
+
@authenticated_at = authenticated_at; @signed_at = signed_at
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def deconstruct_keys(_)
|
|
205
|
+
{ id: @id, ref_id: @ref_id, ssn: @ssn, name: @name, given_name: @given_name,
|
|
206
|
+
surname: @surname, cert_start_date: @cert_start_date,
|
|
207
|
+
ocsp_response: @ocsp_response, risk: @risk, device: @device, step_up: @step_up,
|
|
208
|
+
address: @address,
|
|
209
|
+
company_signatory_text: @company_signatory_text,
|
|
210
|
+
authenticated_at: @authenticated_at, signed_at: @signed_at }
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def self.from_json(d)
|
|
214
|
+
new(id: d['id'], ref_id: d['refId'], ssn: d['ssn'], name: d['name'],
|
|
215
|
+
given_name: d['givenName'], surname: d['surname'],
|
|
216
|
+
cert_start_date: d['certStartDate'], ocsp_response: d['ocspResponse'],
|
|
217
|
+
risk: d['risk'],
|
|
218
|
+
device: d['device'] ? Device.from_json(d['device']) : nil,
|
|
219
|
+
step_up: d['stepUp'] ? StepUp.from_json(d['stepUp']) : nil,
|
|
220
|
+
address: d['address'],
|
|
221
|
+
company_signatory_text: d['companySignatoryText'],
|
|
222
|
+
authenticated_at: d['authenticatedAt'], signed_at: d['signedAt'])
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
class Failed
|
|
227
|
+
attr_reader :id, :ref_id, :error
|
|
228
|
+
|
|
229
|
+
def initialize(id:, error:, ref_id: nil)
|
|
230
|
+
@id = id; @ref_id = ref_id; @error = error
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def deconstruct_keys(_) = { id: @id, ref_id: @ref_id, error: @error }
|
|
234
|
+
|
|
235
|
+
def self.from_json(d) = new(id: d['id'], ref_id: d['refId'], error: d['error'])
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
class Unknown
|
|
239
|
+
attr_reader :status
|
|
240
|
+
|
|
241
|
+
def initialize(status:)
|
|
242
|
+
@status = status
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def deconstruct_keys(_) = { status: @status }
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
module Status
|
|
249
|
+
def self.from_json(d)
|
|
250
|
+
case d['status']
|
|
251
|
+
when 'PENDING' then Pending.from_json(d)
|
|
252
|
+
when 'COMPLETED' then Completed.from_json(d)
|
|
253
|
+
when 'FAILED' then Failed.from_json(d)
|
|
254
|
+
when String then Unknown.new(status: d['status'])
|
|
255
|
+
else raise IdentisureError.new(0, "Invalid bankid-se status: #{d['status'].inspect}")
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
module PhoneStatus
|
|
261
|
+
def self.from_json(d)
|
|
262
|
+
case d['status']
|
|
263
|
+
when 'PENDING' then PendingPhone.from_json(d)
|
|
264
|
+
when 'COMPLETED' then Completed.from_json(d)
|
|
265
|
+
when 'FAILED' then Failed.from_json(d)
|
|
266
|
+
when String then Unknown.new(status: d['status'])
|
|
267
|
+
else raise IdentisureError.new(0, "Invalid bankid-se phone status: #{d['status'].inspect}")
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# --- Endpoint ---
|
|
273
|
+
|
|
274
|
+
class Endpoint
|
|
275
|
+
# @api private
|
|
276
|
+
def initialize(transport)
|
|
277
|
+
@transport = transport
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def auth(req) = Status.from_json(@transport.post('/v3/bankid-se/auth', req.to_h))
|
|
281
|
+
def phone_auth(req) = PhoneStatus.from_json(@transport.post('/v3/bankid-se/phone/auth', req.to_h))
|
|
282
|
+
def sign(req) = Status.from_json(@transport.post('/v3/bankid-se/sign', req.to_h))
|
|
283
|
+
def phone_sign(req) = PhoneStatus.from_json(@transport.post('/v3/bankid-se/phone/sign', req.to_h))
|
|
284
|
+
def verify(req) = VerifyResponse.from_json(@transport.post('/v3/bankid-se/verify', req.to_h))
|
|
285
|
+
|
|
286
|
+
def age_verification(req)
|
|
287
|
+
Identisure::AgeVerification::Status.from_json(@transport.post('/v3/bankid-se/age-verification', req.to_h))
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def auth_status(id) = Status.from_json(@transport.get("/v3/bankid-se/auth/#{id}"))
|
|
291
|
+
def sign_status(id) = Status.from_json(@transport.get("/v3/bankid-se/sign/#{id}"))
|
|
292
|
+
|
|
293
|
+
def age_verification_status(id)
|
|
294
|
+
Identisure::AgeVerification::Status.from_json(@transport.get("/v3/bankid-se/age-verification/#{id}"))
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def cancel_auth(id) = @transport.delete("/v3/bankid-se/auth/#{id}")
|
|
298
|
+
def cancel_sign(id) = @transport.delete("/v3/bankid-se/sign/#{id}")
|
|
299
|
+
def cancel_age_verification(id) = @transport.delete("/v3/bankid-se/age-verification/#{id}")
|
|
300
|
+
|
|
301
|
+
def wait_for_auth(id, opts: PollOptions.new)
|
|
302
|
+
poll_status(opts) { auth_status(id) }
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def wait_for_sign(id, opts: PollOptions.new)
|
|
306
|
+
poll_status(opts) { sign_status(id) }
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def wait_for_age_verification(id, opts: PollOptions.new)
|
|
310
|
+
poll_age(opts) { age_verification_status(id) }
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
private
|
|
314
|
+
|
|
315
|
+
def poll_status(opts)
|
|
316
|
+
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + opts.timeout
|
|
317
|
+
loop do
|
|
318
|
+
status = yield
|
|
319
|
+
return status unless status.is_a?(Pending)
|
|
320
|
+
raise WaitError.new(timeout: true) if Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline
|
|
321
|
+
|
|
322
|
+
sleep opts.interval
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def poll_age(opts)
|
|
327
|
+
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + opts.timeout
|
|
328
|
+
loop do
|
|
329
|
+
status = yield
|
|
330
|
+
return status unless status.is_a?(Identisure::AgeVerification::Pending)
|
|
331
|
+
raise WaitError.new(timeout: true) if Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline
|
|
332
|
+
|
|
333
|
+
sleep opts.interval
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'openssl'
|
|
4
|
+
|
|
5
|
+
module Identisure
|
|
6
|
+
# Verifies the X-Signature-SHA256 header of a callback request. Pass the raw request body as
|
|
7
|
+
# received, before parsing it.
|
|
8
|
+
def self.verify_callback_signature(body, signature, secret)
|
|
9
|
+
expected = OpenSSL::HMAC.digest('SHA256', secret, body)
|
|
10
|
+
actual = signature.unpack1('m0')
|
|
11
|
+
actual.bytesize == expected.bytesize && OpenSSL.fixed_length_secure_compare(actual, expected)
|
|
12
|
+
rescue ArgumentError
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'faraday'
|
|
4
|
+
|
|
5
|
+
require_relative 'version'
|
|
6
|
+
require_relative 'environment'
|
|
7
|
+
require_relative 'poll_options'
|
|
8
|
+
require_relative 'error'
|
|
9
|
+
require_relative 'transport'
|
|
10
|
+
require_relative 'age_verification'
|
|
11
|
+
require_relative 'bank_id_se'
|
|
12
|
+
require_relative 'bank_id_no'
|
|
13
|
+
require_relative 'freja'
|
|
14
|
+
require_relative 'mit_id'
|
|
15
|
+
require_relative 'ftn'
|
|
16
|
+
require_relative 'vipps'
|
|
17
|
+
require_relative 'document'
|
|
18
|
+
require_relative 'callback'
|
|
19
|
+
|
|
20
|
+
module Identisure
|
|
21
|
+
class Client
|
|
22
|
+
# @api private
|
|
23
|
+
def initialize(transport)
|
|
24
|
+
@transport = transport
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def bank_id_se = BankIdSe::Endpoint.new(@transport)
|
|
28
|
+
def bank_id_no = BankIdNo::Endpoint.new(@transport)
|
|
29
|
+
def freja = Freja::Endpoint.new(@transport)
|
|
30
|
+
def mit_id = MitId::Endpoint.new(@transport)
|
|
31
|
+
def ftn = Ftn::Endpoint.new(@transport)
|
|
32
|
+
def vipps = Vipps::Endpoint.new(@transport)
|
|
33
|
+
def document = Document::Endpoint.new(@transport)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class ClientBuilder
|
|
37
|
+
def initialize(client_id, client_secret)
|
|
38
|
+
@client_id = client_id
|
|
39
|
+
@client_secret = client_secret
|
|
40
|
+
@environment = Environment::PRODUCTION
|
|
41
|
+
@base_url = nil
|
|
42
|
+
@http_client = nil
|
|
43
|
+
@timeout = 30
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def environment(env)
|
|
47
|
+
@environment = env
|
|
48
|
+
self
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def base_url(url)
|
|
52
|
+
@base_url = url
|
|
53
|
+
self
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def http_client(conn)
|
|
57
|
+
@http_client = conn
|
|
58
|
+
self
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Timeout in seconds for each HTTP request. Defaults to 30.
|
|
62
|
+
def timeout(seconds)
|
|
63
|
+
raise ArgumentError, 'Timeout must be positive' unless seconds.positive?
|
|
64
|
+
|
|
65
|
+
@timeout = seconds
|
|
66
|
+
self
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def build
|
|
70
|
+
base = @base_url || Environment.base_url(@environment)
|
|
71
|
+
conn = @http_client || Faraday.new
|
|
72
|
+
Client.new(Transport.new(conn, base, @client_id, @client_secret, @timeout))
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def inspect = "#<#{self.class.name} client_id=#{@client_id.inspect}>"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Identisure
|
|
4
|
+
module Document
|
|
5
|
+
class UploadResponse
|
|
6
|
+
attr_reader :id, :document_hash
|
|
7
|
+
|
|
8
|
+
def initialize(id:, document_hash:)
|
|
9
|
+
@id = id; @document_hash = document_hash
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def deconstruct_keys(_) = { id: @id, document_hash: @document_hash }
|
|
13
|
+
def self.from_json(d) = new(id: d['id'], document_hash: d['hash'])
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class Endpoint
|
|
17
|
+
# @api private
|
|
18
|
+
def initialize(transport)
|
|
19
|
+
@transport = transport
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def upload(data, filename, mime_type: 'application/pdf')
|
|
23
|
+
UploadResponse.from_json(@transport.post_multipart('/v3/document', data, filename, mime_type))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def download(id)
|
|
27
|
+
@transport.get_raw("/v3/document/#{id}")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Identisure
|
|
4
|
+
module Environment
|
|
5
|
+
PRODUCTION = :production
|
|
6
|
+
STAGING = :staging
|
|
7
|
+
|
|
8
|
+
BASE_URLS = {
|
|
9
|
+
PRODUCTION => 'https://api.idkollen.se',
|
|
10
|
+
STAGING => 'https://stgapi.idkollen.se',
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
def self.base_url(env)
|
|
14
|
+
BASE_URLS.fetch(env)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Identisure
|
|
4
|
+
class IdentisureError < StandardError
|
|
5
|
+
attr_reader :status_code
|
|
6
|
+
|
|
7
|
+
def initialize(status_code, message)
|
|
8
|
+
@status_code = status_code
|
|
9
|
+
super("identisure: #{status_code} #{message}")
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class WaitError < StandardError
|
|
14
|
+
attr_reader :timeout
|
|
15
|
+
|
|
16
|
+
def initialize(timeout:)
|
|
17
|
+
@timeout = timeout
|
|
18
|
+
super('Poll timed out')
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|