yoti 1.4.0 → 1.5.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 +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.
|