smile-identity-core 1.2.1 → 2.0.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.
@@ -1,26 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SmileIdentityCore
4
+ # Allows you to query the Identity Information for an individual using their ID number
2
5
  class IDApi
3
-
4
6
  def initialize(partner_id, api_key, sid_server)
5
7
  @partner_id = partner_id.to_s
6
8
  @api_key = api_key
7
9
 
8
- @sid_server = sid_server
9
- if !(sid_server =~ URI::regexp)
10
- sid_server_mapping = {
11
- 0 => 'https://testapi.smileidentity.com/v1',
12
- 1 => 'https://api.smileidentity.com/v1',
13
- }
14
- @url = sid_server_mapping[sid_server.to_i]
15
- else
16
- @url = sid_server
17
- end
10
+ @url = if sid_server !~ URI::DEFAULT_PARSER.make_regexp
11
+ SmileIdentityCore::ENV::SID_SERVER_MAPPING[sid_server.to_s]
12
+ else
13
+ sid_server
14
+ end
18
15
  end
19
16
 
20
17
  def submit_job(partner_params, id_info, options = {})
21
18
  self.partner_params = symbolize_keys partner_params
22
19
  self.id_info = symbolize_keys id_info
23
- @use_new_signature = symbolize_keys(options || {}).fetch(:signature, false)
20
+ options = symbolize_keys(options || {})
21
+ @use_async_endpoint = options.fetch(:async, false)
24
22
 
25
23
  if @partner_params[:job_type].to_i != 5
26
24
  raise ArgumentError, 'Please ensure that you are setting your job_type to 5 to query ID Api'
@@ -30,17 +28,14 @@ module SmileIdentityCore
30
28
  end
31
29
 
32
30
  def partner_params=(partner_params)
33
- if partner_params == nil
34
- raise ArgumentError, 'Please ensure that you send through partner params'
35
- end
31
+ raise ArgumentError, 'Please ensure that you send through partner params' if partner_params.nil?
36
32
 
37
- if !partner_params.is_a?(Hash)
38
- raise ArgumentError, 'Partner params needs to be a hash'
39
- end
33
+ raise ArgumentError, 'Partner params needs to be a hash' unless partner_params.is_a?(Hash)
40
34
 
41
- [:user_id, :job_id, :job_type].each do |key|
42
- unless partner_params[key] && !partner_params[key].nil? && !(partner_params[key].empty? if partner_params[key].is_a?(String))
43
- raise ArgumentError, "Please make sure that #{key} is included in the partner params"
35
+ %i[user_id job_id job_type].each do |key|
36
+ if partner_params[key].to_s.empty?
37
+ raise ArgumentError,
38
+ "Please make sure that #{key} is included in the partner params"
44
39
  end
45
40
  end
46
41
 
@@ -48,14 +43,13 @@ module SmileIdentityCore
48
43
  end
49
44
 
50
45
  def id_info=(id_info)
51
-
52
46
  updated_id_info = id_info
53
47
 
54
- if updated_id_info.nil? || updated_id_info.keys.length == 0
48
+ if updated_id_info.nil? || updated_id_info.keys.length.zero?
55
49
  raise ArgumentError, 'Please make sure that id_info not empty or nil'
56
50
  end
57
51
 
58
- [:country, :id_type, :id_number].each do |key|
52
+ %i[country id_type id_number].each do |key|
59
53
  unless updated_id_info[key] && !updated_id_info[key].nil? && !updated_id_info[key].empty?
60
54
  raise ArgumentError, "Please make sure that #{key} is included in the id_info"
61
55
  end
@@ -66,17 +60,15 @@ module SmileIdentityCore
66
60
 
67
61
  private
68
62
 
69
- def symbolize_keys params
70
- (params.is_a?(Hash)) ? Hash[params.map{ |k, v| [k.to_sym, v] }] : params
63
+ def symbolize_keys(params)
64
+ params.is_a?(Hash) ? params.transform_keys(&:to_sym) : params
71
65
  end
72
66
 
73
67
  def setup_requests
74
- url = "#{@url}/id_verification"
75
-
76
68
  request = Typhoeus::Request.new(
77
- url,
69
+ "#{@url}/#{endpoint}",
78
70
  method: 'POST',
79
- headers: {'Content-Type'=> "application/json"},
71
+ headers: { 'Content-Type' => 'application/json' },
80
72
  body: configure_json
81
73
  )
82
74
 
