yoti 1.6.1 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE.md +17 -0
  3. data/.gitignore +1 -0
  4. data/CONTRIBUTING.md +1 -30
  5. data/README.md +23 -224
  6. data/Rakefile +9 -8
  7. data/lib/yoti.rb +50 -1
  8. data/lib/yoti/activity_details.rb +1 -0
  9. data/lib/yoti/client.rb +13 -4
  10. data/lib/yoti/configuration.rb +7 -2
  11. data/lib/yoti/data_type/age_verification.rb +1 -1
  12. data/lib/yoti/data_type/base_profile.rb +1 -1
  13. data/lib/yoti/data_type/document_details.rb +5 -13
  14. data/lib/yoti/data_type/image.rb +4 -12
  15. data/lib/yoti/data_type/image_jpeg.rb +2 -0
  16. data/lib/yoti/data_type/image_png.rb +2 -0
  17. data/lib/yoti/data_type/media.rb +19 -0
  18. data/lib/yoti/doc_scan/client.rb +163 -0
  19. data/lib/yoti/doc_scan/constants.rb +28 -0
  20. data/lib/yoti/doc_scan/session/create/create_session_result.rb +50 -0
  21. data/lib/yoti/doc_scan/session/create/document_filter.rb +31 -0
  22. data/lib/yoti/doc_scan/session/create/document_restrictions_filter.rb +140 -0
  23. data/lib/yoti/doc_scan/session/create/notification_config.rb +142 -0
  24. data/lib/yoti/doc_scan/session/create/orthogonal_restrictions_filter.rb +150 -0
  25. data/lib/yoti/doc_scan/session/create/requested_check.rb +39 -0
  26. data/lib/yoti/doc_scan/session/create/requested_document_authenticity_check.rb +53 -0
  27. data/lib/yoti/doc_scan/session/create/requested_face_match_check.rb +95 -0
  28. data/lib/yoti/doc_scan/session/create/requested_liveness_check.rb +108 -0
  29. data/lib/yoti/doc_scan/session/create/requested_task.rb +39 -0
  30. data/lib/yoti/doc_scan/session/create/requested_text_extraction_task.rb +94 -0
  31. data/lib/yoti/doc_scan/session/create/required_document.rb +31 -0
  32. data/lib/yoti/doc_scan/session/create/required_id_document.rb +53 -0
  33. data/lib/yoti/doc_scan/session/create/sdk_config.rb +221 -0
  34. data/lib/yoti/doc_scan/session/create/session_specification.rb +203 -0
  35. data/lib/yoti/doc_scan/session/retrieve/authenticity_check_response.rb +12 -0
  36. data/lib/yoti/doc_scan/session/retrieve/breakdown_response.rb +38 -0
  37. data/lib/yoti/doc_scan/session/retrieve/check_response.rb +63 -0
  38. data/lib/yoti/doc_scan/session/retrieve/details_response.rb +28 -0
  39. data/lib/yoti/doc_scan/session/retrieve/document_fields_response.rb +21 -0
  40. data/lib/yoti/doc_scan/session/retrieve/face_map_response.rb +21 -0
  41. data/lib/yoti/doc_scan/session/retrieve/face_match_check_response.rb +12 -0
  42. data/lib/yoti/doc_scan/session/retrieve/frame_response.rb +21 -0
  43. data/lib/yoti/doc_scan/session/retrieve/generated_check_response.rb +28 -0
  44. data/lib/yoti/doc_scan/session/retrieve/generated_media.rb +28 -0
  45. data/lib/yoti/doc_scan/session/retrieve/generated_text_data_check_response.rb +12 -0
  46. data/lib/yoti/doc_scan/session/retrieve/get_session_result.rb +113 -0
  47. data/lib/yoti/doc_scan/session/retrieve/id_document_resource_response.rb +52 -0
  48. data/lib/yoti/doc_scan/session/retrieve/liveness_check_response.rb +12 -0
  49. data/lib/yoti/doc_scan/session/retrieve/liveness_resource_response.rb +24 -0
  50. data/lib/yoti/doc_scan/session/retrieve/media_response.rb +38 -0
  51. data/lib/yoti/doc_scan/session/retrieve/page_response.rb +27 -0
  52. data/lib/yoti/doc_scan/session/retrieve/recommendation_response.rb +34 -0
  53. data/lib/yoti/doc_scan/session/retrieve/report_response.rb +31 -0
  54. data/lib/yoti/doc_scan/session/retrieve/resource_container.rb +50 -0
  55. data/lib/yoti/doc_scan/session/retrieve/resource_response.rb +39 -0
  56. data/lib/yoti/doc_scan/session/retrieve/task_response.rb +87 -0
  57. data/lib/yoti/doc_scan/session/retrieve/text_data_check_response.rb +12 -0
  58. data/lib/yoti/doc_scan/session/retrieve/text_extraction_task_response.rb +18 -0
  59. data/lib/yoti/doc_scan/session/retrieve/zoom_liveness_resource_response.rb +33 -0
  60. data/lib/yoti/doc_scan/support/supported_documents.rb +60 -0
  61. data/lib/yoti/dynamic_share_service/extension/thirdparty_attribute_extension.rb +62 -11
  62. data/lib/yoti/dynamic_share_service/policy/dynamic_policy.rb +17 -17
  63. data/lib/yoti/dynamic_share_service/share_url.rb +28 -33
  64. data/lib/yoti/errors.rb +17 -2
  65. data/lib/yoti/http/aml_check_request.rb +12 -6
  66. data/lib/yoti/http/payloads/aml_address.rb +4 -0
  67. data/lib/yoti/http/payloads/aml_profile.rb +7 -1
  68. data/lib/yoti/http/profile_request.rb +11 -6
  69. data/lib/yoti/http/request.rb +221 -18
  70. data/lib/yoti/http/signed_request.rb +13 -4
  71. data/lib/yoti/protobuf/main.rb +1 -1
  72. data/lib/yoti/ssl.rb +3 -2
  73. data/lib/yoti/util/anchor_processor.rb +1 -1
  74. data/lib/yoti/util/validation.rb +41 -0
  75. data/lib/yoti/version.rb +1 -1
  76. data/rubocop.yml +9 -1
  77. data/yoti.gemspec +5 -8
  78. metadata +53 -63
  79. data/lib/yoti/sandbox.rb +0 -5
  80. data/lib/yoti/sandbox/anchor.rb +0 -49
  81. data/lib/yoti/sandbox/attribute.rb +0 -52
  82. data/lib/yoti/sandbox/profile.rb +0 -171
  83. data/lib/yoti/sandbox/sandbox.rb +0 -105
  84. data/lib/yoti/sandbox/sandbox_client.rb +0 -45
  85. data/login_flow.png +0 -0
