yoti 1.4.0 → 1.5.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/README.md +25 -14
- data/lib/yoti.rb +2 -0
- data/lib/yoti/activity_details.rb +123 -21
- data/lib/yoti/client.rb +10 -6
- data/lib/yoti/configuration.rb +2 -0
- data/lib/yoti/data_type/anchor.rb +56 -2
- data/lib/yoti/data_type/application_profile.rb +43 -0
- data/lib/yoti/data_type/attribute.rb +76 -3
- data/lib/yoti/data_type/base_profile.rb +33 -0
- data/lib/yoti/data_type/profile.rb +70 -13
- data/lib/yoti/http/signed_request.rb +1 -0
- data/lib/yoti/protobuf/main.rb +28 -3
- data/lib/yoti/util/anchor_processor.rb +190 -24
- data/lib/yoti/version.rb +1 -1
- data/rubocop.yml +3 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00ff1a296c371b2d5e94ccd5e0951963ff8cbcf9676717724369567e39ef1652
|
4
|
+
data.tar.gz: e80cb02c9f2cd4b9fdab9ac59de05aeee58cdc1066229a0bde35f4310052d562
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74652cb02c63be28c4296c47e073f756baf3836289cf71f646949a36d870716a7851dbe2c4c78f9fb3b771e08213d6035e1bb2508a0a4fbae340d1964d4754a5
|
7
|
+
data.tar.gz: '019dd78cc18bdfeb6bb2b852cd3ae8331062f4a5d7af312882aa143818af75ea7fc7e15e3dddf96d30c32b208c13a56327eeebc509415502a888442bd45e7b4b'
|
data/README.md
CHANGED
@@ -19,7 +19,7 @@ Welcome to the Yoti Ruby SDK. This repository contains the tools you need to qui
|
|
19
19
|
## An Architectural view
|
20
20
|
|
21
21
|
To integrate your application with Yoti, your back-end must expose a GET endpoint that Yoti will use to forward tokens.
|
22
|
-
The endpoint is configured in the [Yoti
|
22
|
+
The endpoint is configured in the [Yoti Hub](https://hub.yoti.com) where you create/update your application. To see an example of how this is configured, see the [Running the Examples](#running-the-examples) section.
|
23
23
|
|
24
24
|
The image below shows how your application back-end and Yoti integrate into the context of a Login flow.
|
25
25
|
Yoti SDK carries out for you steps 6, 7, 8 and the profile decryption in step 9.
|
@@ -98,7 +98,7 @@ end
|
|
98
98
|
|
99
99
|
Make sure the following environment variables can be accessed by your app:
|
100
100
|
|
101
|
-
`YOTI_CLIENT_SDK_ID` - found on the Key settings page on your
|
101
|
+
`YOTI_CLIENT_SDK_ID` - found on the Key settings page on your Yoti Hub
|
102
102
|
|
103
103
|
`YOTI_KEY_FILE_PATH` - the full path to your security key downloaded from the *Keys* settings page (e.g. /Users/developer/access-security.pem)
|
104
104
|
|
@@ -161,7 +161,7 @@ else
|
|
161
161
|
end
|
162
162
|
```
|
163
163
|
|
164
|
-
The `profile` object provides a set of attributes corresponding to user attributes. Whether the attributes are present or not depends on the settings you have applied to your app on Yoti
|
164
|
+
The `profile` object provides a set of attributes corresponding to user attributes. Whether the attributes are present or not depends on the settings you have applied to your app on Yoti Hub.
|
165
165
|
|
166
166
|
### Handling Users
|
167
167
|
|
@@ -194,17 +194,19 @@ Where `your_user_search_function` is a piece of logic in your app that is suppos
|
|
194
194
|
You can retrieve the sources and verifiers for each attribute as follows:
|
195
195
|
|
196
196
|
```ruby
|
197
|
-
given_names_sources = profile.given_names.sources
|
198
|
-
given_names_verifiers = profile.given_names.verifiers
|
197
|
+
given_names_sources = profile.given_names.sources # list of anchors
|
198
|
+
given_names_verifiers = profile.given_names.verifiers # list of anchors
|
199
|
+
given_names_anchors = profile.given_names.anchors # list of anchors
|
199
200
|
```
|
200
201
|
You can also retrieve further properties from these respective anchors in the following way:
|
201
202
|
|
202
203
|
```ruby
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
204
|
+
# Retrieving properties of the first anchor
|
205
|
+
type = given_names_sources[0].type # string
|
206
|
+
value = given_names_sources[0].value # string
|
207
|
+
sub_type = given_names_sources[0].sub_type # string
|
208
|
+
time_stamp = given_names_sources[0].signed_time_stamp.time_stamp # DateTime object
|
209
|
+
origin_server_certs = given_names_sources[0].origin_server_certs # list of X509 certificates
|
208
210
|
```
|
209
211
|
|
210
212
|
In case you want to prove the sources and verifiers of the helper`ActivityDetails.age_verified` on `Age Over 18` set as age derivation, please retrieve it's original attribute from the profile as follow:
|
@@ -213,6 +215,7 @@ In case you want to prove the sources and verifiers of the helper`ActivityDetail
|
|
213
215
|
age_attribute = profile.get_attribute('age_over:18')
|
214
216
|
sources = age_attribute.sources
|
215
217
|
verifiers = age_attribute.verifiers
|
218
|
+
anchors = age_attribute.anchors
|
216
219
|
```
|
217
220
|
|
218
221
|
## AML Integration
|
@@ -225,11 +228,11 @@ Yoti will provide a boolean result on the following checks:
|
|
225
228
|
* Fraud list - Verify against US Social Security Administration Fraud (SSN Fraud) list
|
226
229
|
* Watch list - Verify against watch lists from the Office of Foreign Assets Control
|
227
230
|
|
228
|
-
To use this functionality you must ensure your application is assigned to your organisation in the Yoti
|
231
|
+
To use this functionality you must ensure your application is assigned to your organisation in the Yoti Hub - please see [here](https://developers.yoti.com/yoti-app-integration/yoti-app-integration#step-1-creating-an-organisation) for further information.
|
229
232
|
|
230
233
|
For the AML check you will need to provide the following:
|
231
234
|
|
232
|
-
* Data provided by Yoti (please ensure you have selected the Given name(s) and Family name attributes
|
235
|
+
* Data provided by Yoti (please ensure you have selected the Given name(s) and Family name attributes for your scenario on the Yoti Hub)
|
233
236
|
* Given name(s)
|
234
237
|
* Family name
|
235
238
|
* Data that must be collected from the user:
|
@@ -266,7 +269,7 @@ The examples can be found in the [examples folder](examples).
|
|
266
269
|
|
267
270
|
### Ruby on Rails
|
268
271
|
|
269
|
-
1. Create your application in the [Yoti
|
272
|
+
1. Create your application in the [Yoti Hub](https://hub.yoti.com)
|
270
273
|
1. Set the application domain of your app to `localhost:3000`
|
271
274
|
1. Set the scenario callback URL to `/profile`
|
272
275
|
1. Rename the [.env.example](examples/rails/.env.example) file to `.env`
|
@@ -282,7 +285,7 @@ Visiting `https://localhost:3001/` should show a Yoti Connect button
|
|
282
285
|
|
283
286
|
### Sinatra
|
284
287
|
|
285
|
-
1. Create your application in the [Yoti
|
288
|
+
1. Create your application in the [Yoti Hub](https://hub.yoti.com)
|
286
289
|
1. Set the application domain of your app to `localhost:4567`
|
287
290
|
1. Set the scenario callback URL to `/profile`
|
288
291
|
1. Rename the [.env.example](examples/sinatra/.env.example) file to `.env`
|
@@ -307,6 +310,8 @@ Visiting `https://localhost:4567/` should show a Yoti Connect button
|
|
307
310
|
* Activity Details
|
308
311
|
* [X] Remember Me ID `remember_me_id`
|
309
312
|
* [X] Parent Remember Me ID `parent_remember_me_id`
|
313
|
+
* [X] Receipt ID `receipt_id`
|
314
|
+
* [X] Timestamp `timestamp`
|
310
315
|
* [X] Base64 Selfie URI `base64_selfie_uri`
|
311
316
|
* [X] Age verified `age_verified`
|
312
317
|
* [X] Profile `profile`
|
@@ -318,8 +323,14 @@ Visiting `https://localhost:4567/` should show a Yoti Connect button
|
|
318
323
|
* [X] Email Address `email_address`
|
319
324
|
* [X] Age / Date of Birth `date_of_birth`
|
320
325
|
* [X] Address `postal_address`
|
326
|
+
* [X] Structured Postal Address `structured_postal_address`
|
321
327
|
* [X] Gender `gender`
|
322
328
|
* [X] Nationality `nationality`
|
329
|
+
* [X] Application Profile `application_profile`
|
330
|
+
* [X] Name `name`
|
331
|
+
* [X] URL `url`
|
332
|
+
* [X] Logo `logo`
|
333
|
+
* [X] Receipt Background Color `receipt_bgcolor`
|
323
334
|
|
324
335
|
## Support
|
325
336
|
|
data/lib/yoti.rb
CHANGED
@@ -12,6 +12,8 @@ require_relative 'yoti/http/profile_request'
|
|
12
12
|
require_relative 'yoti/http/request'
|
13
13
|
|
14
14
|
require_relative 'yoti/data_type/anchor'
|
15
|
+
require_relative 'yoti/data_type/base_profile'
|
16
|
+
require_relative 'yoti/data_type/application_profile'
|
15
17
|
require_relative 'yoti/data_type/profile'
|
16
18
|
require_relative 'yoti/data_type/attribute'
|
17
19
|
require_relative 'yoti/data_type/signed_time_stamp'
|
@@ -1,69 +1,167 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
|
3
3
|
module Yoti
|
4
|
-
#
|
4
|
+
#
|
5
|
+
# Details of an activity between a user and the application.
|
6
|
+
#
|
5
7
|
class ActivityDetails
|
6
|
-
#
|
8
|
+
#
|
9
|
+
# The outcome of the profile request, eg: SUCCESS
|
10
|
+
#
|
11
|
+
# @return [String]
|
12
|
+
#
|
7
13
|
attr_reader :outcome
|
8
14
|
|
15
|
+
#
|
9
16
|
# @deprecated replaced by :remember_me_id
|
10
|
-
#
|
17
|
+
#
|
18
|
+
# @return [String]
|
19
|
+
#
|
11
20
|
attr_reader :user_id
|
12
21
|
|
13
|
-
#
|
22
|
+
#
|
23
|
+
# Return the Remember Me ID, which is a unique, stable identifier for
|
24
|
+
# a user in the context of an application.
|
25
|
+
#
|
26
|
+
# You can use it to identify returning users. This value will be different
|
27
|
+
# for the same user in different applications.
|
28
|
+
#
|
29
|
+
# @return [String]
|
30
|
+
#
|
14
31
|
attr_reader :remember_me_id
|
15
32
|
|
16
|
-
#
|
33
|
+
#
|
34
|
+
# Return the Parent Remember Me ID, which is a unique, stable identifier for a
|
35
|
+
# user in the context of an organisation.
|
36
|
+
#
|
37
|
+
# You can use it to identify returning users. This value is consistent for a
|
38
|
+
# given user across different applications belonging to a single organisation.
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
#
|
17
42
|
attr_reader :parent_remember_me_id
|
18
43
|
|
19
|
-
#
|
44
|
+
#
|
45
|
+
# The decoded profile attributes
|
46
|
+
#
|
47
|
+
# @deprecated replaced by :profile
|
48
|
+
#
|
49
|
+
# @return [Hash]
|
50
|
+
#
|
20
51
|
attr_reader :user_profile
|
21
52
|
|
22
|
-
#
|
53
|
+
#
|
54
|
+
# Base64 encoded selfie image
|
55
|
+
#
|
56
|
+
# @return [String]
|
57
|
+
#
|
23
58
|
attr_reader :base64_selfie_uri
|
24
59
|
|
25
|
-
#
|
60
|
+
#
|
61
|
+
# The age under/over attribute
|
62
|
+
#
|
63
|
+
# @return [Boolean]
|
64
|
+
#
|
26
65
|
attr_reader :age_verified
|
27
66
|
|
67
|
+
#
|
68
|
+
# Receipt ID identifying a completed activity
|
69
|
+
#
|
70
|
+
# @return [String]
|
71
|
+
#
|
72
|
+
attr_reader :receipt_id
|
73
|
+
|
74
|
+
#
|
75
|
+
# Time and date of the sharing activity
|
76
|
+
#
|
77
|
+
# @return [Time]
|
78
|
+
#
|
79
|
+
attr_reader :timestamp
|
80
|
+
|
81
|
+
#
|
28
82
|
# @param receipt [Hash] the receipt from the API request
|
29
83
|
# @param decrypted_profile [Object] Protobuf AttributeList decrypted object containing the profile attributes
|
30
|
-
|
84
|
+
#
|
85
|
+
def initialize(receipt, decrypted_profile = nil, decrypted_application_profile = nil)
|
31
86
|
@remember_me_id = receipt['remember_me_id']
|
32
87
|
@user_id = @remember_me_id
|
88
|
+
@receipt_id = receipt['receipt_id']
|
33
89
|
@parent_remember_me_id = receipt['parent_remember_me_id']
|
34
90
|
@outcome = receipt['sharing_outcome']
|
35
|
-
@
|
36
|
-
@
|
37
|
-
process_decrypted_profile(
|
91
|
+
@timestamp = receipt['timestamp'] ? Time.parse(receipt['timestamp']) : nil
|
92
|
+
@extended_user_profile = process_decrypted_profile(decrypted_profile)
|
93
|
+
@extended_application_profile = process_decrypted_profile(decrypted_application_profile)
|
94
|
+
@user_profile = @extended_user_profile.map do |name, attribute|
|
95
|
+
[name, attribute.value]
|
96
|
+
end.to_h
|
38
97
|
end
|
39
98
|
|
40
|
-
#
|
99
|
+
#
|
100
|
+
# The user's structured postal address as JSON
|
101
|
+
#
|
102
|
+
# @deprecated replaced by Profile.structured_postal_address
|
103
|
+
#
|
104
|
+
# @return [Hash]
|
105
|
+
#
|
41
106
|
def structured_postal_address
|
42
|
-
|
107
|
+
user_profile['structured_postal_address']
|
43
108
|
end
|
44
109
|
|
45
|
-
#
|
110
|
+
#
|
111
|
+
# The user profile with shared attributes and anchor information, returned
|
112
|
+
# by Yoti if the request was successful
|
113
|
+
#
|
114
|
+
# @return [Profile]
|
115
|
+
#
|
46
116
|
def profile
|
47
|
-
Yoti::Profile.new(@
|
117
|
+
Yoti::Profile.new(@extended_user_profile)
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Profile of an application, with convenience methods to access well-known attributes
|
122
|
+
#
|
123
|
+
# @return [ApplicationProfile]
|
124
|
+
#
|
125
|
+
def application_profile
|
126
|
+
Yoti::ApplicationProfile.new(@extended_application_profile)
|
48
127
|
end
|
49
128
|
|
50
129
|
protected
|
51
130
|
|
131
|
+
#
|
132
|
+
# Process the decrypted profile into key-value hash
|
133
|
+
#
|
134
|
+
# @param [Yoti::Protobuf::Attrpubapi::AttributeList] decrypted_profile
|
135
|
+
#
|
136
|
+
# @return [Hash]
|
137
|
+
#
|
52
138
|
def process_decrypted_profile(decrypted_profile)
|
53
|
-
return
|
54
|
-
return
|
139
|
+
return {} unless decrypted_profile.is_a?(Object)
|
140
|
+
return {} unless decrypted_profile.respond_to?(:attributes)
|
55
141
|
|
142
|
+
profile_data = {}
|
56
143
|
decrypted_profile.attributes.each do |attribute|
|
57
144
|
begin
|
58
|
-
process_attribute(attribute)
|
145
|
+
profile_data[attribute.name] = process_attribute(attribute)
|
59
146
|
process_age_verified(attribute)
|
60
147
|
rescue StandardError => e
|
61
148
|
Yoti::Log.logger.warn("#{e.message} (Attribute: #{attribute.name})")
|
62
149
|
end
|
63
150
|
end
|
151
|
+
profile_data
|
64
152
|
end
|
65
153
|
|
154
|
+
#
|
155
|
+
# Converts protobuf attribute into Attribute
|
156
|
+
#
|
157
|
+
# @param [Yoti::Protobuf::Attrpubapi::Attribute] attribute
|
158
|
+
#
|
159
|
+
# @return [Attribute, nil]
|
160
|
+
#
|
66
161
|
def process_attribute(attribute)
|
162
|
+
# Application Logo can be empty, return nil when this occurs.
|
163
|
+
return nil if attribute.name == Yoti::Attribute::APPLICATION_LOGO && attribute.value == ''
|
164
|
+
|
67
165
|
attr_value = Yoti::Protobuf.value_based_on_content_type(attribute.value, attribute.content_type)
|
68
166
|
attr_value = Yoti::Protobuf.value_based_on_attribute_name(attr_value, attribute.name)
|
69
167
|
|
@@ -74,10 +172,14 @@ module Yoti
|
|
74
172
|
end
|
75
173
|
|
76
174
|
anchors_list = Yoti::AnchorProcessor.new(attribute.anchors).process
|
77
|
-
|
78
|
-
@user_profile[attribute.name] = attr_value
|
175
|
+
Yoti::Attribute.new(attribute.name, attr_value, anchors_list['sources'], anchors_list['verifiers'], anchors_list)
|
79
176
|
end
|
80
177
|
|
178
|
+
#
|
179
|
+
# Processes age verification
|
180
|
+
#
|
181
|
+
# @param [Yoti::Protobuf::Attrpubapi::Attribute] attribute
|
182
|
+
#
|
81
183
|
def process_age_verified(attribute)
|
82
184
|
@age_verified = attribute.value == 'true' if Yoti::AgeProcessor.is_age_verification(attribute.name)
|
83
185
|
end
|
data/lib/yoti/client.rb
CHANGED
@@ -1,20 +1,24 @@
|
|
1
1
|
module Yoti
|
2
|
+
#
|
2
3
|
# Handles all the publicly accesible Yoti methods for
|
3
4
|
# geting data using an encrypted connect token
|
5
|
+
#
|
4
6
|
module Client
|
7
|
+
#
|
5
8
|
# Performs all the steps required to get the decrypted profile from an API request
|
9
|
+
#
|
6
10
|
# @param encrypted_connect_token [String] token provided as a base 64 string
|
11
|
+
#
|
7
12
|
# @return [Object] an ActivityDetails instance encapsulating the user profile
|
13
|
+
#
|
8
14
|
def self.get_activity_details(encrypted_connect_token)
|
9
15
|
receipt = Yoti::ProfileRequest.new(encrypted_connect_token).receipt
|
10
|
-
|
16
|
+
user_profile = Protobuf.user_profile(receipt)
|
17
|
+
application_profile = Protobuf.application_profile(receipt)
|
11
18
|
|
12
|
-
return ActivityDetails.new(receipt) if
|
19
|
+
return ActivityDetails.new(receipt) if user_profile.nil?
|
13
20
|
|
14
|
-
|
15
|
-
decrypted_data = Yoti::SSL.decipher(unwrapped_key, encrypted_data.iv, encrypted_data.cipher_text)
|
16
|
-
decrypted_profile = Protobuf.attribute_list(decrypted_data)
|
17
|
-
ActivityDetails.new(receipt, decrypted_profile)
|
21
|
+
ActivityDetails.new(receipt, user_profile, application_profile)
|
18
22
|
end
|
19
23
|
|
20
24
|
def self.aml_check(aml_profile)
|
data/lib/yoti/configuration.rb
CHANGED
@@ -1,13 +1,67 @@
|
|
1
1
|
module Yoti
|
2
2
|
# Encapsulates attribute anchor
|
3
3
|
class Anchor
|
4
|
-
|
4
|
+
#
|
5
|
+
# Gets the value of the given anchor.
|
6
|
+
#
|
7
|
+
# Among possible options for SOURCE are "USER_PROVIDED", "PASSPORT",
|
8
|
+
# "DRIVING_LICENCE", "NATIONAL_ID" and "PASSCARD".
|
9
|
+
#
|
10
|
+
# Among possible options for VERIFIER are "YOTI_ADMIN", "YOTI_IDENTITY",
|
11
|
+
# "YOTI_OTP", "PASSPORT_NFC_SIGNATURE", "ISSUING_AUTHORITY" and
|
12
|
+
# "ISSUING_AUTHORITY_PKI".
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
#
|
16
|
+
attr_reader :value
|
5
17
|
|
6
|
-
|
18
|
+
#
|
19
|
+
# SubType is an indicator of any specific processing method, or subcategory,
|
20
|
+
# pertaining to an artifact.
|
21
|
+
#
|
22
|
+
# Examples:
|
23
|
+
# - For a passport, this would be either "NFC" or "OCR".
|
24
|
+
# - For a national ID, this could be "AADHAAR".
|
25
|
+
#
|
26
|
+
# @return [String]
|
27
|
+
#
|
28
|
+
attr_reader :sub_type
|
29
|
+
|
30
|
+
#
|
31
|
+
# Timestamp applied at the time of Anchor creation.
|
32
|
+
#
|
33
|
+
# @return [Yoti::SignedTimeStamp]
|
34
|
+
#
|
35
|
+
attr_reader :signed_time_stamp
|
36
|
+
|
37
|
+
#
|
38
|
+
# Certificate chain generated when this Anchor was created (attribute value was
|
39
|
+
# sourced or verified). Securely encodes the Anchor type and value.
|
40
|
+
#
|
41
|
+
# @return [Array<OpenSSL::X509::Certificate>]
|
42
|
+
#
|
43
|
+
attr_reader :origin_server_certs
|
44
|
+
|
45
|
+
#
|
46
|
+
# Gets the type of the given anchor.
|
47
|
+
#
|
48
|
+
# @return [String]
|
49
|
+
#
|
50
|
+
attr_reader :type
|
51
|
+
|
52
|
+
#
|
53
|
+
# @param [String] value
|
54
|
+
# @param [String] sub_type
|
55
|
+
# @param [Yoti::SignedTimeStamp] signed_time_stamp
|
56
|
+
# @param [Array<OpenSSL::X509::Certificate>] origin_server_certs
|
57
|
+
# @param [String] type
|
58
|
+
#
|
59
|
+
def initialize(value, sub_type, signed_time_stamp, origin_server_certs, type = nil)
|
7
60
|
@value = value
|
8
61
|
@sub_type = sub_type
|
9
62
|
@signed_time_stamp = signed_time_stamp
|
10
63
|
@origin_server_certs = origin_server_certs
|
64
|
+
@type = type
|
11
65
|
end
|
12
66
|
end
|
13
67
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Yoti
|
2
|
+
#
|
3
|
+
# Profile of an application with convenience methods to access well-known attributes.
|
4
|
+
#
|
5
|
+
class ApplicationProfile < BaseProfile
|
6
|
+
#
|
7
|
+
# The name of the application.
|
8
|
+
#
|
9
|
+
# @return [Attribute, nil]
|
10
|
+
#
|
11
|
+
def name
|
12
|
+
get_attribute(Yoti::Attribute::APPLICATION_NAME)
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# The URL where the application is available at.
|
17
|
+
#
|
18
|
+
# @return [Attribute, nil]
|
19
|
+
#
|
20
|
+
def url
|
21
|
+
get_attribute(Yoti::Attribute::APPLICATION_URL)
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# The logo of the application that will be displayed to users that perform a share with it.
|
26
|
+
#
|
27
|
+
# @return [Attribute, nil]
|
28
|
+
#
|
29
|
+
def logo
|
30
|
+
get_attribute(Yoti::Attribute::APPLICATION_LOGO)
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# The background color that will be displayed on each receipt the user gets, as a result
|
35
|
+
# of a share with the application.
|
36
|
+
#
|
37
|
+
# @return [Attribute, nil]
|
38
|
+
#
|
39
|
+
def receipt_bgcolor
|
40
|
+
get_attribute(Yoti::Attribute::APPLICATION_RECEIPT_BGCOLOR)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,5 +1,13 @@
|
|
1
1
|
module Yoti
|
2
|
-
#
|
2
|
+
#
|
3
|
+
# A class to represent a Yoti attribute.
|
4
|
+
#
|
5
|
+
# A Yoti attribute consists of the attribute name, an associated
|
6
|
+
# attribute value, and a list of Anchors from Yoti.
|
7
|
+
#
|
8
|
+
# It may hold one or more anchors, which specify how an attribute has been provided
|
9
|
+
# and how it has been verified within the Yoti platform.
|
10
|
+
#
|
3
11
|
class Attribute
|
4
12
|
FAMILY_NAME = 'family_name'
|
5
13
|
GIVEN_NAMES = 'given_names'
|
@@ -13,14 +21,79 @@ module Yoti
|
|
13
21
|
POSTAL_ADDRESS = 'postal_address'
|
14
22
|
STRUCTURED_POSTAL_ADDRESS = 'structured_postal_address'
|
15
23
|
DOCUMENT_IMAGES = 'document_images'
|
24
|
+
APPLICATION_NAME = 'application_name'
|
25
|
+
APPLICATION_LOGO = 'application_logo'
|
26
|
+
APPLICATION_URL = 'application_url'
|
27
|
+
APPLICATION_RECEIPT_BGCOLOR = 'application_receipt_bgcolor'
|
16
28
|
|
17
|
-
|
29
|
+
#
|
30
|
+
# Gets the name of the attribute.
|
31
|
+
#
|
32
|
+
# @return [String]
|
33
|
+
#
|
34
|
+
attr_reader :name
|
18
35
|
|
19
|
-
|
36
|
+
#
|
37
|
+
# Retrieves the value of an attribute. If this is null, the default value for
|
38
|
+
# the type is returned.
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
#
|
42
|
+
attr_reader :value
|
43
|
+
|
44
|
+
#
|
45
|
+
# Sources are a subset of the anchors associated with an attribute, where the
|
46
|
+
# anchor type is SOURCE.
|
47
|
+
#
|
48
|
+
# @return [Array<Yoti::Anchor>]
|
49
|
+
#
|
50
|
+
attr_reader :sources
|
51
|
+
|
52
|
+
#
|
53
|
+
# Verifiers are a subset of the anchors associated with an attribute, where the
|
54
|
+
# anchor type is VERIFIER.
|
55
|
+
#
|
56
|
+
# @return [Array<Yoti::Anchor>]
|
57
|
+
#
|
58
|
+
attr_reader :verifiers
|
59
|
+
|
60
|
+
#
|
61
|
+
# Get the anchors for an attribute. If an attribute has only one SOURCE
|
62
|
+
# Anchor with the value set to "USER_PROVIDED" and zero VERIFIER Anchors,
|
63
|
+
# then the attribute is a self-certified one.
|
64
|
+
#
|
65
|
+
# @return [Array<Yoti::Anchor>]
|
66
|
+
#
|
67
|
+
attr_reader :anchors
|
68
|
+
|
69
|
+
#
|
70
|
+
# @param [String] name
|
71
|
+
# @param [String] value
|
72
|
+
# @param [Array<Yoti::Anchor>] sources
|
73
|
+
# @param [Array<Yoti::Anchor>] verifiers
|
74
|
+
# @param [Hash<String => Array>] anchors_list
|
75
|
+
#
|
76
|
+
def initialize(name, value, sources, verifiers, anchors_list = {})
|
20
77
|
@name = name
|
21
78
|
@value = value
|
22
79
|
@sources = sources
|
23
80
|
@verifiers = verifiers
|
81
|
+
@anchors = process_anchors_list(anchors_list)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
#
|
87
|
+
# Flattens anchor lists into single array.
|
88
|
+
#
|
89
|
+
# @param [Hash<String => Array>] anchors_list
|
90
|
+
#
|
91
|
+
# @return [Array<Yoti::Anchor>] <description>
|
92
|
+
#
|
93
|
+
def process_anchors_list(anchors_list)
|
94
|
+
anchors = []
|
95
|
+
anchors_list.each { |_type, list| anchors += list }
|
96
|
+
anchors
|
24
97
|
end
|
25
98
|
end
|
26
99
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Yoti
|
2
|
+
#
|
3
|
+
# Encapsulates Yoti user profile
|
4
|
+
#
|
5
|
+
class BaseProfile
|
6
|
+
#
|
7
|
+
# Return all attributes for the profile.
|
8
|
+
#
|
9
|
+
# @return [Hash{String => Yoti::Attribute}]
|
10
|
+
#
|
11
|
+
attr_reader :attributes
|
12
|
+
|
13
|
+
#
|
14
|
+
# @param [Hash{String => Yoti::Attribute}] profile_data
|
15
|
+
#
|
16
|
+
def initialize(profile_data)
|
17
|
+
@attributes = profile_data.is_a?(Object) ? profile_data : {}
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Get attribute value by name.
|
22
|
+
#
|
23
|
+
# @param [String] attr_name
|
24
|
+
#
|
25
|
+
# @return [Attribute, nil]
|
26
|
+
#
|
27
|
+
def get_attribute(attr_name)
|
28
|
+
return nil unless @attributes.key? attr_name
|
29
|
+
|
30
|
+
@attributes[attr_name]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,51 +1,105 @@
|
|
1
1
|
module Yoti
|
2
|
+
#
|
2
3
|
# Encapsulates Yoti user profile
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
#
|
5
|
+
class Profile < BaseProfile
|
6
|
+
#
|
7
|
+
# Selfie is a photograph of the user.
|
8
|
+
#
|
9
|
+
# @return [Attribute, nil]
|
10
|
+
#
|
9
11
|
def selfie
|
10
12
|
get_attribute(Yoti::Attribute::SELFIE)
|
11
13
|
end
|
12
14
|
|
15
|
+
#
|
16
|
+
# Corresponds to primary name in passport, and surname in English.
|
17
|
+
#
|
18
|
+
# @return [Attribute, nil]
|
19
|
+
#
|
13
20
|
def family_name
|
14
21
|
get_attribute(Yoti::Attribute::FAMILY_NAME)
|
15
22
|
end
|
16
23
|
|
24
|
+
#
|
25
|
+
# Corresponds to secondary names in passport, and first/middle names in English.
|
26
|
+
#
|
27
|
+
# @return [Attribute, nil]
|
28
|
+
#
|
17
29
|
def given_names
|
18
30
|
get_attribute(Yoti::Attribute::GIVEN_NAMES)
|
19
31
|
end
|
20
32
|
|
33
|
+
#
|
34
|
+
# The user's full name.
|
35
|
+
#
|
36
|
+
# @return [Attribute, nil]
|
37
|
+
#
|
21
38
|
def full_name
|
22
39
|
get_attribute(Yoti::Attribute::FULL_NAME)
|
23
40
|
end
|
24
41
|
|
42
|
+
#
|
43
|
+
# The user's phone number, as verified at registration time. This will be a number with + for
|
44
|
+
# international prefix and no spaces, e.g. "+447777123456".
|
45
|
+
#
|
46
|
+
# @return [Attribute, nil]
|
47
|
+
#
|
25
48
|
def phone_number
|
26
49
|
get_attribute(Yoti::Attribute::PHONE_NUMBER)
|
27
50
|
end
|
28
51
|
|
52
|
+
#
|
53
|
+
# The user's verified email address.
|
54
|
+
#
|
55
|
+
# @return [Attribute, nil]
|
56
|
+
#
|
29
57
|
def email_address
|
30
58
|
get_attribute(Yoti::Attribute::EMAIL_ADDRESS)
|
31
59
|
end
|
32
60
|
|
61
|
+
#
|
62
|
+
# Date of birth.
|
63
|
+
#
|
64
|
+
# @return [Attribute, nil]
|
65
|
+
#
|
33
66
|
def date_of_birth
|
34
67
|
get_attribute(Yoti::Attribute::DATE_OF_BIRTH)
|
35
68
|
end
|
36
69
|
|
70
|
+
#
|
71
|
+
# Corresponds to the gender in the passport; will be one of the strings
|
72
|
+
# "MALE", "FEMALE", "TRANSGENDER" or "OTHER".
|
73
|
+
#
|
74
|
+
# @return [Attribute, nil]
|
75
|
+
#
|
37
76
|
def gender
|
38
77
|
get_attribute(Yoti::Attribute::GENDER)
|
39
78
|
end
|
40
79
|
|
80
|
+
#
|
81
|
+
# Corresponds to the nationality in the passport.
|
82
|
+
#
|
83
|
+
# @return [Attribute, nil]
|
84
|
+
#
|
41
85
|
def nationality
|
42
86
|
get_attribute(Yoti::Attribute::NATIONALITY)
|
43
87
|
end
|
44
88
|
|
89
|
+
#
|
90
|
+
# Document images.
|
91
|
+
#
|
92
|
+
# @return [Attribute, nil]
|
93
|
+
#
|
45
94
|
def document_images
|
46
95
|
get_attribute(Yoti::Attribute::DOCUMENT_IMAGES)
|
47
96
|
end
|
48
97
|
|
98
|
+
#
|
99
|
+
# The user's postal address as a String.
|
100
|
+
#
|
101
|
+
# @return [Attribute, nil]
|
102
|
+
#
|
49
103
|
def postal_address
|
50
104
|
postal_address = get_attribute(Yoti::Attribute::POSTAL_ADDRESS)
|
51
105
|
return postal_address unless postal_address.nil?
|
@@ -53,19 +107,22 @@ module Yoti
|
|
53
107
|
attribute_from_formatted_address
|
54
108
|
end
|
55
109
|
|
110
|
+
#
|
111
|
+
# The user's structured postal address as a JSON.
|
112
|
+
#
|
113
|
+
# @return [Attribute, nil]
|
114
|
+
#
|
56
115
|
def structured_postal_address
|
57
116
|
get_attribute(Yoti::Attribute::STRUCTURED_POSTAL_ADDRESS)
|
58
117
|
end
|
59
118
|
|
60
|
-
# @return attribute value by name
|
61
|
-
def get_attribute(attr_name)
|
62
|
-
return nil unless @profile_data.key? attr_name
|
63
|
-
|
64
|
-
@profile_data[attr_name]
|
65
|
-
end
|
66
|
-
|
67
119
|
protected
|
68
120
|
|
121
|
+
#
|
122
|
+
# Creates attribute from formatted address.
|
123
|
+
#
|
124
|
+
# @return [Attribute, nil]
|
125
|
+
#
|
69
126
|
def attribute_from_formatted_address
|
70
127
|
return nil if structured_postal_address.nil?
|
71
128
|
return nil unless structured_postal_address.value.key?('formatted_address')
|
@@ -14,6 +14,7 @@ module Yoti
|
|
14
14
|
@http_req['X-Yoti-Auth-Key'] = @auth_key
|
15
15
|
@http_req['X-Yoti-Auth-Digest'] = message_signature
|
16
16
|
@http_req['X-Yoti-SDK'] = Yoti.configuration.sdk_identifier
|
17
|
+
@http_req['X-Yoti-SDK-Version'] = "#{Yoti.configuration.sdk_identifier}-#{Yoti::VERSION}"
|
17
18
|
@http_req['Content-Type'] = 'application/json'
|
18
19
|
@http_req['Accept'] = 'application/json'
|
19
20
|
@http_req
|
data/lib/yoti/protobuf/main.rb
CHANGED
@@ -19,12 +19,25 @@ module Yoti
|
|
19
19
|
CT_MULTI_VALUE = :MULTI_VALUE # multi value
|
20
20
|
CT_INT = :INT # integer
|
21
21
|
|
22
|
+
#
|
23
|
+
# @deprecated replaced by user_profile
|
24
|
+
#
|
22
25
|
def current_user(receipt)
|
23
26
|
return nil unless valid_receipt?(receipt)
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
+
decode_profile(receipt['other_party_profile_content'])
|
29
|
+
end
|
30
|
+
|
31
|
+
def user_profile(receipt)
|
32
|
+
return nil unless valid_receipt?(receipt)
|
33
|
+
|
34
|
+
decipher_profile(receipt['other_party_profile_content'], receipt['wrapped_receipt_key'])
|
35
|
+
end
|
36
|
+
|
37
|
+
def application_profile(receipt)
|
38
|
+
return nil unless valid_receipt?(receipt)
|
39
|
+
|
40
|
+
decipher_profile(receipt['profile_content'], receipt['wrapped_receipt_key'])
|
28
41
|
end
|
29
42
|
|
30
43
|
def attribute_list(data)
|
@@ -80,6 +93,18 @@ module Yoti
|
|
80
93
|
!receipt['other_party_profile_content'].nil? &&
|
81
94
|
receipt['other_party_profile_content'] != ''
|
82
95
|
end
|
96
|
+
|
97
|
+
def decode_profile(profile_content)
|
98
|
+
decoded_profile_content = Base64.decode64(profile_content)
|
99
|
+
Yoti::Protobuf::Compubapi::EncryptedData.decode(decoded_profile_content)
|
100
|
+
end
|
101
|
+
|
102
|
+
def decipher_profile(profile_content, wrapped_key)
|
103
|
+
encrypted_data = decode_profile(profile_content)
|
104
|
+
unwrapped_key = Yoti::SSL.decrypt_token(wrapped_key)
|
105
|
+
decrypted_data = Yoti::SSL.decipher(unwrapped_key, encrypted_data.iv, encrypted_data.cipher_text)
|
106
|
+
Protobuf.attribute_list(decrypted_data)
|
107
|
+
end
|
83
108
|
end
|
84
109
|
end
|
85
110
|
end
|
@@ -2,58 +2,95 @@ require 'openssl'
|
|
2
2
|
require 'date'
|
3
3
|
|
4
4
|
module Yoti
|
5
|
+
#
|
5
6
|
# Parse attribute anchors
|
7
|
+
#
|
6
8
|
class AnchorProcessor
|
9
|
+
#
|
10
|
+
# @param [Array<Yoti::Protobuf::Attrpubapi::Anchor>]
|
11
|
+
#
|
7
12
|
def initialize(anchors_list)
|
8
13
|
@anchors_list = anchors_list
|
9
14
|
@get_next = false
|
10
15
|
end
|
11
16
|
|
17
|
+
#
|
18
|
+
# Extract matching Attribute Anchors from list.
|
19
|
+
#
|
20
|
+
# @return [Array<Yoti::Anchor>]
|
21
|
+
#
|
12
22
|
def process
|
13
|
-
result_data = {
|
14
|
-
anchor_types = self.anchor_types
|
23
|
+
result_data = ANCHOR_LIST_KEYS.map { |key, _value| [key, []] }.to_h
|
15
24
|
|
16
25
|
@anchors_list.each do |anchor|
|
17
26
|
x509_certs_list = convert_certs_list_to_X509(anchor.origin_server_certs)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
yoti_anchor = get_anchor_by_oid(cert, oid, anchor.sub_type, yoti_signed_time_stamp, x509_certs_list)
|
23
|
-
result_data[type].push(yoti_anchor) unless yoti_anchor.nil?
|
24
|
-
end
|
25
|
-
end
|
27
|
+
signed_time_stamp = process_signed_time_stamp(anchor.signed_time_stamp)
|
28
|
+
yoti_anchor = get_anchor_from_certs(x509_certs_list, anchor.sub_type, signed_time_stamp)
|
29
|
+
anchor_list_key = get_anchor_list_key_by_type(yoti_anchor.type)
|
30
|
+
result_data[anchor_list_key].push(yoti_anchor)
|
26
31
|
end
|
27
32
|
|
28
33
|
result_data
|
29
34
|
end
|
30
35
|
|
36
|
+
#
|
37
|
+
# Convert certificate list to a list of X509 certificates.
|
38
|
+
#
|
39
|
+
# @param [Google::Protobuf::RepeatedField] certs_list
|
40
|
+
#
|
41
|
+
# @return [Array<OpenSSL::X509::Certificate>]
|
42
|
+
#
|
31
43
|
def convert_certs_list_to_X509(certs_list)
|
32
44
|
x509_certs_list = []
|
33
45
|
certs_list.each do |cert|
|
34
|
-
|
35
|
-
x509_certs_list.push x509_cert
|
46
|
+
x509_certs_list.push OpenSSL::X509::Certificate.new(cert)
|
36
47
|
end
|
37
|
-
|
38
48
|
x509_certs_list
|
39
49
|
end
|
40
50
|
|
51
|
+
#
|
52
|
+
# Return signed timestamp.
|
53
|
+
#
|
54
|
+
# @param [String] signed_time_stamp_binary
|
55
|
+
#
|
56
|
+
# @return [Yoti::SignedTimeStamp]
|
57
|
+
#
|
41
58
|
def process_signed_time_stamp(signed_time_stamp_binary)
|
42
59
|
signed_time_stamp = Yoti::Protobuf::Compubapi::SignedTimestamp.decode(signed_time_stamp_binary)
|
43
|
-
time_in_sec = signed_time_stamp.timestamp
|
44
|
-
|
45
|
-
Yoti::SignedTimeStamp.new(signed_time_stamp.version, date_time)
|
60
|
+
time_in_sec = signed_time_stamp.timestamp.quo(1000000)
|
61
|
+
Yoti::SignedTimeStamp.new(signed_time_stamp.version, Time.at(time_in_sec))
|
46
62
|
end
|
47
63
|
|
64
|
+
#
|
65
|
+
# Return Anchor for provided oid.
|
66
|
+
#
|
67
|
+
# @deprecated no longer in use
|
68
|
+
#
|
69
|
+
# @param [OpenSSL::X509::Certificate] cert
|
70
|
+
# @param [String] oid
|
71
|
+
# @param [String] sub_type
|
72
|
+
# @param [Yoti::SignedTimeStamp] signed_time_stamp
|
73
|
+
# @param [Array<OpenSSL::X509::Certificate>] x509_certs_list
|
74
|
+
#
|
75
|
+
# @return [Yoti::Anchor, nil]
|
76
|
+
#
|
48
77
|
def get_anchor_by_oid(cert, oid, sub_type, signed_time_stamp, x509_certs_list)
|
49
78
|
asn1_obj = OpenSSL::ASN1.decode(cert)
|
50
79
|
anchor_value = get_anchor_value_by_oid(asn1_obj, oid)
|
51
80
|
|
52
|
-
|
53
|
-
|
54
|
-
Yoti::Anchor.new(anchor_value, sub_type, signed_time_stamp, x509_certs_list)
|
81
|
+
Yoti::Anchor.new(anchor_value, sub_type, signed_time_stamp, x509_certs_list) unless anchor_value.nil?
|
55
82
|
end
|
56
83
|
|
84
|
+
#
|
85
|
+
# Return Anchor value for provided oid.
|
86
|
+
#
|
87
|
+
# @deprecated no longer in use
|
88
|
+
#
|
89
|
+
# @param [OpenSSL::ASN1::Sequence, OpenSSL::ASN1::ASN1Data, Array] obj
|
90
|
+
# @param [String] oid
|
91
|
+
#
|
92
|
+
# @return [String, nil]
|
93
|
+
#
|
57
94
|
def get_anchor_value_by_oid(obj, oid)
|
58
95
|
case obj
|
59
96
|
when OpenSSL::ASN1::Sequence, Array
|
@@ -66,19 +103,37 @@ module Yoti
|
|
66
103
|
nil
|
67
104
|
end
|
68
105
|
|
106
|
+
#
|
107
|
+
# Return Anchor value for ASN1 data.
|
108
|
+
#
|
109
|
+
# @deprecated no longer in use
|
110
|
+
#
|
111
|
+
# @param [OpenSSL::ASN1::ASN1Data] value
|
112
|
+
# @param [String] oid
|
113
|
+
#
|
114
|
+
# @return [String, nil]
|
115
|
+
#
|
69
116
|
def get_anchor_value_by_asn1_data(value, oid)
|
70
117
|
if value.respond_to?(:to_s) && value == oid
|
71
118
|
@get_next = true
|
72
119
|
elsif value.respond_to?(:to_s) && @get_next
|
73
|
-
raw_value = OpenSSL::ASN1.decode(value)
|
74
|
-
anchor_value = raw_value.value[0].value
|
75
120
|
@get_next = false
|
76
|
-
return
|
121
|
+
return OpenSSL::ASN1.decode(value).value[0].value
|
77
122
|
end
|
78
123
|
|
79
124
|
get_anchor_value_by_oid(value, oid)
|
80
125
|
end
|
81
126
|
|
127
|
+
#
|
128
|
+
# Return Anchor value for ASN1 sequence.
|
129
|
+
#
|
130
|
+
# @deprecated no longer in use
|
131
|
+
#
|
132
|
+
# @param [OpenSSL::ASN1::Sequence, Array] obj
|
133
|
+
# @param [String] oid
|
134
|
+
#
|
135
|
+
# @return [String, nil]
|
136
|
+
#
|
82
137
|
def get_anchor_value_by_asn1_sequence(obj, oid)
|
83
138
|
obj.each do |child_obj|
|
84
139
|
result = get_anchor_value_by_oid(child_obj, oid)
|
@@ -87,15 +142,126 @@ module Yoti
|
|
87
142
|
nil
|
88
143
|
end
|
89
144
|
|
145
|
+
#
|
146
|
+
# Mapping of anchor types to oid.
|
147
|
+
#
|
148
|
+
# @deprecated no longer in use
|
149
|
+
#
|
150
|
+
# @return [Hash]
|
151
|
+
#
|
90
152
|
def anchor_types
|
91
|
-
|
92
|
-
'verifiers' => '1.3.6.1.4.1.47127.1.1.2' }
|
153
|
+
ANCHOR_LIST_KEYS
|
93
154
|
end
|
94
155
|
|
95
156
|
protected
|
96
157
|
|
158
|
+
#
|
97
159
|
# Define whether the search function get_anchor_value_by_oid
|
98
160
|
# should return the next value in the array
|
161
|
+
#
|
162
|
+
# @deprecated no longer in use
|
163
|
+
#
|
164
|
+
# @return [Boolean]
|
165
|
+
#
|
99
166
|
attr_reader :get_next
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
#
|
171
|
+
# Mapping of anchor types.
|
172
|
+
#
|
173
|
+
ANCHOR_TYPES = {
|
174
|
+
'SOURCE' => '1.3.6.1.4.1.47127.1.1.1',
|
175
|
+
'VERIFIER' => '1.3.6.1.4.1.47127.1.1.2',
|
176
|
+
'UNKNOWN' => ''
|
177
|
+
}.freeze
|
178
|
+
|
179
|
+
#
|
180
|
+
# Mapping of anchor list keys.
|
181
|
+
#
|
182
|
+
ANCHOR_LIST_KEYS = {
|
183
|
+
'sources' => ANCHOR_TYPES['SOURCE'],
|
184
|
+
'verifiers' => ANCHOR_TYPES['VERIFIER'],
|
185
|
+
'unknown' => ANCHOR_TYPES['UNKNOWN']
|
186
|
+
}.freeze
|
187
|
+
|
188
|
+
#
|
189
|
+
# Get anchor type by oid.
|
190
|
+
#
|
191
|
+
# @param [String] oid
|
192
|
+
#
|
193
|
+
def get_anchor_type_by_oid(oid)
|
194
|
+
ANCHOR_TYPES.find { |_key, value| value == oid }.first
|
195
|
+
end
|
196
|
+
|
197
|
+
#
|
198
|
+
# Get anchor list key by type.
|
199
|
+
#
|
200
|
+
# @param [String] type
|
201
|
+
#
|
202
|
+
def get_anchor_list_key_by_type(type)
|
203
|
+
ANCHOR_LIST_KEYS.find { |_key, value| value == ANCHOR_TYPES[type] }.first
|
204
|
+
end
|
205
|
+
|
206
|
+
#
|
207
|
+
# Get anchor from provided certificate list.
|
208
|
+
#
|
209
|
+
# @param [Array<OpenSSL::X509::Certificate>] x509_certs_list
|
210
|
+
# @param [String] sub_type
|
211
|
+
# @param [Yoti::SignedTimeStamp] signed_time_stamp
|
212
|
+
#
|
213
|
+
# @return [Yoti::Anchor]
|
214
|
+
#
|
215
|
+
def get_anchor_from_certs(x509_certs_list, sub_type, signed_time_stamp)
|
216
|
+
x509_certs_list.each do |cert|
|
217
|
+
ANCHOR_TYPES.each do |_type, oid|
|
218
|
+
anchor_extension = get_extension_by_oid(cert, oid)
|
219
|
+
next if anchor_extension.nil?
|
220
|
+
|
221
|
+
return Yoti::Anchor.new(
|
222
|
+
get_anchor_value(anchor_extension),
|
223
|
+
sub_type,
|
224
|
+
signed_time_stamp,
|
225
|
+
x509_certs_list,
|
226
|
+
get_anchor_type_by_oid(oid)
|
227
|
+
)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
Yoti::Anchor.new('', sub_type, signed_time_stamp, x509_certs_list, 'UNKNOWN')
|
231
|
+
end
|
232
|
+
|
233
|
+
#
|
234
|
+
# Get extension for provided oid.
|
235
|
+
#
|
236
|
+
# @param [OpenSSL::X509::Certificate] cert
|
237
|
+
# @param [String] oid
|
238
|
+
#
|
239
|
+
# @return [OpenSSL::X509::Extension]
|
240
|
+
#
|
241
|
+
def get_extension_by_oid(cert, oid)
|
242
|
+
cert.extensions.each do |extension|
|
243
|
+
return extension if extension.oid == oid
|
244
|
+
end
|
245
|
+
nil
|
246
|
+
end
|
247
|
+
|
248
|
+
#
|
249
|
+
# Return Anchor value.
|
250
|
+
#
|
251
|
+
# @param [OpenSSL::X509::Extension] anchor_extension
|
252
|
+
#
|
253
|
+
# @return [String, nil]
|
254
|
+
#
|
255
|
+
def get_anchor_value(anchor_extension)
|
256
|
+
decoded_extension = OpenSSL::ASN1.decode(anchor_extension)
|
257
|
+
extension_value = decoded_extension.value[1] if decoded_extension.value.is_a?(Array)
|
258
|
+
extension_value_item = extension_value.value if extension_value.is_a?(OpenSSL::ASN1::OctetString)
|
259
|
+
if extension_value_item.is_a?(String)
|
260
|
+
decoded = OpenSSL::ASN1.decode(extension_value_item)
|
261
|
+
return decoded.value[0].value if decoded.value[0].is_a?(OpenSSL::ASN1::ASN1Data)
|
262
|
+
end
|
263
|
+
|
264
|
+
nil
|
265
|
+
end
|
100
266
|
end
|
101
267
|
end
|
data/lib/yoti/version.rb
CHANGED
data/rubocop.yml
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yoti
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Zaremba
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: google-protobuf
|
@@ -189,7 +189,9 @@ files:
|
|
189
189
|
- lib/yoti/client.rb
|
190
190
|
- lib/yoti/configuration.rb
|
191
191
|
- lib/yoti/data_type/anchor.rb
|
192
|
+
- lib/yoti/data_type/application_profile.rb
|
192
193
|
- lib/yoti/data_type/attribute.rb
|
194
|
+
- lib/yoti/data_type/base_profile.rb
|
193
195
|
- lib/yoti/data_type/image.rb
|
194
196
|
- lib/yoti/data_type/image_jpeg.rb
|
195
197
|
- lib/yoti/data_type/image_png.rb
|
@@ -238,7 +240,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
238
240
|
- !ruby/object:Gem::Version
|
239
241
|
version: '0'
|
240
242
|
requirements: []
|
241
|
-
|
243
|
+
rubyforge_project:
|
244
|
+
rubygems_version: 2.7.9
|
242
245
|
signing_key:
|
243
246
|
specification_version: 4
|
244
247
|
summary: Yoti Ruby SDK for back-end integration.
|