@@ -88,39 +80,24 @@ module SmileIdentityCore
88
80
  request.run
89
81
  end
90
82
 
83
+ def endpoint
84
+ @use_async_endpoint ? 'async_id_verification' : 'id_verification'
85
+ end
86
+
91
87
  def configure_json
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
88
+ signature_generator.generate_signature(Time.now.to_s)
89
+ .merge(@id_info)
90
+ .merge(
91
+ partner_id: @partner_id,
92
+ partner_params: @partner_params,
93
+ source_sdk: SmileIdentityCore::SOURCE_SDK,
94
+ source_sdk_version: SmileIdentityCore::VERSION
95
+ )
96
+ .to_json
98
97
  end
99
98
 
100
99
  def signature_generator
101
100
  SmileIdentityCore::Signature.new(@partner_id, @api_key)
102
101
  end
103
-
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
- }
118
- end
119
-
120
- def request_security(use_new_signature: true)
121
- return signature if use_new_signature
122
-
123
- sec_key
124
- end
125
102
  end
126
103
  end
@@ -1,54 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SmileIdentityCore
4
+ # Contains handy methods to generate and confirm signature for authentication
2
5
  class Signature
3
-
4
6
  def initialize(partner_id, api_key)
5
7
  @api_key = api_key
6
8
  @partner_id = partner_id
7
9
  end
8
10
 
9
- def generate_sec_key(timestamp=Time.now.to_i)
10
- begin
11
- @timestamp = timestamp
12
-
13
- hash_signature = Digest::SHA256.hexdigest([@partner_id.to_i, @timestamp].join(":"))
14
- public_key = OpenSSL::PKey::RSA.new(Base64.decode64(@api_key))
15
- @sec_key = [Base64.encode64(public_key.public_encrypt(hash_signature)), hash_signature].join('|')
16
-
17
- {
18
- sec_key: @sec_key,
19
- timestamp: @timestamp
20
- }
21
- rescue => e
22
- raise e
23
- end
24
- end
25
-
26
- def confirm_sec_key(timestamp, sec_key)
27
- begin
28
- hash_signature = Digest::SHA256.hexdigest([@partner_id.to_i, timestamp].join(":"))
29
- encrypted = sec_key.split('|')[0]
30
-
31
- public_key = OpenSSL::PKey::RSA.new(Base64.decode64(@api_key))
32
- decrypted = public_key.public_decrypt(Base64.decode64(encrypted))
33
-
34
- decrypted == hash_signature
35
- rescue => e
36
- raise e
37
- end
38
- end
39
-
40
- def generate_signature(timestamp=Time.now.to_s)
11
+ # Generates a signature based on the specified timestamp (uses the current time by default)
12
+ #
13
+ # @return [Hash] containing both the signature and related timestamp
14
+ def generate_signature(timestamp = Time.now.to_s)
41
15
  hmac = OpenSSL::HMAC.new(@api_key, 'sha256')
42
16
  hmac.update(timestamp.to_s)
43
17
  hmac.update(@partner_id)
44
- hmac.update("sid_request")
45
- signature = Base64.strict_encode64(hmac.digest())
18
+ hmac.update('sid_request')
19
+ @signature = Base64.strict_encode64(hmac.digest)
46
20
  {
47
- signature: signature,
21
+ signature: @signature,
48
22
  timestamp: timestamp.to_s
49
23
  }
50
24
  end
51
25
 
26
+ # Confirms the signature against a newly generated signature based on the same timestamp
27
+ #
28
+ # @param [String] timestamp the timestamp to generate the signature from
29
+ # @param [String] msg_signature a previously generated signature, to be confirmed
30
+ # @return [Boolean] TRUE or FALSE
52
31
  def confirm_signature(timestamp, msg_signature)
53
32
  generate_signature(timestamp)[:signature] == msg_signature
54
33
  end
@@ -1,22 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SmileIdentityCore
4
+ # A utility class to query job status
2
5
  class Utilities
3
-
4
6
  def initialize(partner_id, api_key, sid_server)
5
7
  @partner_id = partner_id.to_s
6
8
  @api_key = api_key
7
9
 