@@ -1,4 +1,5 @@
1
1
  require 'net/http'
2
+ require 'time'
2
3
 
3
4
  module Yoti
4
5
  #
@@ -1,15 +1,17 @@
1
1
  module Yoti
2
2
  #
3
- # Handles all the publicly accesible Yoti methods for
4
- # geting data using an encrypted connect token
3
+ # Handles all the publicly accessible Yoti methods for
4
+ # getting data using an encrypted connect token
5
5
  #
6
6
  module Client
7
7
  #
8
8
  # Performs all the steps required to get the decrypted profile from an API request
9
9
  #
10
- # @param encrypted_connect_token [String] token provided as a base 64 string
10
+ # @param [String] encrypted_connect_token
11
+ # Token provided as a base 64 string
11
12
  #
12
- # @return [Object] an ActivityDetails instance encapsulating the user profile
13
+ # @return [ActivityDetails]
14
+ # An ActivityDetails instance encapsulating the user profile
13
15
  #
14
16
  def self.get_activity_details(encrypted_connect_token)
15
17
  receipt = Yoti::ProfileRequest.new(encrypted_connect_token).receipt
@@ -22,6 +24,13 @@ module Yoti
22
24
  ActivityDetails.new(receipt, user_profile, application_profile, extra_data)
23
25
  end
24
26
 
27
+ #
28
+ # Perform AML check
29
+ #
30
+ # @param [AmlProfile] aml_profile
31
+ #
32
+ # @return [<Hash>]
33
+ #
25
34
  def self.aml_check(aml_profile)
26
35
  Yoti::AmlCheckRequest.new(aml_profile).response
27
36
  end
@@ -3,7 +3,7 @@ module Yoti
3
3
  attr_accessor :client_sdk_id, :key_file_path, :key, :sdk_identifier,
4
4
  :api_url, :api_port, :api_version
5
5
 
6
- attr_writer :api_endpoint
6
+ attr_writer :api_endpoint, :doc_scan_api_endpoint
7
7
 
8
8
  # Set config variables by using a configuration block
9
9
  def initialize
@@ -18,7 +18,12 @@ module Yoti
18
18
 
19
19
  # @return [String] the API endpoint for the selected API version
20
20
  def api_endpoint
