yoti 1.6.3 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +22 -224
- data/lib/yoti.rb +54 -1
- data/lib/yoti/client.rb +13 -4
- data/lib/yoti/configuration.rb +7 -2
- data/lib/yoti/data_type/age_verification.rb +1 -1
- data/lib/yoti/data_type/base_profile.rb +1 -1
- data/lib/yoti/data_type/image.rb +4 -12
- data/lib/yoti/data_type/image_jpeg.rb +2 -0
- data/lib/yoti/data_type/image_png.rb +2 -0
- data/lib/yoti/data_type/media.rb +19 -0
- data/lib/yoti/data_type/signed_time_stamp.rb +1 -1
- data/lib/yoti/doc_scan/client.rb +187 -0
- data/lib/yoti/doc_scan/constants.rb +31 -0
- data/lib/yoti/doc_scan/errors.rb +81 -0
- data/lib/yoti/doc_scan/session/create/create_session_result.rb +50 -0
- data/lib/yoti/doc_scan/session/create/document_filter.rb +31 -0
- data/lib/yoti/doc_scan/session/create/document_restrictions_filter.rb +140 -0
- data/lib/yoti/doc_scan/session/create/notification_config.rb +142 -0
- data/lib/yoti/doc_scan/session/create/orthogonal_restrictions_filter.rb +150 -0
- data/lib/yoti/doc_scan/session/create/requested_check.rb +39 -0
- data/lib/yoti/doc_scan/session/create/requested_document_authenticity_check.rb +95 -0
- data/lib/yoti/doc_scan/session/create/requested_face_match_check.rb +95 -0
- data/lib/yoti/doc_scan/session/create/requested_id_document_comparison_check.rb +53 -0
- data/lib/yoti/doc_scan/session/create/requested_liveness_check.rb +108 -0
- data/lib/yoti/doc_scan/session/create/requested_task.rb +39 -0
- data/lib/yoti/doc_scan/session/create/requested_text_extraction_task.rb +116 -0
- data/lib/yoti/doc_scan/session/create/required_document.rb +31 -0
- data/lib/yoti/doc_scan/session/create/required_id_document.rb +53 -0
- data/lib/yoti/doc_scan/session/create/sdk_config.rb +221 -0
- data/lib/yoti/doc_scan/session/create/session_specification.rb +221 -0
- data/lib/yoti/doc_scan/session/retrieve/authenticity_check_response.rb +12 -0
- data/lib/yoti/doc_scan/session/retrieve/breakdown_response.rb +38 -0
- data/lib/yoti/doc_scan/session/retrieve/check_response.rb +63 -0
- data/lib/yoti/doc_scan/session/retrieve/details_response.rb +28 -0
- data/lib/yoti/doc_scan/session/retrieve/document_fields_response.rb +21 -0
- data/lib/yoti/doc_scan/session/retrieve/document_id_photo_response.rb +21 -0
- data/lib/yoti/doc_scan/session/retrieve/face_map_response.rb +21 -0
- data/lib/yoti/doc_scan/session/retrieve/face_match_check_response.rb +12 -0
- data/lib/yoti/doc_scan/session/retrieve/frame_response.rb +21 -0
- data/lib/yoti/doc_scan/session/retrieve/generated_check_response.rb +28 -0
- data/lib/yoti/doc_scan/session/retrieve/generated_media.rb +28 -0
- data/lib/yoti/doc_scan/session/retrieve/generated_text_data_check_response.rb +12 -0
- data/lib/yoti/doc_scan/session/retrieve/get_session_result.rb +127 -0
- data/lib/yoti/doc_scan/session/retrieve/id_document_comparison_check_response.rb +12 -0
- data/lib/yoti/doc_scan/session/retrieve/id_document_resource_response.rb +57 -0
- data/lib/yoti/doc_scan/session/retrieve/liveness_check_response.rb +12 -0
- data/lib/yoti/doc_scan/session/retrieve/liveness_resource_response.rb +24 -0
- data/lib/yoti/doc_scan/session/retrieve/media_response.rb +38 -0
- data/lib/yoti/doc_scan/session/retrieve/page_response.rb +27 -0
- data/lib/yoti/doc_scan/session/retrieve/recommendation_response.rb +34 -0
- data/lib/yoti/doc_scan/session/retrieve/report_response.rb +31 -0
- data/lib/yoti/doc_scan/session/retrieve/resource_container.rb +50 -0
- data/lib/yoti/doc_scan/session/retrieve/resource_response.rb +39 -0
- data/lib/yoti/doc_scan/session/retrieve/task_response.rb +87 -0
- data/lib/yoti/doc_scan/session/retrieve/text_data_check_response.rb +12 -0
- data/lib/yoti/doc_scan/session/retrieve/text_extraction_task_response.rb +18 -0
- data/lib/yoti/doc_scan/session/retrieve/zoom_liveness_resource_response.rb +33 -0
- data/lib/yoti/doc_scan/support/supported_documents.rb +60 -0
- data/lib/yoti/dynamic_share_service/extension/thirdparty_attribute_extension.rb +62 -11
- data/lib/yoti/dynamic_share_service/policy/dynamic_policy.rb +84 -22
- data/lib/yoti/dynamic_share_service/share_url.rb +28 -33
- data/lib/yoti/errors.rb +15 -2
- data/lib/yoti/http/aml_check_request.rb +12 -6
- data/lib/yoti/http/payloads/aml_address.rb +4 -0
- data/lib/yoti/http/payloads/aml_profile.rb +7 -1
- data/lib/yoti/http/profile_request.rb +11 -6
- data/lib/yoti/http/request.rb +221 -18
- data/lib/yoti/http/signed_request.rb +13 -4
- data/lib/yoti/protobuf/main.rb +1 -1
- data/lib/yoti/ssl.rb +2 -2
- data/lib/yoti/util/anchor_processor.rb +1 -1
- data/lib/yoti/util/validation.rb +41 -0
- data/lib/yoti/version.rb +1 -1
- data/yoti.gemspec +19 -9
- metadata +60 -67
- data/.github/ISSUE_TEMPLATE.md +0 -17
- data/.gitignore +0 -39
- data/CONTRIBUTING.md +0 -127
- data/Guardfile +0 -11
- data/Rakefile +0 -49
- data/login_flow.png +0 -0
- data/rubocop.yml +0 -57
- data/yardstick.yml +0 -9
data/lib/yoti/data_type/image.rb
CHANGED
@@ -1,19 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Yoti
|
4
|
-
class Image
|
5
|
-
attr_reader :content
|
6
|
-
attr_reader :mime_type
|
7
|
-
|
4
|
+
class Image < Media
|
8
5
|
def initialize(content, mime_type)
|
9
|
-
raise(TypeError,
|
10
|
-
|
11
|
-
@content = content
|
12
|
-
@mime_type = mime_type
|
13
|
-
end
|
6
|
+
raise(TypeError, "#{self.class} is an abstract class, so cannot be instantiated") if self.class == Image
|
14
7
|
|
15
|
-
|
16
|
-
"data:#{mime_type};base64,#{Base64.strict_encode64(content)}"
|
8
|
+
super(content, mime_type)
|
17
9
|
end
|
18
10
|
end
|
19
11
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module Yoti
|
6
|
+
class Media
|
7
|
+
attr_reader :content
|
8
|
+
attr_reader :mime_type
|
9
|
+
|
10
|
+
def initialize(content, mime_type)
|
11
|
+
@content = content
|
12
|
+
@mime_type = mime_type
|
13
|
+
end
|
14
|
+
|
15
|
+
def base64_content
|
16
|
+
"data:#{mime_type};base64,#{Base64.strict_encode64(content)}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Yoti
|
4
|
+
module DocScan
|
5
|
+
class Client
|
6
|
+
class << self
|
7
|
+
#
|
8
|
+
# Creates a Doc Scan session using the supplied session specification
|
9
|
+
#
|
10
|
+
# @param [Yoti::DocScan::Session::Create::SessionSpecification] session_specification
|
11
|
+
#
|
12
|
+
# @return [Yoti::DocScan::Session::Create::CreateSessionResult]
|
13
|
+
#
|
14
|
+
def create_session(session_specification)
|
15
|
+
Validation.assert_is_a(
|
16
|
+
Yoti::DocScan::Session::Create::SessionSpecification,
|
17
|
+
session_specification,
|
18
|
+
'session_specification'
|
19
|
+
)
|
20
|
+
|
21
|
+
request = create_request
|
22
|
+
.with_http_method('POST')
|
23
|
+
.with_endpoint('sessions')
|
24
|
+
.with_payload(session_specification)
|
25
|
+
.with_query_param('sdkId', Yoti.configuration.client_sdk_id)
|
26
|
+
.build
|
27
|
+
|
28
|
+
begin
|
29
|
+
Yoti::DocScan::Session::Create::CreateSessionResult.new(JSON.parse(request.execute.body))
|
30
|
+
rescue Yoti::RequestError => e
|
31
|
+
raise Yoti::DocScan::Error.wrap(e)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Retrieves the state of a previously created Yoti Doc Scan session
|
37
|
+
#
|
38
|
+
# @param [String] session_id
|
39
|
+
#
|
40
|
+
# @return [Yoti::DocScan::Session::Retrieve::GetSessionResult]
|
41
|
+
#
|
42
|
+
def get_session(session_id)
|
43
|
+
Validation.assert_is_a(String, session_id, 'session_id')
|
44
|
+
|
45
|
+
request = create_request
|
46
|
+
.with_http_method('GET')
|
47
|
+
.with_endpoint(session_path(session_id))
|
48
|
+
.with_query_param('sdkId', Yoti.configuration.client_sdk_id)
|
49
|
+
.build
|
50
|
+
|
51
|
+
begin
|
52
|
+
Yoti::DocScan::Session::Retrieve::GetSessionResult.new(JSON.parse(request.execute.body))
|
53
|
+
rescue Yoti::RequestError => e
|
54
|
+
raise Yoti::DocScan::Error.wrap(e)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Deletes a previously created Yoti Doc Scan session and all
|
60
|
+
# of its related resources
|
61
|
+
#
|
62
|
+
# @param [String] session_id
|
63
|
+
#
|
64
|
+
def delete_session(session_id)
|
65
|
+
Validation.assert_is_a(String, session_id, 'session_id')
|
66
|
+
|
67
|
+
request = create_request
|
68
|
+
.with_http_method('DELETE')
|
69
|
+
.with_endpoint(session_path(session_id))
|
70
|
+
.with_query_param('sdkId', Yoti.configuration.client_sdk_id)
|
71
|
+
.build
|
72
|
+
|
73
|
+
begin
|
74
|
+
request.execute
|
75
|
+
rescue Yoti::RequestError => e
|
76
|
+
raise Yoti::DocScan::Error.wrap(e)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Retrieves media related to a Yoti Doc Scan session based
|
82
|
+
# on the supplied media ID
|
83
|
+
#
|
84
|
+
# @param [String] session_id
|
85
|
+
# @param [String] media_id
|
86
|
+
#
|
87
|
+
# @return [Yoti::Media]
|
88
|
+
#
|
89
|
+
def get_media_content(session_id, media_id)
|
90
|
+
Validation.assert_is_a(String, session_id, 'session_id')
|
91
|
+
Validation.assert_is_a(String, media_id, 'media_id')
|
92
|
+
|
93
|
+
request = create_request
|
94
|
+
.with_http_method('GET')
|
95
|
+
.with_endpoint(media_path(session_id, media_id))
|
96
|
+
.with_query_param('sdkId', Yoti.configuration.client_sdk_id)
|
97
|
+
.build
|
98
|
+
|
99
|
+
begin
|
100
|
+
response = request.execute
|
101
|
+
|
102
|
+
Yoti::Media.new(
|
103
|
+
response.body,
|
104
|
+
response.get_fields('content-type')[0]
|
105
|
+
)
|
106
|
+
rescue Yoti::RequestError => e
|
107
|
+
raise Yoti::DocScan::Error.wrap(e)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Deletes media related to a Yoti Doc Scan session based
|
113
|
+
# on the supplied media ID
|
114
|
+
#
|
115
|
+
# @param [String] session_id
|
116
|
+
# @param [String] media_id
|
117
|
+
#
|
118
|
+
def delete_media_content(session_id, media_id)
|
119
|
+
Validation.assert_is_a(String, session_id, 'session_id')
|
120
|
+
Validation.assert_is_a(String, media_id, 'media_id')
|
121
|
+
|
122
|
+
request = create_request
|
123
|
+
.with_http_method('DELETE')
|
124
|
+
.with_endpoint(media_path(session_id, media_id))
|
125
|
+
.with_query_param('sdkId', Yoti.configuration.client_sdk_id)
|
126
|
+
.build
|
127
|
+
|
128
|
+
begin
|
129
|
+
request.execute
|
130
|
+
rescue Yoti::RequestError => e
|
131
|
+
raise Yoti::DocScan::Error.wrap(e)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# Gets a list of supported documents.
|
137
|
+
#
|
138
|
+
# @return [Yoti::DocScan::Support::SupportedDocumentsResponse]
|
139
|
+
#
|
140
|
+
def supported_documents
|
141
|
+
request = create_request
|
142
|
+
.with_http_method('GET')
|
143
|
+
.with_endpoint('supported-documents')
|
144
|
+
.build
|
145
|
+
|
146
|
+
begin
|
147
|
+
Yoti::DocScan::Support::SupportedDocumentsResponse.new(JSON.parse(request.execute.body))
|
148
|
+
rescue Yoti::RequestError => e
|
149
|
+
raise Yoti::DocScan::Error.wrap(e)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
#
|
156
|
+
# @param [String] session_id
|
157
|
+
#
|
158
|
+
# @return [String]
|
159
|
+
#
|
160
|
+
def session_path(session_id)
|
161
|
+
"sessions/#{session_id}"
|
162
|
+
end
|
163
|
+
|
164
|
+
#
|
165
|
+
# @param [String] session_id
|
166
|
+
# @param [String] media_id
|
167
|
+
#
|
168
|
+
# @return [String]
|
169
|
+
#
|
170
|
+
def media_path(session_id, media_id)
|
171
|
+
"#{session_path(session_id)}/media/#{media_id}/content"
|
172
|
+
end
|
173
|
+
|
174
|
+
#
|
175
|
+
# Create a base Doc Scan request
|
176
|
+
#
|
177
|
+
# @return [Yoti::Request]
|
178
|
+
#
|
179
|
+
def create_request
|
180
|
+
Yoti::Request
|
181
|
+
.builder
|
182
|
+
.with_base_url(Yoti.configuration.doc_scan_api_endpoint)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Yoti
|
4
|
+
module DocScan
|
5
|
+
class Constants
|
6
|
+
ID_DOCUMENT_AUTHENTICITY = 'ID_DOCUMENT_AUTHENTICITY'
|
7
|
+
ID_DOCUMENT_COMPARISON = 'ID_DOCUMENT_COMPARISON'
|
8
|
+
ID_DOCUMENT_TEXT_DATA_CHECK = 'ID_DOCUMENT_TEXT_DATA_CHECK'
|
9
|
+
ID_DOCUMENT_FACE_MATCH = 'ID_DOCUMENT_FACE_MATCH'
|
10
|
+
LIVENESS = 'LIVENESS'
|
11
|
+
ID_DOCUMENT_TEXT_DATA_EXTRACTION = 'ID_DOCUMENT_TEXT_DATA_EXTRACTION'
|
12
|
+
ID_DOCUMENT = 'ID_DOCUMENT'
|
13
|
+
ORTHOGONAL_RESTRICTIONS = 'ORTHOGONAL_RESTRICTIONS'
|
14
|
+
DOCUMENT_RESTRICTIONS = 'DOCUMENT_RESTRICTIONS'
|
15
|
+
INCLUDE = 'WHITELIST'
|
16
|
+
EXCLUDE = 'BLACKLIST'
|
17
|
+
ALWAYS = 'ALWAYS'
|
18
|
+
FALLBACK = 'FALLBACK'
|
19
|
+
DESIRED = 'DESIRED'
|
20
|
+
IGNORE = 'IGNORE'
|
21
|
+
NEVER = 'NEVER'
|
22
|
+
ZOOM = 'ZOOM'
|
23
|
+
CAMERA = 'CAMERA'
|
24
|
+
CAMERA_AND_UPLOAD = 'CAMERA_AND_UPLOAD'
|
25
|
+
RESOURCE_UPDATE = 'RESOURCE_UPDATE'
|
26
|
+
TASK_COMPLETION = 'TASK_COMPLETION'
|
27
|
+
CHECK_COMPLETION = 'CHECK_COMPLETION'
|
28
|
+
SESSION_COMPLETION = 'SESSION_COMPLETION'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Yoti
|
4
|
+
module DocScan
|
5
|
+
#
|
6
|
+
# Raises exceptions related to Doc Scan API requests
|
7
|
+
#
|
8
|
+
class Error < RequestError
|
9
|
+
def initialize(msg = nil, response = nil)
|
10
|
+
super(msg, response)
|
11
|
+
|
12
|
+
@default_message = msg
|
13
|
+
end
|
14
|
+
|
15
|
+
def message
|
16
|
+
@message ||= format_message
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Wraps an existing error
|
21
|
+
#
|
22
|
+
# @param [Error] error
|
23
|
+
#
|
24
|
+
# @return [self]
|
25
|
+
#
|
26
|
+
def self.wrap(error)
|
27
|
+
new(error.message, error.response)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
#
|
33
|
+
# Formats error message from response.
|
34
|
+
#
|
35
|
+
# @return [String]
|
36
|
+
#
|
37
|
+
def format_message
|
38
|
+
return @default_message if @response.nil? || @response['Content-Type'] != 'application/json'
|
39
|
+
|
40
|
+
json = JSON.parse(@response.body)
|
41
|
+
format_response(json) || @default_message
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Format JSON error response.
|
46
|
+
#
|
47
|
+
# @param [Hash] json
|
48
|
+
#
|
49
|
+
# @return [String, nil]
|
50
|
+
#
|
51
|
+
def format_response(json)
|
52
|
+
return nil if json['code'].nil? || json['message'].nil?
|
53
|
+
|
54
|
+
code_message = "#{json['code']} - #{json['message']}"
|
55
|
+
|
56
|
+
unless json['errors'].nil?
|
57
|
+
property_errors = format_property_errors(json['errors'])
|
58
|
+
|
59
|
+
return "#{code_message}: #{property_errors.compact.join(', ')}" if property_errors.count.positive?
|
60
|
+
end
|
61
|
+
|
62
|
+
code_message
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Format property errors.
|
67
|
+
#
|
68
|
+
# @param [Array<Hash>] errors
|
69
|
+
#
|
70
|
+
# @return [Array<String>]
|
71
|
+
#
|
72
|
+
def format_property_errors(errors)
|
73
|
+
errors
|
74
|
+
.map do |e|
|
75
|
+
"#{e['property']} \"#{e['message']}\"" if e['property'] && e['message']
|
76
|
+
end
|
77
|
+
.compact
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Yoti
|
4
|
+
module DocScan
|
5
|
+
module Session
|
6
|
+
module Create
|
7
|
+
#
|
8
|
+
# The response to a successful CreateSession call
|
9
|
+
#
|
10
|
+
class CreateSessionResult
|
11
|
+
#
|
12
|
+
# Returns the time-to-live (TTL) for the client session
|
13
|
+
# token for the created session
|
14
|
+
#
|
15
|
+
# @return [Integer]
|
16
|
+
#
|
17
|
+
attr_reader :client_session_token_ttl
|
18
|
+
|
19
|
+
#
|
20
|
+
# Returns the client session token for the created session
|
21
|
+
#
|
22
|
+
# @return [String]
|
23
|
+
#
|
24
|
+
attr_reader :client_session_token
|
25
|
+
|
26
|
+
#
|
27
|
+
# Session ID of the created session
|
28
|
+
#
|
29
|
+
# @return [String]
|
30
|
+
#
|
31
|
+
attr_reader :session_id
|
32
|
+
|
33
|
+
#
|
34
|
+
# @param [Hash] response
|
35
|
+
#
|
36
|
+
def initialize(response)
|
37
|
+
Validation.assert_is_a(Integer, response['client_session_token_ttl'], 'client_session_token_ttl', true)
|
38
|
+
@client_session_token_ttl = response['client_session_token_ttl']
|
39
|
+
|
40
|
+
Validation.assert_is_a(String, response['client_session_token'], 'client_session_token', true)
|
41
|
+
@client_session_token = response['client_session_token']
|
42
|
+
|
43
|
+
Validation.assert_is_a(String, response['session_id'], 'session_id', true)
|
44
|
+
@session_id = response['session_id']
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Yoti
|
4
|
+
module DocScan
|
5
|
+
module Session
|
6
|
+
module Create
|
7
|
+
class DocumentFilter
|
8
|
+
#
|
9
|
+
# @param [String] type
|
10
|
+
#
|
11
|
+
def initialize(type)
|
12
|
+
raise(TypeError, "#{self.class} cannot be instantiated") if self.class == DocumentFilter
|
13
|
+
|
14
|
+
Validation.assert_is_a(String, type, 'type')
|
15
|
+
@type = type
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_json(*_args)
|
19
|
+
as_json.to_json
|
20
|
+
end
|
21
|
+
|
22
|
+
def as_json(*_args)
|
23
|
+
{
|
24
|
+
type: @type
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|