8
- if !(sid_server =~ URI::regexp)
9
- sid_server_mapping = {
10
- 0 => 'https://testapi.smileidentity.com/v1',
11
- 1 => 'https://api.smileidentity.com/v1',
12
- }
13
- @url = sid_server_mapping[sid_server.to_i]
14
- else
15
- @url = sid_server
16
- end
10
+ @url = if sid_server !~ URI::DEFAULT_PARSER.make_regexp
11
+ SmileIdentityCore::ENV::SID_SERVER_MAPPING[sid_server.to_s]
12
+ else
13
+ sid_server
14
+ end
17
15
 
18
16
  @signature_connection = SmileIdentityCore::Signature.new(@partner_id, @api_key)
19
-
20
17
  end
21
18
 
22
19
  def get_job_status(user_id, job_id, options = {})
@@ -24,77 +21,53 @@ module SmileIdentityCore
24
21
  options[:return_history] ||= false
25
22
  options[:return_image_links] ||= false
26
23
 
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))
24
+ query_job_status(configure_job_query(user_id, job_id,
25
+ options).merge(@signature_connection.generate_signature(Time.now.to_s)))
29
26
  end
30
27
 
31
28
  private
32
29
 
33
- def symbolize_keys params
34
- (params.is_a?(Hash)) ? Hash[params.map{ |k, v| [k.to_sym, v] }] : params
30
+ def symbolize_keys(params)
31
+ params.is_a?(Hash) ? params.transform_keys(&:to_sym) : params
35
32
  end
36
33
 
37
34
  def query_job_status(request_json_data)
38
- url = "#{@url}/job_status"
39
-
40
35
  request = Typhoeus::Request.new(
41
- url,
42
- headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
36
+ "#{@url}/job_status",
37
+ headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
43
38
  method: :post,
44
39
  body: request_json_data.to_json
45
40
  )
46
41
 
47
42
  request.on_complete do |response|
48
- begin
49
- body = JSON.parse(response.body)
43
+ body = JSON.parse(response.body)
50
44
 
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
45
+ # NB: we have to trust that the server will return the right kind of
46
+ # timestamp (integer or string) for the signature, and the right kind
47
+ # of signature in the "signature" field. The best way to know what
48
+ # kind of validation to perform is by remembering which kind of
49
+ # security we started with.
50
+ valid = @signature_connection.confirm_signature(body['timestamp'], body['signature'])
61
51
 
62
- if(!valid)
63
- raise "Unable to confirm validity of the job_status response"
64
- end
52
+ raise 'Unable to confirm validity of the job_status response' unless valid
65
53
 
66
- return body
67
- rescue => e
68
- raise e
69
- end
54
+ return body
55
+ rescue StandardError => e
56
+ raise e
70
57
  end
71
58
 
72
59
  request.run
73
60
  end
74
61
 
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
-
91
62
  def configure_job_query(user_id, job_id, options)
92
63
  {
93
64
  user_id: user_id,
94
65
  job_id: job_id,
95
66
  partner_id: @partner_id,
96
67
  image_links: options[:return_image_links],
97
- history: options[:return_history]
68
+ history: options[:return_history],
69
+ source_sdk: SmileIdentityCore::SOURCE_SDK,
70
+ source_sdk_version: SmileIdentityCore::VERSION
98
71
  }
99
72
  end
100
73
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmileIdentityCore
4
+ module Validations # :nodoc:
5
+ def validate_partner_params(partner_params)
6
+ raise ArgumentError, 'Please ensure that you send through partner params' if partner_params.nil?
7
+
8
+ raise ArgumentError, 'Partner params needs to be a hash' unless partner_params.is_a?(Hash)
9
+
10
+ %i[user_id job_id job_type].each do |key|
11
+ if partner_params[key].to_s.empty?
12
+ raise ArgumentError,
13
+ "Please make sure that #{key} is included in the partner params"
14
+ end
15
+ end
16
+
17
+ partner_params
18
+ end
19
+
20
+ def validate_id_info(id_info, required_id_info_fields)
21
+ raise ArgumentError, 'Please make sure that id_info not empty or nil' if id_info.nil? || id_info.empty?
22
+
23
+ raise ArgumentError, 'Id info needs to be a hash' unless id_info.is_a?(Hash)
24
+
25
+ required_id_info_fields.each do |key|
26
+ raise ArgumentError, "Please make sure that #{key} is included in the id_info" if id_info[key].to_s.empty?
27
+ end
28
+
29
+ id_info
30
+ end
31
+ end
32
+ end
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SmileIdentityCore
2
- VERSION = "1.2.1"
4
+ VERSION = '2.0.0'
5
+ SOURCE_SDK = 'Ruby'
3
6
  end