smile-identity-core 1.0.1 → 1.2.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 +4 -4
- data/.travis.yml +5 -1
- data/CHANGELOG.md +3 -0
- data/Gemfile.lock +5 -5
- data/README.md +74 -29
- data/lib/smile-identity-core/id_api.rb +42 -34
- data/lib/smile-identity-core/signature.rb +19 -3
- data/lib/smile-identity-core/utilities.rb +39 -21
- data/lib/smile-identity-core/version.rb +1 -1
- data/lib/smile-identity-core/web_api.rb +99 -67
- data/smile-identity-core.gemspec +2 -2
- metadata +8 -10
- data/travis.yml +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e90f488e56f0f23468d8ce70a6190d7f343b6f626f3383e5909b0f2bede5e89
|
4
|
+
data.tar.gz: 2b53062431bd66ac011e1fde789c16fe501b565297b33324101153aa550da364
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89338028a53553ddf63d7b004437b9305e6fc301578e7646888b6bf89557be2bbd5def9fce62cce7bbbc094c5e7bdc255a2ef9bf25f5a9732a06a7aa95ac3f44
|
7
|
+
data.tar.gz: efb84f0d05c9ce9df6b47126389cdc8dfa4245909b14fc396537b350e71b41c2e134a38462968432fffc85cff9c9a5347799d1eca07fb7c49253c5006deed9b1
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -44,3 +44,6 @@ Update the documentation
|
|
44
44
|
## Updated
|
45
45
|
Remove first_name and last_name validations from id information in Web Api
|
46
46
|
Add country, id_number and id_type validations for id information in ID Api
|
47
|
+
|
48
|
+
## [1.0.2] - 2020-01-16
|
49
|
+
Add {"success":true,"smile_job_id":"job_id"} to the response when we poll job status too
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
smile-identity-core (1.
|
4
|
+
smile-identity-core (1.2.1)
|
5
5
|
rubyzip (~> 1.2, >= 1.2.3)
|
6
6
|
typhoeus (~> 1.0, >= 1.0.1)
|
7
7
|
|
@@ -12,8 +12,8 @@ GEM
|
|
12
12
|
docile (1.1.5)
|
13
13
|
ethon (0.12.0)
|
14
14
|
ffi (>= 1.3.0)
|
15
|
-
ffi (1.
|
16
|
-
json (2.
|
15
|
+
ffi (1.13.1)
|
16
|
+
json (2.5.1)
|
17
17
|
rake (10.5.0)
|
18
18
|
rspec (3.8.0)
|
19
19
|
rspec-core (~> 3.8.0)
|
@@ -34,7 +34,7 @@ GEM
|
|
34
34
|
json (>= 1.8, < 3)
|
35
35
|
simplecov-html (~> 0.10.0)
|
36
36
|
simplecov-html (0.10.2)
|
37
|
-
typhoeus (1.
|
37
|
+
typhoeus (1.4.0)
|
38
38
|
ethon (>= 0.9.0)
|
39
39
|
|
40
40
|
PLATFORMS
|
@@ -48,4 +48,4 @@ DEPENDENCIES
|
|
48
48
|
smile-identity-core!
|
49
49
|
|
50
50
|
BUNDLED WITH
|
51
|
-
2.
|
51
|
+
2.2.6
|
data/README.md
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
# SmileIdentityCore
|
1
|
+
# SmileIdentityCore [](https://travis-ci.com/smileidentity/smile-identity-core-ruby)
|
2
2
|
|
3
|
-
The official Smile Identity gem exposes
|
3
|
+
The official Smile Identity gem exposes four classes namely; the Web Api class, the ID Api class, the Signature class and the Utilities class.
|
4
4
|
|
5
|
-
The **Web
|
5
|
+
The **Web Api Class** allows you as the Partner to validate a user’s identity against the relevant Identity Authorities/Third Party databases that Smile Identity has access to using ID information provided by your customer/user (including photo for compare). It has the following public methods:
|
6
6
|
- submit_job
|
7
7
|
- get_job_status
|
8
|
+
- get_web_token
|
8
9
|
|
9
|
-
The **ID Class** lets you performs basic KYC Services including verifying an ID number as well as retrieve a user's Personal Information. It has the following public methods:
|
10
|
+
The **ID Api Class** lets you performs basic KYC Services including verifying an ID number as well as retrieve a user's Personal Information. It has the following public methods:
|
10
11
|
- submit_job
|
11
12
|
|
12
13
|
The **Signature Class** allows you as the Partner to generate a sec key to interact with our servers. It has the following public methods:
|
@@ -20,7 +21,7 @@ The **Utilities Class** allows you as the Partner to have access to our general
|
|
20
21
|
|
21
22
|
This gem requires specific input parameters, for more detail on these parameters please refer to our [documentation for Web API](https://docs.smileidentity.com).
|
22
23
|
|
23
|
-
Please note that you will have to be a Smile Identity Partner to be able to query our services. You can sign up on the [Portal](https://
|
24
|
+
Please note that you will have to be a Smile Identity Partner to be able to query our services. You can sign up on the [Portal](https://portal.smileidentity.com/signup).
|
24
25
|
|
25
26
|
## Installation
|
26
27
|
|
@@ -39,7 +40,7 @@ require 'smile-identity-core'
|
|
39
40
|
|
40
41
|
Or install it to your system as:
|
41
42
|
|
42
|
-
```
|
43
|
+
```sh
|
43
44
|
$ gem install smile-identity-core
|
44
45
|
```
|
45
46
|
|
@@ -48,33 +49,33 @@ You now may use the classes as follows:
|
|
48
49
|
#### Web Api Class
|
49
50
|
|
50
51
|
##### submit_job method
|
51
|
-
```
|
52
|
-
|
52
|
+
```ruby
|
53
|
+
connection = SmileIdentityCore::WebApi.new(partner_id, default_callback, api_key, sid_server)
|
53
54
|
|
54
|
-
|
55
|
+
response = connection.submit_job(partner_params, images, id_info, options)
|
55
56
|
```
|
56
57
|
|
57
58
|
Please note that if you do not need to pass through id_info or options, you may omit calling those class and send through nil in submit_job, as follows:
|
58
59
|
|
59
|
-
```
|
60
|
-
|
60
|
+
```ruby
|
61
|
+
response = connection.submit_job(partner_params, images, nil, nil);
|
61
62
|
```
|
62
63
|
|
63
64
|
In the case of a Job Type 5 you can simply omit the the images and options keys. Remember that the response is immediate, so there is no need to query the job_status. There is also no enrollment so no images are required. The response for a job type 5 can be found in the response section below.
|
64
65
|
|
65
|
-
```
|
66
|
-
|
66
|
+
```ruby
|
67
|
+
response = connection.submit_job(partner_params, nil, id_info, nil);
|
67
68
|
```
|
68
69
|
|
69
70
|
**Response:**
|
70
71
|
|
71
72
|
Should you choose to *set return_job_status to false*, the response will be a JSON String containing:
|
72
|
-
```
|
73
|
+
```ruby
|
73
74
|
{success: true, smile_job_id: smile_job_id}
|
74
75
|
```
|
75
76
|
|
76
77
|
However, if you have *set return_job_status to true (with image_links and history)* then you will receive JSON Object response like below:
|
77
|
-
```
|
78
|
+
```json
|
78
79
|
{
|
79
80
|
"job_success":true,
|
80
81
|
"result":{
|
@@ -150,7 +151,7 @@ However, if you have *set return_job_status to true (with image_links and histor
|
|
150
151
|
```
|
151
152
|
|
152
153
|
You can also *view your response asynchronously at the callback* that you have set, it will look as follows:
|
153
|
-
```
|
154
|
+
```json
|
154
155
|
{
|
155
156
|
"job_success":true,
|
156
157
|
"result":{
|
@@ -226,7 +227,7 @@ You can also *view your response asynchronously at the callback* that you have s
|
|
226
227
|
```
|
227
228
|
|
228
229
|
If you have queried a job type 5, your response be a JSON String that will contain the following:
|
229
|
-
```
|
230
|
+
```json
|
230
231
|
{
|
231
232
|
"JSONVersion":"1.0.0",
|
232
233
|
"SmileJobID":"0000001105",
|
@@ -279,7 +280,7 @@ response = connection.get_job_status(partner_params, nil);
|
|
279
280
|
|
280
281
|
Your response will return a JSON Object below with image_links and history included:
|
281
282
|
|
282
|
-
```
|
283
|
+
```json
|
283
284
|
{
|
284
285
|
"job_success":true,
|
285
286
|
"result":{
|
@@ -354,20 +355,54 @@ Your response will return a JSON Object below with image_links and history inclu
|
|
354
355
|
}
|
355
356
|
```
|
356
357
|
|
358
|
+
##### get_web_token method
|
359
|
+
You may want to use our hosted web integration, and create a session. The `get_web_token` method enables this.
|
360
|
+
You have your Web Api class initialised as follows:
|
361
|
+
```ruby
|
362
|
+
connection = SmileIdentityCore::WebApi.new(partner_id, default_callback, api_key, sid_server)
|
363
|
+
|
364
|
+
```
|
365
|
+
|
366
|
+
Next, you'll need to create your request params. This should take the following
|
367
|
+
structure:
|
368
|
+
|
369
|
+
```ruby
|
370
|
+
{
|
371
|
+
user_id: 'user-1', # String: required
|
372
|
+
job_id: 'job-1', # String: required
|
373
|
+
product: 'authentication', # String: required one of 'authentication', 'identity_verification', 'smartselfie', 'ekyc_smartselfie', 'enhanced_kyc', 'document_verification'
|
374
|
+
callback_url: "https://smileidentity.com/callback" # String: required, optional if callback url was set during instantiation of the class
|
375
|
+
}
|
376
|
+
```
|
377
|
+
|
378
|
+
Thereafter, call `get_web_token` with the correct parameters:
|
379
|
+
```ruby
|
380
|
+
response = connection.get_web_token(request_params)
|
381
|
+
```
|
382
|
+
|
383
|
+
**Response**
|
384
|
+
|
385
|
+
Your response will return a hash that contains
|
386
|
+
```ruby
|
387
|
+
{
|
388
|
+
token: <token_string>
|
389
|
+
}
|
390
|
+
```
|
391
|
+
|
357
392
|
#### ID Api Class
|
358
393
|
|
359
394
|
|
360
395
|
##### submit_job method
|
361
|
-
```
|
362
|
-
|
396
|
+
```ruby
|
397
|
+
connection = SmileIdentityCore::IDApi.new(partner_id, api_key, sid_server)
|
363
398
|
|
364
|
-
|
399
|
+
response = connection.submit_job(partner_params, id_info)
|
365
400
|
```
|
366
401
|
|
367
402
|
**Response**
|
368
403
|
|
369
404
|
Your response will return a JSON String containing the below:
|
370
|
-
```
|
405
|
+
```json
|
371
406
|
{
|
372
407
|
"JSONVersion":"1.0.0",
|
373
408
|
"SmileJobID":"0000001105",
|
@@ -400,17 +435,17 @@ Your response will return a JSON String containing the below:
|
|
400
435
|
|
401
436
|
##### generate_sec_key method
|
402
437
|
|
403
|
-
```
|
404
|
-
|
438
|
+
```ruby
|
439
|
+
connection = SmileIdentityCore::Signature.new(partner_id, api_key)
|
405
440
|
|
406
|
-
|
441
|
+
sec_key = connection.generate_sec_key(timestamp)
|
407
442
|
where timestamp is optional
|
408
443
|
|
409
444
|
```
|
410
445
|
|
411
446
|
The response will be a hash:
|
412
447
|
|
413
|
-
```
|
448
|
+
```ruby
|
414
449
|
{
|
415
450
|
:sec_key=> "<the generated sec key>",
|
416
451
|
:timestamp=> 1563283420
|
@@ -422,8 +457,8 @@ The response will be a hash:
|
|
422
457
|
You can also confirm the signature that you receive when you interacting with our servers, simply use the confirm_sec_key method which returns a boolean:
|
423
458
|
|
424
459
|
```ruby
|
425
|
-
|
426
|
-
|
460
|
+
connection = SmileIdentityCore::Signature.new(partner_id, api_key)
|
461
|
+
sec_key = connection.confirm_sec_key(sec_key, timestamp)
|
427
462
|
```
|
428
463
|
|
429
464
|
#### Utilities Class
|
@@ -443,13 +478,23 @@ After checking out the repo, run `bundle install` to install dependencies. Then,
|
|
443
478
|
|
444
479
|
To install this gem onto your local machine, run `bundle exec rake install`.
|
445
480
|
|
481
|
+
You can use `bundle console` and then call the necessary classes with their parameters.
|
482
|
+
|
483
|
+
## Testing
|
484
|
+
|
485
|
+
Run `bundle exec rspec` to run the tests.
|
486
|
+
After running your tests open the coverage/index.html to view the test coverage
|
487
|
+
|
488
|
+
## Deployment
|
489
|
+
|
446
490
|
To release a new version:
|
447
491
|
- Update the version number in `version.rb`
|
448
492
|
- Run `gem build smile-identity-core.gemspec`
|
449
|
-
- Thereafter `gem push smile-identity-core
|
493
|
+
- Thereafter `gem push smile-identity-core-<version>.gem`.
|
450
494
|
|
451
495
|
Make sure to git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
452
496
|
|
497
|
+
|
453
498
|
## Contributing
|
454
499
|
|
455
500
|
Bug reports and pull requests are welcome on GitHub at https://github.com/smileidentity/smile-identity-core
|
@@ -8,8 +8,8 @@ module SmileIdentityCore
|
|
8
8
|
@sid_server = sid_server
|
9
9
|
if !(sid_server =~ URI::regexp)
|
10
10
|
sid_server_mapping = {
|
11
|
-
0 => 'https://
|
12
|
-
1 => 'https://
|
11
|
+
0 => 'https://testapi.smileidentity.com/v1',
|
12
|
+
1 => 'https://api.smileidentity.com/v1',
|
13
13
|
}
|
14
14
|
@url = sid_server_mapping[sid_server.to_i]
|
15
15
|
else
|
@@ -17,32 +17,30 @@ module SmileIdentityCore
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def submit_job(partner_params, id_info)
|
20
|
+
def submit_job(partner_params, id_info, options = {})
|
21
21
|
self.partner_params = symbolize_keys partner_params
|
22
|
-
|
23
|
-
@timestamp = Time.now.to_i
|
24
|
-
|
25
22
|
self.id_info = symbolize_keys id_info
|
23
|
+
@use_new_signature = symbolize_keys(options || {}).fetch(:signature, false)
|
26
24
|
|
27
25
|
if @partner_params[:job_type].to_i != 5
|
28
|
-
raise ArgumentError
|
26
|
+
raise ArgumentError, 'Please ensure that you are setting your job_type to 5 to query ID Api'
|
29
27
|
end
|
30
28
|
|
31
|
-
|
29
|
+
setup_requests
|
32
30
|
end
|
33
31
|
|
34
32
|
def partner_params=(partner_params)
|
35
33
|
if partner_params == nil
|
36
|
-
raise ArgumentError
|
34
|
+
raise ArgumentError, 'Please ensure that you send through partner params'
|
37
35
|
end
|
38
36
|
|
39
37
|
if !partner_params.is_a?(Hash)
|
40
|
-
raise ArgumentError
|
38
|
+
raise ArgumentError, 'Partner params needs to be a hash'
|
41
39
|
end
|
42
40
|
|
43
41
|
[:user_id, :job_id, :job_type].each do |key|
|
44
42
|
unless partner_params[key] && !partner_params[key].nil? && !(partner_params[key].empty? if partner_params[key].is_a?(String))
|
45
|
-
raise ArgumentError
|
43
|
+
raise ArgumentError, "Please make sure that #{key} is included in the partner params"
|
46
44
|
end
|
47
45
|
end
|
48
46
|
|
@@ -54,12 +52,12 @@ module SmileIdentityCore
|
|
54
52
|
updated_id_info = id_info
|
55
53
|
|
56
54
|
if updated_id_info.nil? || updated_id_info.keys.length == 0
|
57
|
-
raise ArgumentError
|
55
|
+
raise ArgumentError, 'Please make sure that id_info not empty or nil'
|
58
56
|
end
|
59
57
|
|
60
58
|
[:country, :id_type, :id_number].each do |key|
|
61
59
|
unless updated_id_info[key] && !updated_id_info[key].nil? && !updated_id_info[key].empty?
|
62
|
-
raise ArgumentError
|
60
|
+
raise ArgumentError, "Please make sure that #{key} is included in the id_info"
|
63
61
|
end
|
64
62
|
end
|
65
63
|
|
@@ -83,36 +81,46 @@ module SmileIdentityCore
|
|
83
81
|
)
|
84
82
|
|
85
83
|
request.on_complete do |response|
|
86
|
-
if response.success?
|
87
|
-
|
88
|
-
|
89
|
-
raise "#{response.code.to_s}: #{response.body}"
|
90
|
-
elsif response.code == 0
|
91
|
-
# Could not get an http response, something's wrong.
|
92
|
-
raise "#{response.code.to_s}: #{response.body}"
|
93
|
-
else
|
94
|
-
# Received a non-successful http response.
|
95
|
-
raise "#{response.code.to_s}: #{response.body}"
|
96
|
-
end
|
84
|
+
return response.body if response.success?
|
85
|
+
|
86
|
+
raise "#{response.code}: #{response.body}"
|
97
87
|
end
|
98
88
|
request.run
|
99
89
|
end
|
100
90
|
|
101
91
|
def configure_json
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
92
|
+
request_security(use_new_signature: @use_new_signature)
|
93
|
+
.merge(@id_info)
|
94
|
+
.merge(
|
95
|
+
partner_id: @partner_id,
|
96
|
+
partner_params: @partner_params)
|
97
|
+
.to_json
|
98
|
+
end
|
108
99
|
|
109
|
-
|
110
|
-
|
100
|
+
def signature_generator
|
101
|
+
SmileIdentityCore::Signature.new(@partner_id, @api_key)
|
111
102
|
end
|
112
103
|
|
113
|
-
def
|
114
|
-
|
104
|
+
def signature(timestamp: Time.now.to_s)
|
105
|
+
signature = signature_generator.generate_signature(timestamp)[:signature]
|
106
|
+
{
|
107
|
+
signature: signature,
|
108
|
+
timestamp: timestamp
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def sec_key(timestamp: Time.now.to_s)
|
113
|
+
sec_key = signature_generator.generate_sec_key(timestamp)[:sec_key]
|
114
|
+
{
|
115
|
+
sec_key: sec_key,
|
116
|
+
timestamp: timestamp
|
117
|
+
}
|
115
118
|
end
|
116
119
|
|
120
|
+
def request_security(use_new_signature: true)
|
121
|
+
return signature if use_new_signature
|
122
|
+
|
123
|
+
sec_key
|
124
|
+
end
|
117
125
|
end
|
118
126
|
end
|
@@ -3,7 +3,7 @@ module SmileIdentityCore
|
|
3
3
|
|
4
4
|
def initialize(partner_id, api_key)
|
5
5
|
@api_key = api_key
|
6
|
-
@partner_id = partner_id
|
6
|
+
@partner_id = partner_id
|
7
7
|
end
|
8
8
|
|
9
9
|
def generate_sec_key(timestamp=Time.now.to_i)
|
@@ -14,7 +14,7 @@ module SmileIdentityCore
|
|
14
14
|
public_key = OpenSSL::PKey::RSA.new(Base64.decode64(@api_key))
|
15
15
|
@sec_key = [Base64.encode64(public_key.public_encrypt(hash_signature)), hash_signature].join('|')
|
16
16
|
|
17
|
-
|
17
|
+
{
|
18
18
|
sec_key: @sec_key,
|
19
19
|
timestamp: @timestamp
|
20
20
|
}
|
@@ -31,10 +31,26 @@ module SmileIdentityCore
|
|
31
31
|
public_key = OpenSSL::PKey::RSA.new(Base64.decode64(@api_key))
|
32
32
|
decrypted = public_key.public_decrypt(Base64.decode64(encrypted))
|
33
33
|
|
34
|
-
|
34
|
+
decrypted == hash_signature
|
35
35
|
rescue => e
|
36
36
|
raise e
|
37
37
|
end
|
38
38
|
end
|
39
|
+
|
40
|
+
def generate_signature(timestamp=Time.now.to_s)
|
41
|
+
hmac = OpenSSL::HMAC.new(@api_key, 'sha256')
|
42
|
+
hmac.update(timestamp.to_s)
|
43
|
+
hmac.update(@partner_id)
|
44
|
+
hmac.update("sid_request")
|
45
|
+
signature = Base64.strict_encode64(hmac.digest())
|
46
|
+
{
|
47
|
+
signature: signature,
|
48
|
+
timestamp: timestamp.to_s
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def confirm_signature(timestamp, msg_signature)
|
53
|
+
generate_signature(timestamp)[:signature] == msg_signature
|
54
|
+
end
|
39
55
|
end
|
40
56
|
end
|
@@ -7,8 +7,8 @@ module SmileIdentityCore
|
|
7
7
|
|
8
8
|
if !(sid_server =~ URI::regexp)
|
9
9
|
sid_server_mapping = {
|
10
|
-
0 => 'https://
|
11
|
-
1 => 'https://
|
10
|
+
0 => 'https://testapi.smileidentity.com/v1',
|
11
|
+
1 => 'https://api.smileidentity.com/v1',
|
12
12
|
}
|
13
13
|
@url = sid_server_mapping[sid_server.to_i]
|
14
14
|
else
|
@@ -20,16 +20,12 @@ module SmileIdentityCore
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def get_job_status(user_id, job_id, options = {})
|
23
|
+
options = symbolize_keys(options || {})
|
24
|
+
options[:return_history] ||= false
|
25
|
+
options[:return_image_links] ||= false
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
return_history: false,
|
27
|
-
return_job_status: false
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
@timestamp = Time.now.to_i
|
32
|
-
return query_job_status(user_id, job_id, symbolize_keys(options))
|
27
|
+
security = request_security(use_new_signature: options.fetch(:signature, false))
|
28
|
+
query_job_status(configure_job_query(user_id, job_id, options).merge(security))
|
33
29
|
end
|
34
30
|
|
35
31
|
private
|
@@ -38,21 +34,30 @@ module SmileIdentityCore
|
|
38
34
|
(params.is_a?(Hash)) ? Hash[params.map{ |k, v| [k.to_sym, v] }] : params
|
39
35
|
end
|
40
36
|
|
41
|
-
def query_job_status(
|
37
|
+
def query_job_status(request_json_data)
|
42
38
|
url = "#{@url}/job_status"
|
43
39
|
|
44
40
|
request = Typhoeus::Request.new(
|
45
41
|
url,
|
46
42
|
headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
|
47
43
|
method: :post,
|
48
|
-
body:
|
44
|
+
body: request_json_data.to_json
|
49
45
|
)
|
50
46
|
|
51
47
|
request.on_complete do |response|
|
52
48
|
begin
|
53
49
|
body = JSON.parse(response.body)
|
54
50
|
|
55
|
-
|
51
|
+
# NB: we have to trust that the server will return the right kind of
|
52
|
+
# timestamp (integer or string) for the signature, and the right kind
|
53
|
+
# of signature in the "signature" field. The best way to know what
|
54
|
+
# kind of validation to perform is by remembering which kind of
|
55
|
+
# security we started with.
|
56
|
+
if request_json_data.has_key?(:sec_key)
|
57
|
+
valid = @signature_connection.confirm_sec_key(body['timestamp'], body['signature'])
|
58
|
+
else
|
59
|
+
valid = @signature_connection.confirm_signature(body['timestamp'], body['signature'])
|
60
|
+
end
|
56
61
|
|
57
62
|
if(!valid)
|
58
63
|
raise "Unable to confirm validity of the job_status response"
|
@@ -67,17 +72,30 @@ module SmileIdentityCore
|
|
67
72
|
request.run
|
68
73
|
end
|
69
74
|
|
75
|
+
def request_security(use_new_signature: false)
|
76
|
+
if use_new_signature
|
77
|
+
@timestamp = Time.now.to_s
|
78
|
+
{
|
79
|
+
signature: @signature_connection.generate_signature(@timestamp)[:signature],
|
80
|
+
timestamp: @timestamp,
|
81
|
+
}
|
82
|
+
else
|
83
|
+
@timestamp = Time.now.to_i
|
84
|
+
{
|
85
|
+
sec_key: @signature_connection.generate_sec_key(@timestamp)[:sec_key],
|
86
|
+
timestamp: @timestamp,
|
87
|
+
}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
70
91
|
def configure_job_query(user_id, job_id, options)
|
71
|
-
|
72
|
-
sec_key: @signature_connection.generate_sec_key(@timestamp)[:sec_key],
|
73
|
-
timestamp: @timestamp,
|
92
|
+
{
|
74
93
|
user_id: user_id,
|
75
94
|
job_id: job_id,
|
76
95
|
partner_id: @partner_id,
|
77
|
-
image_links: options[:return_image_links]
|
78
|
-
history: options[:return_history]
|
79
|
-
}
|
96
|
+
image_links: options[:return_image_links],
|
97
|
+
history: options[:return_history]
|
98
|
+
}
|
80
99
|
end
|
81
|
-
|
82
100
|
end
|
83
101
|
end
|
@@ -18,8 +18,8 @@ module SmileIdentityCore
|
|
18
18
|
@sid_server = sid_server
|
19
19
|
if !(sid_server =~ URI::regexp)
|
20
20
|
sid_server_mapping = {
|
21
|
-
0 => 'https://
|
22
|
-
1 => 'https://
|
21
|
+
0 => 'https://testapi.smileidentity.com/v1',
|
22
|
+
1 => 'https://api.smileidentity.com/v1',
|
23
23
|
}
|
24
24
|
@url = sid_server_mapping[sid_server.to_i]
|
25
25
|
else
|
@@ -35,8 +35,6 @@ module SmileIdentityCore
|
|
35
35
|
end
|
36
36
|
|
37
37
|
self.images = images
|
38
|
-
@timestamp = Time.now.to_i
|
39
|
-
|
40
38
|
self.id_info = symbolize_keys id_info
|
41
39
|
self.options = symbolize_keys options
|
42
40
|
|
@@ -50,7 +48,7 @@ module SmileIdentityCore
|
|
50
48
|
|
51
49
|
validate_return_data
|
52
50
|
|
53
|
-
|
51
|
+
setup_requests
|
54
52
|
end
|
55
53
|
|
56
54
|
def get_job_status(partner_params, options)
|
@@ -61,21 +59,21 @@ module SmileIdentityCore
|
|
61
59
|
job_id = partner_params[:job_id]
|
62
60
|
|
63
61
|
utilities = SmileIdentityCore::Utilities.new(@partner_id, @api_key, @sid_server)
|
64
|
-
|
62
|
+
utilities.get_job_status(user_id, job_id, options);
|
65
63
|
end
|
66
64
|
|
67
65
|
def partner_params=(partner_params)
|
68
66
|
if partner_params == nil
|
69
|
-
raise ArgumentError
|
67
|
+
raise ArgumentError, 'Please ensure that you send through partner params'
|
70
68
|
end
|
71
69
|
|
72
70
|
if !partner_params.is_a?(Hash)
|
73
|
-
raise ArgumentError
|
71
|
+
raise ArgumentError, 'Partner params needs to be a hash'
|
74
72
|
end
|
75
73
|
|
76
74
|
[:user_id, :job_id, :job_type].each do |key|
|
77
75
|
unless partner_params[key] && !partner_params[key].nil? && !(partner_params[key].empty? if partner_params[key].is_a?(String))
|
78
|
-
raise ArgumentError
|
76
|
+
raise ArgumentError, "Please make sure that #{key} is included in the partner params"
|
79
77
|
end
|
80
78
|
end
|
81
79
|
|
@@ -84,16 +82,16 @@ module SmileIdentityCore
|
|
84
82
|
|
85
83
|
def images=(images)
|
86
84
|
if images == nil
|
87
|
-
raise ArgumentError
|
85
|
+
raise ArgumentError, 'Please ensure that you send through image details'
|
88
86
|
end
|
89
87
|
|
90
88
|
if !images.is_a?(Array)
|
91
|
-
raise ArgumentError
|
89
|
+
raise ArgumentError, 'Image details needs to be an array'
|
92
90
|
end
|
93
91
|
|
94
92
|
# all job types require atleast a selfie
|
95
93
|
if images.length == 0 || images.none? {|h| h[:image_type_id] == 0 || h[:image_type_id] == 2 }
|
96
|
-
raise ArgumentError
|
94
|
+
raise ArgumentError, 'You need to send through at least one selfie image'
|
97
95
|
end
|
98
96
|
|
99
97
|
@images = images.map { |image| symbolize_keys image }
|
@@ -121,7 +119,7 @@ module SmileIdentityCore
|
|
121
119
|
if updated_id_info[:entered] && updated_id_info[:entered] == 'true'
|
122
120
|
[:country, :id_type, :id_number].each do |key|
|
123
121
|
unless id_info[key] && !id_info[key].nil? && !id_info[key].empty?
|
124
|
-
raise ArgumentError
|
122
|
+
raise ArgumentError, "Please make sure that #{key.to_s} is included in the id_info"
|
125
123
|
end
|
126
124
|
end
|
127
125
|
end
|
@@ -130,38 +128,62 @@ module SmileIdentityCore
|
|
130
128
|
end
|
131
129
|
|
132
130
|
def options=(options)
|
133
|
-
updated_options = options
|
131
|
+
updated_options = options || {}
|
134
132
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
if key != :optional_callback
|
141
|
-
updated_options[key] = check_boolean(key, options)
|
142
|
-
else
|
143
|
-
updated_options[key] = check_string(key, options)
|
144
|
-
end
|
145
|
-
end
|
133
|
+
updated_options[:optional_callback] = check_string(:optional_callback, options)
|
134
|
+
updated_options[:return_job_status] = check_boolean(:return_job_status, options)
|
135
|
+
updated_options[:return_image_links] = check_boolean(:return_image_links, options)
|
136
|
+
updated_options[:return_history] = check_boolean(:return_history, options)
|
137
|
+
@use_new_signature = updated_options.fetch(:signature, false)
|
146
138
|
|
147
139
|
@options = updated_options
|
148
140
|
end
|
149
141
|
|
142
|
+
def get_web_token(request_params)
|
143
|
+
raise ArgumentError, 'Please ensure that you send through request params' if request_params.nil?
|
144
|
+
raise ArgumentError, 'Request params needs to be an object' unless request_params.is_a?(Hash)
|
145
|
+
|
146
|
+
callback_url = request_params[:callback_url] || @callback_url
|
147
|
+
request_params[:callback_url] = callback_url
|
148
|
+
|
149
|
+
keys = %i[user_id job_id product callback_url]
|
150
|
+
blank_keys = get_blank_keys(keys, request_params)
|
151
|
+
error_message = "#{blank_keys.join(', ')} #{blank_keys.length > 1 ? 'are' : 'is'} required to get a web token"
|
152
|
+
raise ArgumentError, error_message unless blank_keys.empty?
|
153
|
+
|
154
|
+
request_web_token(request_params)
|
155
|
+
end
|
156
|
+
|
150
157
|
private
|
151
158
|
|
159
|
+
def request_web_token(request_params)
|
160
|
+
request_params.merge!({ partner_id: @partner_id }).merge!(request_security)
|
161
|
+
url = "#{@url}/token"
|
162
|
+
|
163
|
+
response = Typhoeus.post(
|
164
|
+
url,
|
165
|
+
headers: { 'Content-Type' => 'application/json' },
|
166
|
+
body: request_params.to_json
|
167
|
+
)
|
168
|
+
|
169
|
+
return response.body if response.code == 200
|
170
|
+
|
171
|
+
raise "#{response.code}: #{response.body}"
|
172
|
+
end
|
173
|
+
|
152
174
|
def symbolize_keys params
|
153
175
|
(params.is_a?(Hash)) ? Hash[params.map{ |k, v| [k.to_sym, v] }] : params
|
154
176
|
end
|
155
177
|
|
156
178
|
def validate_return_data
|
157
179
|
if (!@callback_url || @callback_url.empty?) && !@options[:return_job_status]
|
158
|
-
raise ArgumentError
|
180
|
+
raise ArgumentError, 'Please choose to either get your response via the callback or job status query'
|
159
181
|
end
|
160
182
|
end
|
161
183
|
|
162
184
|
def validate_enroll_with_id
|
163
185
|
if(((@images.none? {|h| h[:image_type_id] == 1 || h[:image_type_id] == 3 }) && @id_info[:entered] != 'true'))
|
164
|
-
raise ArgumentError
|
186
|
+
raise ArgumentError, 'You are attempting to complete a job type 1 without providing an id card image or id info'
|
165
187
|
end
|
166
188
|
end
|
167
189
|
|
@@ -171,37 +193,54 @@ module SmileIdentityCore
|
|
171
193
|
end
|
172
194
|
|
173
195
|
if !!obj[key] != obj[key]
|
174
|
-
raise ArgumentError
|
196
|
+
raise ArgumentError, "#{key} needs to be a boolean"
|
175
197
|
end
|
176
198
|
|
177
|
-
|
199
|
+
obj[key]
|
178
200
|
end
|
179
201
|
|
180
202
|
def check_string(key, obj)
|
181
203
|
if (!obj || !obj[key])
|
182
|
-
|
204
|
+
''
|
183
205
|
else
|
184
|
-
|
206
|
+
obj[key]
|
185
207
|
end
|
186
208
|
end
|
187
209
|
|
188
|
-
def
|
189
|
-
|
210
|
+
def blank?(obj, key)
|
211
|
+
return obj[key].empty? if obj[key].respond_to?(:empty?)
|
212
|
+
|
213
|
+
obj[key].nil?
|
190
214
|
end
|
191
215
|
|
192
|
-
def
|
216
|
+
def get_blank_keys(keys, obj)
|
217
|
+
keys.select { |key| blank?(obj, key) }
|
218
|
+
end
|
219
|
+
|
220
|
+
def request_security(use_new_signature: true)
|
221
|
+
if use_new_signature
|
222
|
+
@timestamp = Time.now.to_s
|
223
|
+
{
|
224
|
+
signature: SmileIdentityCore::Signature.new(@partner_id, @api_key).generate_signature(@timestamp)[:signature],
|
225
|
+
timestamp: @timestamp,
|
226
|
+
}
|
227
|
+
else
|
228
|
+
@timestamp = Time.now.to_i
|
229
|
+
{
|
230
|
+
sec_key: SmileIdentityCore::Signature.new(@partner_id, @api_key).generate_sec_key(@timestamp)[:sec_key],
|
231
|
+
timestamp: @timestamp,
|
232
|
+
}
|
233
|
+
end
|
234
|
+
end
|
193
235
|
|
194
|
-
|
236
|
+
def configure_prep_upload_json
|
237
|
+
request_security(use_new_signature: @use_new_signature).merge(
|
195
238
|
file_name: 'selfie.zip',
|
196
|
-
timestamp: @timestamp,
|
197
|
-
sec_key: determine_sec_key,
|
198
239
|
smile_client_id: @partner_id,
|
199
240
|
partner_params: @partner_params,
|
200
241
|
model_parameters: {}, # what is this for
|
201
242
|
callback_url: @callback_url
|
202
|
-
|
203
|
-
|
204
|
-
JSON.generate(body)
|
243
|
+
).to_json
|
205
244
|
end
|
206
245
|
|
207
246
|
def setup_requests
|
@@ -216,22 +255,21 @@ module SmileIdentityCore
|
|
216
255
|
|
217
256
|
request.on_complete do |response|
|
218
257
|
if response.success?
|
258
|
+
# TODO: if/when we sign these responses, verify the signature here and raise if it's off.
|
259
|
+
# if updated_options[:signature]
|
260
|
+
# SmileIdentityCore::Signature.new(@partner_id, @api_key).generate_signature(@timestamp)
|
261
|
+
# else
|
262
|
+
# SmileIdentityCore::Signature.new(@partner_id, @api_key).generate_sec_key(@timestamp)
|
263
|
+
# end
|
219
264
|
|
220
265
|
prep_upload_response = JSON.parse(response.body)
|
221
266
|
info_json = configure_info_json(prep_upload_response)
|
222
267
|
|
223
268
|
file_upload_response = upload_file(prep_upload_response['upload_url'], info_json, prep_upload_response['smile_job_id'])
|
224
269
|
return file_upload_response
|
225
|
-
|
226
|
-
elsif response.timed_out?
|
227
|
-
raise "#{response.code.to_s}: #{response.body}"
|
228
|
-
elsif response.code == 0
|
229
|
-
# Could not get an http response, something's wrong.
|
230
|
-
raise "#{response.code.to_s}: #{response.body}"
|
231
|
-
else
|
232
|
-
# Received a non-successful http response.
|
233
|
-
raise "#{response.code.to_s}: #{response.body}"
|
234
270
|
end
|
271
|
+
|
272
|
+
raise "#{response.code}: #{response.body}"
|
235
273
|
end
|
236
274
|
request.run
|
237
275
|
end
|
@@ -246,11 +284,9 @@ module SmileIdentityCore
|
|
246
284
|
},
|
247
285
|
"language": "ruby"
|
248
286
|
},
|
249
|
-
"misc_information":
|
250
|
-
"sec_key": @sec_key,
|
287
|
+
"misc_information": request_security(use_new_signature: @use_new_signature).merge(
|
251
288
|
"retry": "false",
|
252
289
|
"partner_params": @partner_params,
|
253
|
-
"timestamp": @timestamp,
|
254
290
|
"file_name": "selfie.zip", # figure out what to do here
|
255
291
|
"smile_client_id": @partner_id,
|
256
292
|
"callback_url": @callback_url,
|
@@ -266,17 +302,17 @@ module SmileIdentityCore
|
|
266
302
|
"countryCode": "+",
|
267
303
|
"countryName": ""
|
268
304
|
}
|
269
|
-
|
305
|
+
),
|
270
306
|
"id_info": @id_info,
|
271
307
|
"images": configure_image_payload,
|
272
308
|
"server_information": server_information
|
273
309
|
}
|
274
|
-
|
310
|
+
info
|
275
311
|
end
|
276
312
|
|
277
313
|
def configure_image_payload
|
278
314
|
@images.map { |i|
|
279
|
-
if
|
315
|
+
if image_file?(i[:image_type_id])
|
280
316
|
{
|
281
317
|
image_type_id: i[:image_type_id],
|
282
318
|
image: '',
|
@@ -292,7 +328,7 @@ module SmileIdentityCore
|
|
292
328
|
}
|
293
329
|
end
|
294
330
|
|
295
|
-
def
|
331
|
+
def image_file?(type)
|
296
332
|
type.to_i == 0 || type.to_i == 1
|
297
333
|
end
|
298
334
|
|
@@ -329,19 +365,15 @@ module SmileIdentityCore
|
|
329
365
|
if response.success?
|
330
366
|
if @options[:return_job_status]
|
331
367
|
@utilies_connection = SmileIdentityCore::Utilities.new(@partner_id, @api_key, @sid_server)
|
332
|
-
|
368
|
+
job_response = query_job_status
|
369
|
+
job_response["success"] = true
|
370
|
+
job_response["smile_job_id"] = smile_job_id
|
371
|
+
return job_response
|
333
372
|
else
|
334
373
|
return {success: true, smile_job_id: smile_job_id}.to_json
|
335
374
|
end
|
336
|
-
elsif response.timed_out?
|
337
|
-
raise " #{response.code.to_s}: #{response.body}"
|
338
|
-
elsif response.code == 0
|
339
|
-
# Could not get an http response, something's wrong.
|
340
|
-
raise " #{response.code.to_s}: #{response.body}"
|
341
|
-
else
|
342
|
-
# Received a non-successful http response.
|
343
|
-
raise " #{response.code.to_s}: #{response.body}"
|
344
375
|
end
|
376
|
+
raise " #{response.code}: #{response.body}"
|
345
377
|
end
|
346
378
|
request.run
|
347
379
|
|
@@ -354,9 +386,9 @@ module SmileIdentityCore
|
|
354
386
|
response = @utilies_connection.get_job_status(@partner_params[:user_id], @partner_params[:job_id], @options)
|
355
387
|
|
356
388
|
if response && (response['job_complete'] == true || counter == 20)
|
357
|
-
|
389
|
+
response
|
358
390
|
else
|
359
|
-
|
391
|
+
query_job_status(counter)
|
360
392
|
end
|
361
393
|
|
362
394
|
end
|
data/smile-identity-core.gemspec
CHANGED
@@ -5,8 +5,8 @@ require "smile-identity-core/version"
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "smile-identity-core"
|
7
7
|
spec.version = SmileIdentityCore::VERSION
|
8
|
-
spec.authors = ["
|
9
|
-
spec.email = ["
|
8
|
+
spec.authors = ["Smile Identity"]
|
9
|
+
spec.email = ["support@smileidentity.com"]
|
10
10
|
|
11
11
|
spec.summary = "The Smile Identity Web API allows the user to access most of the features of the Smile Identity system through direct server to server queries."
|
12
12
|
spec.description = "The Official Smile Identity gem"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smile-identity-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
autorequire:
|
7
|
+
- Smile Identity
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,7 +108,7 @@ dependencies:
|
|
108
108
|
version: 1.2.3
|
109
109
|
description: The Official Smile Identity gem
|
110
110
|
email:
|
111
|
-
-
|
111
|
+
- support@smileidentity.com
|
112
112
|
executables: []
|
113
113
|
extensions: []
|
114
114
|
extra_rdoc_files: []
|
@@ -130,7 +130,6 @@ files:
|
|
130
130
|
- lib/smile-identity-core/version.rb
|
131
131
|
- lib/smile-identity-core/web_api.rb
|
132
132
|
- smile-identity-core.gemspec
|
133
|
-
- travis.yml
|
134
133
|
homepage: https://www.smileidentity.com/
|
135
134
|
licenses:
|
136
135
|
- MIT
|
@@ -139,7 +138,7 @@ metadata:
|
|
139
138
|
source_code_uri: https://github.com/smileidentity/smile-identity-core-ruby
|
140
139
|
documentation_uri: https://docs.smileidentity.com
|
141
140
|
changelog_uri: https://github.com/smileidentity/smile-identity-core/blob/master/CHANGELOG.md
|
142
|
-
post_install_message:
|
141
|
+
post_install_message:
|
143
142
|
rdoc_options: []
|
144
143
|
require_paths:
|
145
144
|
- lib
|
@@ -154,9 +153,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
153
|
- !ruby/object:Gem::Version
|
155
154
|
version: '0'
|
156
155
|
requirements: []
|
157
|
-
|
158
|
-
|
159
|
-
signing_key:
|
156
|
+
rubygems_version: 3.2.3
|
157
|
+
signing_key:
|
160
158
|
specification_version: 4
|
161
159
|
summary: The Smile Identity Web API allows the user to access most of the features
|
162
160
|
of the Smile Identity system through direct server to server queries.
|