21
- @api_endpoint ||= "#{@api_url}/api/#{@api_version}"
21
+ @api_endpoint ||= ENV['YOTI_API_URL'] || "#{@api_url}/api/#{@api_version}"
22
+ end
23
+
24
+ # @return [String] the Doc Scan API endpoint
25
+ def doc_scan_api_endpoint
26
+ @doc_scan_api_endpoint ||= ENV['YOTI_DOC_SCAN_API_URL'] || "#{@api_url}/idverify/#{@api_version}"
22
27
  end
23
28
 
24
29
  # Validates the configuration values set in instance variables
@@ -37,7 +37,7 @@ module Yoti
37
37
  attr_reader :age
38
38
 
39
39
  #
40
- # @param [Yoti::Attribute]
40
+ # @param [Yoti::Attribute] attribute
41
41
  #
42
42
  def initialize(attribute)
43
43
  raise(ArgumentError, "'#{attribute.name}' is not a valid age verification") unless /^[^:]+:(?!.*:)[0-9]+$/.match?(attribute.name)
@@ -37,7 +37,7 @@ module Yoti
37
37
  #
38
38
  # @param [String] name
39
39
  #
40
- # @returns [Array]
40
+ # @return [Array]
41
41
  #
42
42
  def find_attributes_starting_with(name)
43
43
  @attributes.select { |key| key.to_s.start_with?(name) }
@@ -1,10 +1,10 @@
1
1
  module Yoti
2
2
  class DocumentDetails
3
3
  #
4
- # The values of the Document Details are in the format and order as defined in this pattern
5
- # e.g PASS_CARD GBR 22719564893 - CITIZENCARD, the last two are optionals
4
+ # @deprecated 2.0.0 pattern is no longer used for validation.
6
5
  #
7
6
  VALIDATION_PATTERN = '^([A-Za-z_]*) ([A-Za-z]{3}) ([A-Za-z0-9]{1}).*$'
7
+
8
8
  TYPE_INDEX = 0
9
9
  COUNTRY_INDEX = 1
10
10
  NUMBER_INDEX = 2
@@ -51,28 +51,20 @@ module Yoti
51
51
  # @param [String] value
52
52
  #
53
53
  def initialize(value)
54
- validate_value(value)
55
54
  parse_value(value)
56
55
  end
57
56
 
58
57
  private
59
58
 
60
- #
61
- # Asserts provided matches VALIDATION_PATTERN
62
- #
63
- # @param [String] value
64
- #
65
- def validate_value(value)
66
- raise(ArgumentError, "Invalid value for #{self.class.name}") unless /#{VALIDATION_PATTERN}/.match?(value)
67
- end
68
-
69
59
  #
70
60
  # Parses provided value into separate attributes
71
61
  #
72
62
  # @param [String] value
73
63
  #
74
64
  def parse_value(value)
75
- attributes = value.split(' ')
65
+ attributes = value.split(/ /)
66
+ raise(ArgumentError, "Invalid value for #{self.class.name}") if attributes.length < 3 || attributes.include?('')
67
+
76
68
  @type = attributes[TYPE_INDEX]
77
69
  @issuing_country = attributes[COUNTRY_INDEX]
78
70
  @document_number = attributes[NUMBER_INDEX]
