yoti 1.6.3 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -224
  3. data/lib/yoti.rb +54 -1
  4. data/lib/yoti/client.rb +13 -4
  5. data/lib/yoti/configuration.rb +7 -2
  6. data/lib/yoti/data_type/age_verification.rb +1 -1
  7. data/lib/yoti/data_type/base_profile.rb +1 -1
  8. data/lib/yoti/data_type/image.rb +4 -12
  9. data/lib/yoti/data_type/image_jpeg.rb +2 -0
  10. data/lib/yoti/data_type/image_png.rb +2 -0
  11. data/lib/yoti/data_type/media.rb +19 -0
  12. data/lib/yoti/data_type/signed_time_stamp.rb +1 -1
  13. data/lib/yoti/doc_scan/client.rb +187 -0
  14. data/lib/yoti/doc_scan/constants.rb +31 -0
  15. data/lib/yoti/doc_scan/errors.rb +81 -0
  16. data/lib/yoti/doc_scan/session/create/create_session_result.rb +50 -0
  17. data/lib/yoti/doc_scan/session/create/document_filter.rb +31 -0
  18. data/lib/yoti/doc_scan/session/create/document_restrictions_filter.rb +140 -0
  19. data/lib/yoti/doc_scan/session/create/notification_config.rb +142 -0
  20. data/lib/yoti/doc_scan/session/create/orthogonal_restrictions_filter.rb +150 -0
  21. data/lib/yoti/doc_scan/session/create/requested_check.rb +39 -0
  22. data/lib/yoti/doc_scan/session/create/requested_document_authenticity_check.rb +95 -0
  23. data/lib/yoti/doc_scan/session/create/requested_face_match_check.rb +95 -0
  24. data/lib/yoti/doc_scan/session/create/requested_id_document_comparison_check.rb +53 -0
  25. data/lib/yoti/doc_scan/session/create/requested_liveness_check.rb +108 -0
  26. data/lib/yoti/doc_scan/session/create/requested_task.rb +39 -0
  27. data/lib/yoti/doc_scan/session/create/requested_text_extraction_task.rb +116 -0
  28. data/lib/yoti/doc_scan/session/create/required_document.rb +31 -0
  29. data/lib/yoti/doc_scan/session/create/required_id_document.rb +53 -0
  30. data/lib/yoti/doc_scan/session/create/sdk_config.rb +221 -0
  31. data/lib/yoti/doc_scan/session/create/session_specification.rb +221 -0
  32. data/lib/yoti/doc_scan/session/retrieve/authenticity_check_response.rb +12 -0
  33. data/lib/yoti/doc_scan/session/retrieve/breakdown_response.rb +38 -0
  34. data/lib/yoti/doc_scan/session/retrieve/check_response.rb +63 -0
  35. data/lib/yoti/doc_scan/session/retrieve/details_response.rb +28 -0
  36. data/lib/yoti/doc_scan/session/retrieve/document_fields_response.rb +21 -0
  37. data/lib/yoti/doc_scan/session/retrieve/document_id_photo_response.rb +21 -0
  38. data/lib/yoti/doc_scan/session/retrieve/face_map_response.rb +21 -0
  39. data/lib/yoti/doc_scan/session/retrieve/face_match_check_response.rb +12 -0
  40. data/lib/yoti/doc_scan/session/retrieve/frame_response.rb +21 -0
  41. data/lib/yoti/doc_scan/session/retrieve/generated_check_response.rb +28 -0
  42. data/lib/yoti/doc_scan/session/retrieve/generated_media.rb +28 -0
  43. data/lib/yoti/doc_scan/session/retrieve/generated_text_data_check_response.rb +12 -0
  44. data/lib/yoti/doc_scan/session/retrieve/get_session_result.rb +127 -0
  45. data/lib/yoti/doc_scan/session/retrieve/id_document_comparison_check_response.rb +12 -0
  46. data/lib/yoti/doc_scan/session/retrieve/id_document_resource_response.rb +57 -0
  47. data/lib/yoti/doc_scan/session/retrieve/liveness_check_response.rb +12 -0
  48. data/lib/yoti/doc_scan/session/retrieve/liveness_resource_response.rb +24 -0
  49. data/lib/yoti/doc_scan/session/retrieve/media_response.rb +38 -0
  50. data/lib/yoti/doc_scan/session/retrieve/page_response.rb +27 -0
  51. data/lib/yoti/doc_scan/session/retrieve/recommendation_response.rb +34 -0
  52. data/lib/yoti/doc_scan/session/retrieve/report_response.rb +31 -0
  53. data/lib/yoti/doc_scan/session/retrieve/resource_container.rb +50 -0
  54. data/lib/yoti/doc_scan/session/retrieve/resource_response.rb +39 -0
  55. data/lib/yoti/doc_scan/session/retrieve/task_response.rb +87 -0
  56. data/lib/yoti/doc_scan/session/retrieve/text_data_check_response.rb +12 -0
  57. data/lib/yoti/doc_scan/session/retrieve/text_extraction_task_response.rb +18 -0
  58. data/lib/yoti/doc_scan/session/retrieve/zoom_liveness_resource_response.rb +33 -0
  59. data/lib/yoti/doc_scan/support/supported_documents.rb +60 -0
  60. data/lib/yoti/dynamic_share_service/extension/thirdparty_attribute_extension.rb +62 -11
  61. data/lib/yoti/dynamic_share_service/policy/dynamic_policy.rb +84 -22
  62. data/lib/yoti/dynamic_share_service/share_url.rb +28 -33
  63. data/lib/yoti/errors.rb +15 -2
  64. data/lib/yoti/http/aml_check_request.rb +12 -6
  65. data/lib/yoti/http/payloads/aml_address.rb +4 -0
  66. data/lib/yoti/http/payloads/aml_profile.rb +7 -1
  67. data/lib/yoti/http/profile_request.rb +11 -6
  68. data/lib/yoti/http/request.rb +221 -18
  69. data/lib/yoti/http/signed_request.rb +13 -4
  70. data/lib/yoti/protobuf/main.rb +1 -1
  71. data/lib/yoti/ssl.rb +2 -2
  72. data/lib/yoti/util/anchor_processor.rb +1 -1
  73. data/lib/yoti/util/validation.rb +41 -0
  74. data/lib/yoti/version.rb +1 -1
  75. data/yoti.gemspec +19 -9
  76. metadata +60 -67
  77. data/.github/ISSUE_TEMPLATE.md +0 -17
  78. data/.gitignore +0 -39
  79. data/CONTRIBUTING.md +0 -127
  80. data/Guardfile +0 -11
  81. data/Rakefile +0 -49
  82. data/login_flow.png +0 -0
  83. data/rubocop.yml +0 -57
  84. data/yardstick.yml +0 -9
@@ -1,19 +1,11 @@
1
- require 'base64'
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, 'Image is an abstract class, so cannot be instantiated') if self.class == Yoti::Image
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
- def base64_content
16
- "data:#{mime_type};base64,#{Base64.strict_encode64(content)}"
8
+ super(content, mime_type)
17
9
  end
18
10
  end
19
11
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Yoti
2
4
  class ImageJpeg < Image
3
5
  def initialize(content)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Yoti
2
4
  class ImagePng < Image
3
5
  def initialize(content)
@@ -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
@@ -5,7 +5,7 @@ module Yoti
5
5
 
6
6
  def initialize(version, time_stamp)
7
7
  @version = version
8
- @time_stamp = time_stamp
8
+ @time_stamp = time_stamp.utc
9
9
  end
10
10
  end
11
11
  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