yoti 1.5.0 → 1.6.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +17 -0
  3. data/CONTRIBUTING.md +0 -29
  4. data/Gemfile +0 -2
  5. data/README.md +1 -1
  6. data/Rakefile +16 -3
  7. data/lib/yoti.rb +16 -0
  8. data/lib/yoti/activity_details.rb +21 -2
  9. data/lib/yoti/client.rb +2 -1
  10. data/lib/yoti/data_type/age_verification.rb +54 -0
  11. data/lib/yoti/data_type/attribute.rb +3 -0
  12. data/lib/yoti/data_type/base_profile.rb +13 -0
  13. data/lib/yoti/data_type/document_details.rb +88 -0
  14. data/lib/yoti/data_type/profile.rb +76 -0
  15. data/lib/yoti/dynamic_share_service/dynamic_scenario.rb +67 -0
  16. data/lib/yoti/dynamic_share_service/extension/extension.rb +45 -0
  17. data/lib/yoti/dynamic_share_service/extension/location_constraint_extension.rb +88 -0
  18. data/lib/yoti/dynamic_share_service/extension/thirdparty_attribute_extension.rb +119 -0
  19. data/lib/yoti/dynamic_share_service/extension/transactional_flow_extension.rb +47 -0
  20. data/lib/yoti/dynamic_share_service/policy/dynamic_policy.rb +184 -0
  21. data/lib/yoti/dynamic_share_service/policy/source_constraint.rb +88 -0
  22. data/lib/yoti/dynamic_share_service/policy/wanted_anchor.rb +53 -0
  23. data/lib/yoti/dynamic_share_service/policy/wanted_attribute.rb +85 -0
  24. data/lib/yoti/dynamic_share_service/share_url.rb +82 -0
  25. data/lib/yoti/http/profile_request.rb +1 -0
  26. data/lib/yoti/http/request.rb +15 -0
  27. data/lib/yoti/http/signed_request.rb +0 -3
  28. data/lib/yoti/protobuf/main.rb +25 -4
  29. data/lib/yoti/protobuf/sharepubapi/DataEntry_pb.rb +29 -0
  30. data/lib/yoti/protobuf/sharepubapi/ExtraData_pb.rb +19 -0
  31. data/lib/yoti/protobuf/sharepubapi/IssuingAttributes_pb.rb +23 -0
  32. data/lib/yoti/protobuf/sharepubapi/ThirdPartyAttribute_pb.rb +20 -0
  33. data/lib/yoti/share/attribute_issuance_details.rb +43 -0
  34. data/lib/yoti/share/extra_data.rb +25 -0
  35. data/lib/yoti/ssl.rb +8 -0
  36. data/lib/yoti/util/age_processor.rb +4 -0
  37. data/lib/yoti/version.rb +1 -1
  38. data/rubocop.yml +4 -0
  39. data/yoti.gemspec +3 -3
  40. metadata +31 -14
  41. data/.travis.yml +0 -17
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yoti
4
+ module DynamicSharingService
5
+ # Describes a dynamic share
6
+ class DynamicScenario
7
+ attr_reader :policy
8
+ attr_reader :extensions
9
+ attr_reader :callback_endpoint
10
+
11
+ def initialize
12
+ @extensions = []
13
+ end
14
+
15
+ def to_json(*_args)
16
+ as_json.to_json
17
+ end
18
+
19
+ def as_json(*_args)
20
+ {
21
+ policy: @policy,
22
+ extensions: @extensions,
23
+ callback_endpoint: @callback_endpoint
24
+ }
25
+ end
26
+
27
+ def self.builder
28
+ DynamicScenarioBuilder.new
29
+ end
30
+ end
31
+
32
+ # Builder for DynamicScenario
33
+ class DynamicScenarioBuilder
34
+ def initialize
35
+ @scenario = DynamicScenario.new
36
+ end
37
+
38
+ def build
39
+ Marshal.load Marshal.dump @scenario
40
+ end
41
+
42
+ #
43
+ # @param [Yoti::DynamicSharingService::DynamicPolicy] policy
44
+ #
45
+ def with_policy(policy)
46
+ @scenario.instance_variable_set(:@policy, policy)
47
+ self
48
+ end
49
+
50
+ #
51
+ # @param [Yoti::DynamicSharingService::Extension] extension
52
+ #
53
+ def with_extension(extension)
54
+ @scenario.instance_variable_get(:@extensions) << extension
55
+ self
56
+ end
57
+
58
+ #
59
+ # @param [String] endpoint
60
+ #
61
+ def with_callback_endpoint(endpoint)
62
+ @scenario.instance_variable_set(:@callback_endpoint, endpoint)
63
+ self
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yoti
4
+ module DynamicSharingService
5
+ class Extension
6
+ attr_reader :type
7
+ attr_reader :content
8
+
9
+ def to_json(*_args)
10
+ as_json.to_json
11
+ end
12
+
13
+ def as_json(*_args)
14
+ {
15
+ type: @type,
16
+ content: @content
17
+ }
18
+ end
19
+
20
+ def self.builder
21
+ ExtensionBuilder.new
22
+ end
23
+ end
24
+
25
+ class ExtensionBuilder
26
+ def initialize
27
+ @extension = Extension.new
28
+ end
29
+
30
+ def with_type(type)
31
+ @extension.instance_variable_set(:@type, type)
32
+ self
33
+ end
34
+
35
+ def with_content(content)
36
+ @extension.instance_variable_set(:@content, content)
37
+ self
38
+ end
39
+
40
+ def build
41
+ Marshal.load Marshal.dump @extension
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yoti
4
+ module DynamicSharingService
5
+ # A Location Constraint
6
+ class LocationConstraintExtension
7
+ EXTENSION_TYPE = 'LOCATION_CONSTRAINT'
8
+
9
+ attr_reader :content
10
+ attr_reader :type
11
+
12
+ def initialize
13
+ @content = {}
14
+ @type = EXTENSION_TYPE
15
+ end
16
+
17
+ def as_json(*_args)
18
+ {
19
+ type: @type,
20
+ content: @content
21
+ }
22
+ end
23
+
24
+ def to_json(*_args)
25
+ as_json.to_json
26
+ end
27
+
28
+ def self.builder
29
+ LocationConstraintExtensionBuilder.new
30
+ end
31
+ end
32
+
33
+ # Builder for LocationConstraintExtension
34
+ class LocationConstraintExtensionBuilder
35
+ def with_latitude(latitude)
36
+ raise ArgumentError, 'Latitude must be Integer or Float'\
37
+ unless latitude.is_a?(Integer) || latitude.is_a?(Float)
38
+ raise ArgumentError, 'Latitude must be between -90 and 90'\
39
+ unless latitude >= -90 && latitude <= 90
40
+
41
+ @latitude = latitude
42
+ self
43
+ end
44
+
45
+ def with_longitude(longitude)
46
+ raise ArgumentError, 'Longitude must be Integer or Float'\
47
+ unless longitude.is_a?(Integer) || longitude.is_a?(Float)
48
+ raise ArgumentError, 'Longitude must be between -180 and 180'\
49
+ unless longitude >= -180 && longitude <= 180
50
+
51
+ @longitude = longitude
52
+ self
53
+ end
54
+
55
+ def with_radius(radius)
56
+ raise ArgumentError, 'Radius must be Integer or Float'\
57
+ unless radius.is_a?(Integer) || radius.is_a?(Float)
58
+ raise ArgumentError, 'Radius must be >= 0' unless radius >= 0
59
+
60
+ @radius = radius
61
+ self
62
+ end
63
+
64
+ def with_max_uncertainty(uncertainty)
65
+ raise ArgumentError, 'Uncertainty must be Integer or Float'\
66
+ unless uncertainty.is_a?(Integer) || uncertainty.is_a?(Float)
67
+ raise ArgumentError, 'Uncertainty must be >= 0' unless uncertainty >= 0
68
+
69
+ @uncertainty = uncertainty
70
+ self
71
+ end
72
+
73
+ def build
74
+ @radius ||= 150 unless @radius
75
+ @uncertainty ||= 150 unless @uncertainty
76
+
77
+ extension = LocationConstraintExtension.new
78
+ extension.instance_variable_get(:@content)[:expected_device_location] = {
79
+ latitude: @latitude,
80
+ longitude: @longitude,
81
+ radius: @radius,
82
+ max_uncertainty_radius: @uncertainty
83
+ }
84
+ extension
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ module Yoti
6
+ module DynamicSharingService
7
+ class ThirdPartyAttributeDefinition
8
+ #
9
+ # @param [String] name
10
+ #
11
+ def initialize(name)
12
+ @name = name
13
+ end
14
+
15
+ def as_json(*_args)
16
+ { name: @name }
17
+ end
18
+
19
+ def to_json(*_args)
20
+ as_json.to_json
21
+ end
22
+ end
23
+
24
+ class ThirdPartyAttributeExtensionBuilder
25
+ def initialize
26
+ @expiry_date = nil
27
+ @definitions = []
28
+ end
29
+
30
+ #
31
+ # @param [DateTime,Time] expiry_date
32
+ #
33
+ # @return [self]
34
+ #
35
+ def with_expiry_date(expiry_date)
36
+ @expiry_date = expiry_date
37
+ self
38
+ end
39
+
40
+ #
41
+ # @param [String] *names
42
+ #
43
+ # @return [self]
44
+ #
45
+ def with_definitions(*names)
46
+ @definitions += names.map do |name|
47
+ ThirdPartyAttributeDefinition.new(name)
48
+ end
49
+ self
50
+ end
51
+
52
+ #
53
+ # @return [ThirdPartyAttributeExtension]
54
+ #
55
+ def build
56
+ content = ThirdPartyAttributeExtensionContent.new(@expiry_date, @definitions)
57
+ ThirdPartyAttributeExtension.new(content)
58
+ end
59
+ end
60
+
61
+ class ThirdPartyAttributeExtension
62
+ EXTENSION_TYPE = 'THIRD_PARTY_ATTRIBUTE'
63
+
64
+ # @return [ThirdPartyAttributeExtensionContent]
65
+ attr_reader :content
66
+
67
+ # @return [String]
68
+ attr_reader :type
69
+
70
+ #
71
+ # @param [ThirdPartyAttributeExtensionContent] content
72
+ #
73
+ def initialize(content = nil)
74
+ @content = content
75
+ @type = EXTENSION_TYPE
76
+ end
77
+
78
+ def as_json(*_args)
79
+ json = {}
80
+ json[:type] = @type
81
+ json[:content] = @content.as_json unless @content.nil?
82
+ json
83
+ end
84
+
85
+ def to_json(*_args)
86
+ as_json.to_json
87
+ end
88
+
89
+ #
90
+ # @return [ThirdPartyAttributeExtensionBuilder]
91
+ #
92
+ def self.builder
93
+ ThirdPartyAttributeExtensionBuilder.new
94
+ end
95
+ end
96
+
97
+ class ThirdPartyAttributeExtensionContent
98
+ #
99
+ # @param [DateTime,Time] expiry_date
100
+ # @param [Array<ThirdPartyAttributeDefinition>] definitions
101
+ #
102
+ def initialize(expiry_date, definitions)
103
+ @expiry_date = expiry_date
104
+ @definitions = definitions
105
+ end
106
+
107
+ def as_json(*_args)
108
+ json = {}
109
+ json[:expiry_date] = @expiry_date.to_time.utc.strftime('%FT%T.%3NZ') unless @expiry_date.nil?
110
+ json[:definitions] = @definitions.map(&:as_json)
111
+ json
112
+ end
113
+
114
+ def to_json(*_args)
115
+ as_json.to_json
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yoti
4
+ module DynamicSharingService
5
+ # Extension for transactional flows
6
+ class TransactionalFlowExtension
7
+ EXTENSION_TYPE = 'TRANSACTIONAL_FLOW'
8
+ attr_reader :content
9
+ attr_reader :type
10
+
11
+ def initialize
12
+ @type = EXTENSION_TYPE
13
+ end
14
+
15
+ def to_json(*_args)
16
+ as_json.to_json
17
+ end
18
+
19
+ def as_json(*_args)
20
+ {
21
+ content: @content,
22
+ type: @type
23
+ }
24
+ end
25
+
26
+ def self.builder
27
+ TransactionalFlowExtensionBuilder.new
28
+ end
29
+ end
30
+
31
+ # Builder for TransactionalFlowExtension
32
+ class TransactionalFlowExtensionBuilder
33
+ def initialize
34
+ @extension = TransactionalFlowExtension.new
35
+ end
36
+
37
+ def with_content(content)
38
+ @extension.instance_variable_set(:@content, content)
39
+ self
40
+ end
41
+
42
+ def build
43
+ Marshal.load Marshal.dump @extension
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yoti
4
+ module DynamicSharingService
5
+ # Describes a policy for a dynamic share
6
+ class DynamicPolicy
7
+ SELFIE_AUTH_TYPE = 1
8
+ PIN_AUTH_TYPE = 2
9
+
10
+ attr_reader :wanted_auth_types
11
+ attr_reader :wanted
12
+
13
+ def wanted_remember_me
14
+ return true if @wanted_remember_me
15
+
16
+ false
17
+ end
18
+
19
+ def to_json(*args)
20
+ as_json.to_json(*args)
21
+ end
22
+
23
+ def as_json(*_args)
24
+ {
25
+ wanted_auth_types: @wanted_auth_types,
26
+ wanted: @wanted
27
+ }
28
+ end
29
+
30
+ def self.builder
31
+ DynamicPolicyBuilder.new
32
+ end
33
+ end
34
+
35
+ # Builder for DynamicPolicy
36
+ class DynamicPolicyBuilder
37
+ def initialize
38
+ @policy = DynamicPolicy.new
39
+ @wanted_auth_types = {}
40
+ @wanted_attributes = {}
41
+ end
42
+
43
+ def build
44
+ @policy.instance_variable_set(
45
+ :@wanted_auth_types,
46
+ @wanted_auth_types
47
+ .select { |_, wanted| wanted }
48
+ .keys
49
+ )
50
+ @policy.instance_variable_set(:@wanted, @wanted_attributes.values)
51
+ Marshal.load Marshal.dump @policy
52
+ end
53
+
54
+ #
55
+ # @param [Bool] wanted
56
+ #
57
+ def with_wanted_remember_me(wanted = true)
58
+ @policy.instance_variable_set(:@wanted_remember_me, wanted)
59
+ self
60
+ end
61
+
62
+ #
63
+ # @param [Integer] auth
64
+ # @param [Bool] wanted
65
+ #
66
+ def with_wanted_auth_type(auth, wanted = true)
67
+ @wanted_auth_types[auth] = wanted
68
+ self
69
+ end
70
+
71
+ #
72
+ # @param [Bool] wanted
73
+ #
74
+ def with_selfie_auth(wanted = true)
75
+ with_wanted_auth_type(DynamicPolicy::SELFIE_AUTH_TYPE, wanted)
76
+ end
77
+
78
+ #
79
+ # @param [Bool] wanted
80
+ #
81
+ def with_pin_auth(wanted = true)
82
+ with_wanted_auth_type(DynamicPolicy::PIN_AUTH_TYPE, wanted)
83
+ end
84
+
85
+ #
86
+ # @param [Yoti::DynamicSharingService::WantedAttribute] attribute
87
+ #
88
+ def with_wanted_attribute(attribute)
89
+ key = attribute.derivation || attribute.name
90
+ @wanted_attributes[key] = attribute
91
+ self
92
+ end
93
+
94
+ #
95
+ # @param [String] name
96
+ # @param [Hash] constraints
97
+ #
98
+ def with_wanted_attribute_by_name(name, constraints: nil)
99
+ attribute_builder = WantedAttribute.builder.with_name(name)
100
+ constraints&.each do |constraint|
101
+ attribute_builder.with_constraint constraint
102
+ end
103
+ attribute = attribute_builder.build
104
+ with_wanted_attribute attribute
105
+ end
106
+
107
+ def with_family_name(options = {})
108
+ with_wanted_attribute_by_name Attribute::FAMILY_NAME, **options
109
+ end
110
+
111
+ def with_given_names(options = {})
112
+ with_wanted_attribute_by_name Attribute::GIVEN_NAMES, **options
113
+ end
114
+
115
+ def with_full_name(options = {})
116
+ with_wanted_attribute_by_name Attribute::FULL_NAME, **options
117
+ end
118
+
119
+ def with_date_of_birth(options = {})
120
+ with_wanted_attribute_by_name Attribute::DATE_OF_BIRTH, **options
121
+ end
122
+
123
+ #
124
+ # @param [String] derivation
125
+ # @param [Hash] constraints
126
+ #
127
+ def with_age_derived_attribute(derivation, constraints: nil)
128
+ attribute_builder = WantedAttribute.builder
129
+ attribute_builder.with_name(Attribute::DATE_OF_BIRTH)
130
+ attribute_builder.with_derivation(derivation)
131
+ constraints&.each do |constraint|
132
+ attribute_builder.with_constraint constraint
133
+ end
134
+ with_wanted_attribute(attribute_builder.build)
135
+ end
136
+
137
+ #
138
+ # @param [Integer] derivation
139
+ #
140
+ def with_age_over(age, options = {})
141
+ with_age_derived_attribute(Attribute::AGE_OVER + age.to_s, **options)
142
+ end
143
+
144
+ #
145
+ # @param [Integer] derivation
146
+ #
147
+ def with_age_under(age, options = {})
148
+ with_age_derived_attribute(Attribute::AGE_UNDER + age.to_s, **options)
149
+ end
150
+
151
+ def with_gender(options = {})
152
+ with_wanted_attribute_by_name Attribute::GENDER, **options
153
+ end
154
+
155
+ def with_postal_address(options = {})
156
+ with_wanted_attribute_by_name(Attribute::POSTAL_ADDRESS, **options)
157
+ end
158
+
159
+ def with_structured_postal_address(options = {})
160
+ with_wanted_attribute_by_name(Attribute::STRUCTURED_POSTAL_ADDRESS, **options)
161
+ end
162
+
163
+ def with_nationality(options = {})
164
+ with_wanted_attribute_by_name(Attribute::NATIONALITY, **options)
165
+ end
166
+
167
+ def with_phone_number(options = {})
168
+ with_wanted_attribute_by_name(Attribute::PHONE_NUMBER, **options)
169
+ end
170
+
171
+ def with_selfie(options = {})
172
+ with_wanted_attribute_by_name(Attribute::SELFIE, **options)
173
+ end
174
+
175
+ def with_email(options = {})
176
+ with_wanted_attribute_by_name(Attribute::EMAIL_ADDRESS, **options)
177
+ end
178
+
179
+ def with_document_details
180
+ with_wanted_attribute_by_name(Attribute::DOCUMENT_DETAILS)
181
+ end
182
+ end
183
+ end
184
+ end