@@ -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
@@ -0,0 +1,163 @@
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
+ response = 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
+ .execute
28
+
29
+ Yoti::DocScan::Session::Create::CreateSessionResult.new(JSON.parse(response.body))
30
+ end
31
+
32
+ #
33
+ # Retrieves the state of a previously created Yoti Doc Scan session
34
+ #
35
+ # @param [String] session_id
36
+ #
37
+ # @return [Yoti::DocScan::Session::Retrieve::GetSessionResult]
38
+ #
39
+ def get_session(session_id)
40
+ Validation.assert_is_a(String, session_id, 'session_id')
41
+
42
+ response = create_request
43
+ .with_http_method('GET')
44
+ .with_endpoint(session_path(session_id))
45
+ .with_query_param('sdkId', Yoti.configuration.client_sdk_id)
46
+ .build
47
+ .execute
48
+
49
+ Yoti::DocScan::Session::Retrieve::GetSessionResult.new(JSON.parse(response.body))
50
+ end
51
+
52
+ #
53
+ # Deletes a previously created Yoti Doc Scan session and all
54
+ # of its related resources
55
+ #
56
+ # @param [String] session_id
57
+ #
58
+ def delete_session(session_id)
59
+ Validation.assert_is_a(String, session_id, 'session_id')
60
+
61
+ create_request
62
+ .with_http_method('DELETE')
63
+ .with_endpoint(session_path(session_id))
64
+ .with_query_param('sdkId', Yoti.configuration.client_sdk_id)
65
+ .build
66
+ .execute
67
+ end
68
+
69
+ #
70
+ # Retrieves media related to a Yoti Doc Scan session based
71
+ # on the supplied media ID
72
+ #
73
+ # @param [String] session_id
74
+ # @param [String] media_id
75
+ #
76
+ # @return [Yoti::Media]
77
+ #
78
+ def get_media_content(session_id, media_id)
79
+ Validation.assert_is_a(String, session_id, 'session_id')
80
+ Validation.assert_is_a(String, media_id, 'media_id')
81
+
82
+ response = create_request
83
+ .with_http_method('GET')
84
+ .with_endpoint(media_path(session_id, media_id))
85
+ .with_query_param('sdkId', Yoti.configuration.client_sdk_id)
86
+ .build
87
+ .execute
88
+
89
+ Yoti::Media.new(
90
+ response.body,
91
+ response.get_fields('content-type')[0]
92
+ )
93
+ end
94
+
95
+ #
96
+ # Deletes media related to a Yoti Doc Scan session based
97
+ # on the supplied media ID
98
+ #
99
+ # @param [String] session_id
100
+ # @param [String] media_id
101
+ #
102
+ def delete_media_content(session_id, media_id)
103
+ Validation.assert_is_a(String, session_id, 'session_id')
104
+ Validation.assert_is_a(String, media_id, 'media_id')
105
+
106
+ create_request
107
+ .with_http_method('DELETE')
108
+ .with_endpoint(media_path(session_id, media_id))
109
+ .with_query_param('sdkId', Yoti.configuration.client_sdk_id)
110
+ .build
111
+ .execute
112
+ end
113
+
114
+ #
115
+ # Gets a list of supported documents.
116
+ #
117
+ # @return [Yoti::DocScan::Support::SupportedDocumentsResponse]
118
+ #
119
+ def supported_documents
120
+ response = create_request
121
+ .with_http_method('GET')
122
+ .with_endpoint('supported-documents')
123
+ .build
124
+ .execute
125
+
126
+ Yoti::DocScan::Support::SupportedDocumentsResponse.new(JSON.parse(response.body))
127
+ end
128
+
129
+ private
130
+
131
+ #
132
+ # @param [String] session_id
133
+ #
134
+ # @return [String]
135
+ #
136
+ def session_path(session_id)
137
+ "sessions/#{session_id}"
138
+ end
139
+
140
+ #
141
+ # @param [String] session_id
142
+ # @param [String] media_id
143
+ #
144
+ # @return [String]
145
+ #
146
+ def media_path(session_id, media_id)
147
+ "#{session_path(session_id)}/media/#{media_id}/content"
148
+ end
149
+
150
+ #
151
+ # Create a base Doc Scan request
152
+ #
153
+ # @return [Yoti::Request]
154
+ #
155
+ def create_request
156
+ Yoti::Request
157
+ .builder
158
+ .with_base_url(Yoti.configuration.doc_scan_api_endpoint)
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,28 @@
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_TEXT_DATA_CHECK = 'ID_DOCUMENT_TEXT_DATA_CHECK'
8
+ ID_DOCUMENT_FACE_MATCH = 'ID_DOCUMENT_FACE_MATCH'
9
+ LIVENESS = 'LIVENESS'
10
+ ID_DOCUMENT_TEXT_DATA_EXTRACTION = 'ID_DOCUMENT_TEXT_DATA_EXTRACTION'
11
+ ID_DOCUMENT = 'ID_DOCUMENT'
12
+ ORTHOGONAL_RESTRICTIONS = 'ORTHOGONAL_RESTRICTIONS'
13
+ DOCUMENT_RESTRICTIONS = 'DOCUMENT_RESTRICTIONS'
14
+ INCLUDE = 'WHITELIST'
15
+ EXCLUDE = 'BLACKLIST'
16
+ ALWAYS = 'ALWAYS'
17
+ FALLBACK = 'FALLBACK'
18
+ NEVER = 'NEVER'
19
+ ZOOM = 'ZOOM'
20
+ CAMERA = 'CAMERA'
21
+ CAMERA_AND_UPLOAD = 'CAMERA_AND_UPLOAD'
22
+ RESOURCE_UPDATE = 'RESOURCE_UPDATE'
23
+ TASK_COMPLETION = 'TASK_COMPLETION'
24
+ CHECK_COMPLETION = 'CHECK_COMPLETION'
25
+ SESSION_COMPLETION = 'SESSION_COMPLETION'
26
+ end
27
+ end
28
+ 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