smile-identity-core 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +5 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +5 -5
- data/README.md +74 -29
- data/lib/smile-identity-core/id_api.rb +35 -25
- 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 +6 -1
- data/lib/smile-identity-core/web_api.rb +102 -63
- data/smile-identity-core.gemspec +2 -2
- metadata +5 -7
- 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: 9614cb861ac00a8133527a647e8d6c6dcc91b00aca6c7fe643e32ddc986b3f7d
|
4
|
+
data.tar.gz: f1ac7dcb3413c1f08ac16c909e0f466091519dae0412519a1161cd0179143040
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: db1d5e0344e58bb11728af749ef1b37f051add89fdda7797347d0771d091b3221482d90beed6f566d082d4120c9c2d45d63e0dea828202ff9c087d58c498094e
|
7
|
+
data.tar.gz: f524bd93102a7ac6621314a950b5fba0b06a62437f1ad4328e26c092192ffa74ccc9ce5919d1806e126a5d2d9305b9ad204e913da13cf02f1c31079d5775dc70
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -39,3 +39,11 @@ Amend the success response when job status is false to be a JSON String containi
|
|
39
39
|
Add the ID API Class
|
40
40
|
Add the ability to query ID Api from the Web API class
|
41
41
|
Update the documentation
|
42
|
+
|
43
|
+
## [1.0.1] - 2019-10-24
|
44
|
+
## Updated
|
45
|
+
Remove first_name and last_name validations from id information in Web Api
|
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.0)
|
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,10 +52,14 @@ 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|
|
59
|
+
unless updated_id_info[key] && !updated_id_info[key].nil? && !updated_id_info[key].empty?
|
60
|
+
raise ArgumentError, "Please make sure that #{key} is included in the id_info"
|
61
|
+
end
|
62
|
+
end
|
61
63
|
|
62
64
|
@id_info = updated_id_info
|
63
65
|
end
|
@@ -95,20 +97,28 @@ module SmileIdentityCore
|
|
95
97
|
end
|
96
98
|
|
97
99
|
def configure_json
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
body.merge!(@id_info)
|
106
|
-
JSON.generate(body)
|
100
|
+
request_security(use_new_signature: @use_new_signature)
|
101
|
+
.merge(@id_info)
|
102
|
+
.merge(
|
103
|
+
partner_id: @partner_id,
|
104
|
+
partner_params: @partner_params)
|
105
|
+
.to_json
|
107
106
|
end
|
108
107
|
|
109
|
-
def
|
110
|
-
|
108
|
+
def request_security(use_new_signature: true)
|
109
|
+
if use_new_signature
|
110
|
+
@timestamp = Time.now.to_s
|
111
|
+
{
|
112
|
+
signature: SmileIdentityCore::Signature.new(@partner_id, @api_key).generate_signature(@timestamp)[:signature],
|
113
|
+
timestamp: @timestamp,
|
114
|
+
}
|
115
|
+
else
|
116
|
+
@timestamp = Time.now.to_i
|
117
|
+
{
|
118
|
+
sec_key: SmileIdentityCore::Signature.new(@partner_id, @api_key).generate_sec_key(@timestamp)[:sec_key],
|
119
|
+
timestamp: @timestamp,
|
120
|
+
}
|
121
|
+
end
|
111
122
|
end
|
112
|
-
|
113
123
|
end
|
114
124
|
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,19 +82,20 @@ 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 }
|
98
|
+
|
100
99
|
end
|
101
100
|
|
102
101
|
def id_info=(id_info)
|
@@ -118,53 +117,73 @@ module SmileIdentityCore
|
|
118
117
|
end
|
119
118
|
|
120
119
|
if updated_id_info[:entered] && updated_id_info[:entered] == 'true'
|
121
|
-
[:
|
120
|
+
[:country, :id_type, :id_number].each do |key|
|
122
121
|
unless id_info[key] && !id_info[key].nil? && !id_info[key].empty?
|
123
|
-
raise ArgumentError
|
122
|
+
raise ArgumentError, "Please make sure that #{key.to_s} is included in the id_info"
|
124
123
|
end
|
125
124
|
end
|
126
125
|
end
|
127
126
|
|
128
|
-
if updated_id_info[:country] && updated_id_info[:country].upcase == 'NG' && ['PASSPORT', 'VOTER_ID', 'DRIVERS_LICENSE', 'NATIONAL_ID', 'TIN', 'CAC'].include?(updated_id_info[:id_type].upcase) && (!updated_id_info[:dob] || updated_id_info[:dob].empty? || updated_id_info[:dob].nil?)
|
129
|
-
raise ArgumentError.new("The ID type #{updated_id_info[:id_type]} for #{updated_id_info[:country]} requires a valid dob paramater.")
|
130
|
-
end
|
131
|
-
|
132
127
|
@id_info = updated_id_info
|
133
128
|
end
|
134
129
|
|
135
130
|
def options=(options)
|
136
|
-
updated_options = options
|
131
|
+
updated_options = options || {}
|
137
132
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
if key != :optional_callback
|
144
|
-
updated_options[key] = check_boolean(key, options)
|
145
|
-
else
|
146
|
-
updated_options[key] = check_string(key, options)
|
147
|
-
end
|
148
|
-
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)
|
149
138
|
|
150
139
|
@options = updated_options
|
151
140
|
end
|
152
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
|
+
|
153
157
|
private
|
154
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
|
+
|
155
174
|
def symbolize_keys params
|
156
175
|
(params.is_a?(Hash)) ? Hash[params.map{ |k, v| [k.to_sym, v] }] : params
|
157
176
|
end
|
158
177
|
|
159
178
|
def validate_return_data
|
160
179
|
if (!@callback_url || @callback_url.empty?) && !@options[:return_job_status]
|
161
|
-
raise ArgumentError
|
180
|
+
raise ArgumentError, 'Please choose to either get your response via the callback or job status query'
|
162
181
|
end
|
163
182
|
end
|
164
183
|
|
165
184
|
def validate_enroll_with_id
|
166
185
|
if(((@images.none? {|h| h[:image_type_id] == 1 || h[:image_type_id] == 3 }) && @id_info[:entered] != 'true'))
|
167
|
-
raise ArgumentError
|
186
|
+
raise ArgumentError, 'You are attempting to complete a job type 1 without providing an id card image or id info'
|
168
187
|
end
|
169
188
|
end
|
170
189
|
|
@@ -174,37 +193,54 @@ module SmileIdentityCore
|
|
174
193
|
end
|
175
194
|
|
176
195
|
if !!obj[key] != obj[key]
|
177
|
-
raise ArgumentError
|
196
|
+
raise ArgumentError, "#{key} needs to be a boolean"
|
178
197
|
end
|
179
198
|
|
180
|
-
|
199
|
+
obj[key]
|
181
200
|
end
|
182
201
|
|
183
202
|
def check_string(key, obj)
|
184
203
|
if (!obj || !obj[key])
|
185
|
-
|
204
|
+
''
|
186
205
|
else
|
187
|
-
|
206
|
+
obj[key]
|
188
207
|
end
|
189
208
|
end
|
190
209
|
|
191
|
-
def
|
192
|
-
|
210
|
+
def blank?(obj, key)
|
211
|
+
return obj[key].empty? if obj[key].respond_to?(:empty?)
|
212
|
+
|
213
|
+
obj[key].nil?
|
193
214
|
end
|
194
215
|
|
195
|
-
def
|
216
|
+
def get_blank_keys(keys, obj)
|
217
|
+
keys.select { |key| blank?(obj, key) }
|
218
|
+
end
|
196
219
|
|
197
|
-
|
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
|
235
|
+
|
236
|
+
def configure_prep_upload_json
|
237
|
+
request_security(use_new_signature: @use_new_signature).merge(
|
198
238
|
file_name: 'selfie.zip',
|
199
|
-
timestamp: @timestamp,
|
200
|
-
sec_key: determine_sec_key,
|
201
239
|
smile_client_id: @partner_id,
|
202
240
|
partner_params: @partner_params,
|
203
241
|
model_parameters: {}, # what is this for
|
204
242
|
callback_url: @callback_url
|
205
|
-
|
206
|
-
|
207
|
-
JSON.generate(body)
|
243
|
+
).to_json
|
208
244
|
end
|
209
245
|
|
210
246
|
def setup_requests
|
@@ -219,6 +255,12 @@ module SmileIdentityCore
|
|
219
255
|
|
220
256
|
request.on_complete do |response|
|
221
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
|
222
264
|
|
223
265
|
prep_upload_response = JSON.parse(response.body)
|
224
266
|
info_json = configure_info_json(prep_upload_response)
|
@@ -227,13 +269,13 @@ module SmileIdentityCore
|
|
227
269
|
return file_upload_response
|
228
270
|
|
229
271
|
elsif response.timed_out?
|
230
|
-
raise "#{response.code
|
272
|
+
raise "#{response.code}: #{response.body}"
|
231
273
|
elsif response.code == 0
|
232
274
|
# Could not get an http response, something's wrong.
|
233
|
-
raise "#{response.code
|
275
|
+
raise "#{response.code}: #{response.body}"
|
234
276
|
else
|
235
277
|
# Received a non-successful http response.
|
236
|
-
raise "#{response.code
|
278
|
+
raise "#{response.code}: #{response.body}"
|
237
279
|
end
|
238
280
|
end
|
239
281
|
request.run
|
@@ -242,18 +284,12 @@ module SmileIdentityCore
|
|
242
284
|
def configure_info_json(server_information)
|
243
285
|
info = {
|
244
286
|
"package_information": {
|
245
|
-
"apiVersion":
|
246
|
-
"buildNumber": 0,
|
247
|
-
"majorVersion": 2,
|
248
|
-
"minorVersion": 0
|
249
|
-
},
|
287
|
+
"apiVersion": SmileIdentityCore.version_as_hash,
|
250
288
|
"language": "ruby"
|
251
289
|
},
|
252
|
-
"misc_information":
|
253
|
-
"sec_key": @sec_key,
|
290
|
+
"misc_information": request_security(use_new_signature: @use_new_signature).merge(
|
254
291
|
"retry": "false",
|
255
292
|
"partner_params": @partner_params,
|
256
|
-
"timestamp": @timestamp,
|
257
293
|
"file_name": "selfie.zip", # figure out what to do here
|
258
294
|
"smile_client_id": @partner_id,
|
259
295
|
"callback_url": @callback_url,
|
@@ -269,17 +305,17 @@ module SmileIdentityCore
|
|
269
305
|
"countryCode": "+",
|
270
306
|
"countryName": ""
|
271
307
|
}
|
272
|
-
|
308
|
+
),
|
273
309
|
"id_info": @id_info,
|
274
310
|
"images": configure_image_payload,
|
275
311
|
"server_information": server_information
|
276
312
|
}
|
277
|
-
|
313
|
+
info
|
278
314
|
end
|
279
315
|
|
280
316
|
def configure_image_payload
|
281
317
|
@images.map { |i|
|
282
|
-
if
|
318
|
+
if image_file?(i[:image_type_id])
|
283
319
|
{
|
284
320
|
image_type_id: i[:image_type_id],
|
285
321
|
image: '',
|
@@ -295,7 +331,7 @@ module SmileIdentityCore
|
|
295
331
|
}
|
296
332
|
end
|
297
333
|
|
298
|
-
def
|
334
|
+
def image_file?(type)
|
299
335
|
type.to_i == 0 || type.to_i == 1
|
300
336
|
end
|
301
337
|
|
@@ -332,7 +368,10 @@ module SmileIdentityCore
|
|
332
368
|
if response.success?
|
333
369
|
if @options[:return_job_status]
|
334
370
|
@utilies_connection = SmileIdentityCore::Utilities.new(@partner_id, @api_key, @sid_server)
|
335
|
-
|
371
|
+
job_response = query_job_status
|
372
|
+
job_response["success"] = true
|
373
|
+
job_response["smile_job_id"] = smile_job_id
|
374
|
+
return job_response
|
336
375
|
else
|
337
376
|
return {success: true, smile_job_id: smile_job_id}.to_json
|
338
377
|
end
|
@@ -357,9 +396,9 @@ module SmileIdentityCore
|
|
357
396
|
response = @utilies_connection.get_job_status(@partner_params[:user_id], @partner_params[:job_id], @options)
|
358
397
|
|
359
398
|
if response && (response['job_complete'] == true || counter == 20)
|
360
|
-
|
399
|
+
response
|
361
400
|
else
|
362
|
-
|
401
|
+
query_job_status(counter)
|
363
402
|
end
|
364
403
|
|
365
404
|
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.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Smile Identity
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-10-13 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
|
@@ -154,8 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
153
|
- !ruby/object:Gem::Version
|
155
154
|
version: '0'
|
156
155
|
requirements: []
|
157
|
-
|
158
|
-
rubygems_version: 2.7.6
|
156
|
+
rubygems_version: 3.0.3
|
159
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
|