selfsdk 0.0.196 → 0.0.197

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19017fa46da285bdfa8c3a36adca6321fa3f6f1b84eccb34d7949761f87736a5
4
- data.tar.gz: 4e15f24fd771ea496cf3f5e00d7a29e7cef88eb701d9228a217c5d9533f71c70
3
+ metadata.gz: 88cd6714a5c258e5777b5c7ce465c998b9215fb16459e1687282e3695961fb2a
4
+ data.tar.gz: b05a49bc266ba95b6a957bea27b31edd5216afeea30dc159ca134b65ecf59261
5
5
  SHA512:
6
- metadata.gz: 4648c3554ce576e4dcdf0198b4fa7fabf0afe43d93f1406cd02a618501d9d024e0309bd5446c6a12ec277467bec2d8ca10da9fd9dbbbb4e2958979a28cf9017f
7
- data.tar.gz: 74938c4b8b9f4361af474cbd87082ae2d335c1585ed9783a1b03c41fc93aa7a3a7c68f885f6b942ff6aa40b3fd4f88858ef3c98ec281aa17c9f33d6fbc62ba8c
6
+ metadata.gz: e9bea262aad81d5125dce00ce7afebb05b454eec6e7c26ab8a147ac5177894add5ae827158418100944bd729f8378c59d0296b57a792e688658edf917f2f7b01
7
+ data.tar.gz: 2aafa0e3b09648a67e95d662e19694faa9fb56fe90161cb44f045108f5aee004611390e9e702e0b198a0d9516d21e90ec61170a9b79d70f4b66c1a8694b87a3b
data/lib/authenticated.rb CHANGED
@@ -14,6 +14,7 @@ module SelfSDK
14
14
 
15
15
  def accepted?
16
16
  return false if @payload.nil?
17
+ return false if @payload[:auth] != true
17
18
 
18
19
  @payload[:status] == "accepted"
19
20
  end
@@ -12,7 +12,12 @@ module SelfSDK
12
12
  MSG_TYPE = "identities.facts.query.req"
13
13
  DEFAULT_EXP_TIMEOUT = 900
14
14
 
15
- attr_accessor :facts, :options
15
+ attr_accessor :facts, :options, :auth
16
+
17
+ def initialize(messaging)
18
+ @typ = MSG_TYPE
19
+ super
20
+ end
16
21
 
17
22
  def parse_facts(facts)
18
23
  @facts = []
@@ -82,6 +87,7 @@ module SelfSDK
82
87
  b = {
83
88
  typ: MSG_TYPE,
84
89
  iss: @jwt.id,
90
+ aud: @to,
85
91
  sub: @to,
86
92
  iat: SelfSDK::Time.now.strftime('%FT%TZ'),
87
93
  exp: (SelfSDK::Time.now + @exp_timeout).strftime('%FT%TZ'),
@@ -13,6 +13,11 @@ module SelfSDK
13
13
 
14
14
  attr_accessor :facts, :audience, :auth
15
15
 
16
+ def initialize(messaging)
17
+ @typ = MSG_TYPE
18
+ super
19
+ end
20
+
16
21
  def parse(input, envelope=nil)
17
22
  @input = input
18
23
  @typ = MSG_TYPE
@@ -84,6 +89,10 @@ module SelfSDK
84
89
  auth: @auth }
85
90
  end
86
91
 
92
+ def auth_response?
93
+ @auth == true
94
+ end
95
+
87
96
  protected
88
97
 
89
98
  def proto(to_device)
@@ -4,8 +4,6 @@
4
4
 
5
5
  require_relative "fact_request"
6
6
  require_relative "fact_response"
7
- require_relative "authentication_resp"
8
- require_relative "authentication_req"
9
7
  require_relative "chat_message"
10
8
  require_relative "chat_message_read"
11
9
  require_relative "chat_message_delivered"
@@ -30,18 +28,12 @@ module SelfSDK
30
28
  payload = JSON.parse(messaging.jwt.decode(jwt[:payload]), symbolize_names: true)
31
29
 
32
30
  case payload[:typ]
33
- when "identities.facts.query.req"
31
+ when SelfSDK::Messages::FactRequest::MSG_TYPE
34
32
  m = FactRequest.new(messaging)
35
33
  m.parse(body, envelope)
36
- when "identities.facts.query.resp"
34
+ when SelfSDK::Messages::FactResponse::MSG_TYPE
37
35
  m = FactResponse.new(messaging)
38
36
  m.parse(body, envelope)
39
- when "identities.authenticate.resp"
40
- m = AuthenticationResp.new(messaging)
41
- m.parse(body, envelope)
42
- when "identities.authenticate.req"
43
- m = AuthenticationReq.new(messaging)
44
- m.parse(body, envelope)
45
37
  when SelfSDK::Messages::ChatMessage::MSG_TYPE
46
38
  m = ChatMessage.new(messaging)
47
39
  m.parse(body, envelope)
data/lib/selfsdk.rb CHANGED
@@ -17,6 +17,7 @@ require_relative 'authenticated'
17
17
  require_relative 'acl'
18
18
  require_relative 'sources'
19
19
  require_relative 'services/auth'
20
+ require_relative 'services/requester'
20
21
  require_relative 'services/facts'
21
22
  require_relative 'services/identity'
22
23
  require_relative 'services/messaging'
@@ -66,12 +67,12 @@ module SelfSDK
66
67
 
67
68
  # Provides access to SelfSDK::Services::Facts service
68
69
  def facts
69
- @facts ||= SelfSDK::Services::Facts.new(messaging, @client)
70
+ @facts ||= SelfSDK::Services::Facts.new(requester)
70
71
  end
71
72
 
72
73
  # Provides access to SelfSDK::Services::Authentication service
73
74
  def authentication
74
- @authentication ||= SelfSDK::Services::Authentication.new(messaging, @client)
75
+ @authentication ||= SelfSDK::Services::Authentication.new(requester)
75
76
  end
76
77
 
77
78
  # Provides access to SelfSDK::Services::Identity service
@@ -109,6 +110,10 @@ module SelfSDK
109
110
 
110
111
  protected
111
112
 
113
+ def requester
114
+ @requester ||= SelfSDK::Services::Requester.new(messaging, @client)
115
+ end
116
+
112
117
  def base_url(opts)
113
118
  return opts[:base_url] if opts.key? :base_url
114
119
  return "https://api.#{opts[:env].to_s}.joinself.com" if opts.key? :env
data/lib/services/auth.rb CHANGED
@@ -16,10 +16,8 @@ module SelfSDK
16
16
  # @param client [SelfSDK::Client] http client object.
17
17
  #
18
18
  # @return [SelfSDK::Services::Authentication] authentication service.
19
- def initialize(messaging, client)
20
- @messaging = messaging.client
21
- @messaging_service = messaging
22
- @client = client
19
+ def initialize(requester)
20
+ @requester = requester
23
21
  end
24
22
 
25
23
  # Sends an authentication request to the specified selfid.
@@ -30,6 +28,7 @@ module SelfSDK
30
28
  # @param [String] selfid the receiver of the authentication request.
31
29
  # @param [Hash] opts the options to authenticate.
32
30
  # @option opts [String] :cid The unique identifier of the authentication request.
31
+ # @option opts [Array] :facts array of facts to be requested
33
32
  # @yield [request] Invokes the block with an authentication response for each result.
34
33
  # @return [String, String] conversation id or encoded body.
35
34
  #
@@ -38,29 +37,21 @@ module SelfSDK
38
37
  # @param [Hash] opts the options to authenticate.
39
38
  # @option [Boolean] :async if the request is asynchronous.
40
39
  # @option opts [String] :cid The unique identifier of the authentication request.
40
+ # @option opts [Array] :facts array of facts to be requested
41
41
  # @return [String, String] conversation id or encoded body.
42
42
  def request(selfid, opts = {}, &block)
43
- SelfSDK.logger.info "authenticating #{selfid}"
44
- rq = opts.fetch(:request, true)
45
- if rq
46
- raise "You're not permitting connections from #{selfid}" unless @messaging_service.is_permitted?(selfid)
47
- end
48
-
49
- req = SelfSDK::Messages::AuthenticationReq.new(@messaging)
50
- req.populate(selfid, opts)
51
-
52
- body = @client.jwt.prepare(req.body)
53
- return body unless rq
54
- return req.send_message if opts.fetch(:async, false)
55
-
56
- # when a block is given the request will always be asynchronous.
57
- if block_given?
58
- @messaging.set_observer(req, timeout: req.exp_timeout, &block)
59
- return req.send_message
60
- end
61
-
62
- # Otherwise the request is synchronous
63
- req.request
43
+ opts[:auth] = true
44
+ facts = opts.fetch(:facts, [])
45
+
46
+ @requester.request(selfid, facts, opts, &block)
47
+ end
48
+
49
+ # Adds an observer for a fact response
50
+ # Whenever you receive a fact response registered observers will receive a notification.
51
+ #
52
+ # @yield [request] Invokes the block with a fact response message.
53
+ def subscribe(&block)
54
+ @requester.subscribe(true, &block)
64
55
  end
65
56
 
66
57
  # Generates a QR code so users can authenticate to your app.
@@ -70,10 +61,10 @@ module SelfSDK
70
61
  #
71
62
  # @return [String, String] conversation id or encoded body.
72
63
  def generate_qr(opts = {})
73
- opts[:request] = false
74
- selfid = opts.fetch(:selfid, "-")
75
- req = request(selfid, opts)
76
- ::RQRCode::QRCode.new(req, level: 'l')
64
+ opts[:auth] = true
65
+ facts = opts.fetch(:facts, [])
66
+
67
+ @requester.generate_qr(facts, opts)
77
68
  end
78
69
 
79
70
  # Generates a deep link to authenticate with self app.
@@ -84,24 +75,10 @@ module SelfSDK
84
75
  #
85
76
  # @return [String, String] conversation id or encoded body.
86
77
  def generate_deep_link(callback, opts = {})
87
- opts[:request] = false
88
- selfid = opts.fetch(:selfid, "-")
89
- body = @client.jwt.encode(request(selfid, opts))
90
-
91
- if @client.env.empty?
92
- return "https://links.joinself.com/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app"
93
- elsif @client.env == 'development'
94
- return "https://links.joinself.com/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app.dev"
95
- end
96
- "https://#{@client.env}.links.joinself.com/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app.#{@client.env}"
97
- end
78
+ opts[:auth] = true
79
+ facts = opts.fetch(:facts, [])
98
80
 
99
- # Adds an observer for an authentication response
100
- def subscribe(&block)
101
- @messaging.subscribe :authentication_response do |res|
102
- valid_payload(res.input)
103
- yield(res)
104
- end
81
+ @requester.generate_deep_link(facts, callback, opts)
105
82
  end
106
83
 
107
84
  private
@@ -130,27 +107,6 @@ module SelfSDK
130
107
  nil
131
108
  end
132
109
 
133
- # Prepares an authentication payload to be sent to a user.
134
- #
135
- # @param selfid [string] the selfid of the user you want to send the auth request to.
136
- # @param cid [string] the conversation id to be used.
137
- def prepare_payload(selfid, cid)
138
- # TODO should this be moved to its own message/auth_req.rb?
139
- body = {
140
- typ: 'identities.authenticate.req',
141
- aud: @client.self_url,
142
- iss: @client.jwt.id,
143
- sub: selfid,
144
- iat: SelfSDK::Time.now.strftime('%FT%TZ'),
145
- exp: (SelfSDK::Time.now + 3600).strftime('%FT%TZ'),
146
- cid: cid,
147
- jti: SecureRandom.uuid,
148
- device_id: @messaging.device_id,
149
- }
150
-
151
- @client.jwt.prepare(body)
152
- end
153
-
154
110
  def parse_payload(response)
155
111
  jws = @client.jwt.parse(response)
156
112
  return unless jws.include? :payload
@@ -161,7 +117,7 @@ module SelfSDK
161
117
  identity = @client.entity(payload[:sub])
162
118
  return if identity.nil?
163
119
 
164
- return payload
120
+ payload
165
121
  end
166
122
  end
167
123
  end
@@ -18,10 +18,8 @@ module SelfSDK
18
18
  # @param client [SelfSDK::Client] http client object.
19
19
  #
20
20
  # @return [SelfSDK::Services::Facts] facts service.
21
- def initialize(messaging, client)
22
- @messaging = messaging.client
23
- @messaging_service = messaging
24
- @client = client
21
+ def initialize(requester)
22
+ @requester = requester
25
23
  end
26
24
 
27
25
  # Sends a fact request to the specified selfid.
@@ -29,45 +27,24 @@ module SelfSDK
29
27
  # permission.
30
28
  #
31
29
  # @overload request(selfid, facts, opts = {}, &block)
32
- # @param selfid [string] the receiver of the authentication request.
33
- # @param [Hash] opts the options to authenticate.
34
- # @option opts [String] :cid The unique identifier of the authentication request.
30
+ # @param selfid [string] the receiver of the fact request.
31
+ # @param facts [Array] array of facts to be requested
32
+ # @param [Hash] opts the options to process the request.
33
+ # @option opts [String] :cid The unique identifier of the fact request.
35
34
  # @yield [request] Invokes the given block when a response is received.
36
35
  # @return [Object] SelfSDK:::Messages::FactRequest
37
36
  #
38
37
  # @overload request(selfid, facts, opts = {})
39
- # @param selfid [string] the receiver of the authentication request.
40
- # @param [Hash] opts the options to authenticate.
41
- # @option opts [String] :cid The unique identifier of the authentication request.
38
+ # @param selfid [string] the receiver of the fact request.
39
+ # @param facts [Array] array of facts to be requested
40
+ # @param [Hash] opts the options to request.
41
+ # @option opts [String] :cid The unique identifier of the fact request.
42
42
  # @option opts [Integer] :exp_timeout timeout in seconds to expire the request.
43
43
  # @option opts [Integer] :allowed_for number of seconds for enabling recurrent requests.
44
- # @option opts [Boolean] :auth allows displaying the request as anuthentication request with facts.
45
44
  # @return [Object] SelfSDK:::Messages::FactRequest
46
45
  def request(selfid, facts, opts = {}, &block)
47
- SelfSDK.logger.info "authenticating #{selfid}"
48
- rq = opts.fetch(:request, true)
49
- if rq
50
- raise "You're not permitting connections from #{selfid}" unless @messaging_service.is_permitted?(selfid)
51
- end
52
-
53
- req = SelfSDK::Messages::FactRequest.new(@messaging)
54
- req.populate(selfid, prepare_facts(facts), opts)
55
-
56
- body = @client.jwt.prepare(req.body)
57
- return body unless rq
58
-
59
- # when a block is given the request will always be asynchronous.
60
- if block_given?
61
- @messaging.set_observer(req, timeout: req.exp_timeout, &block)
62
- return req.send_message
63
- end
64
-
65
- if opts[:async] == true
66
- return req.send_message
67
- end
68
-
69
- # Otherwise the request is synchronous
70
- req.request
46
+ opts[:auth] = false # force auth to false as you have auth service to make auth requests
47
+ @requester.request(selfid, facts, opts, &block)
71
48
  end
72
49
 
73
50
  # Sends a request through an intermediary.
@@ -81,8 +58,7 @@ module SelfSDK
81
58
  # @option opts [String] intermediary an intermediary identity to be used.
82
59
  # @return [Object] SelfSDK:::Messages::FactRequest
83
60
  def request_via_intermediary(selfid, facts, opts = {}, &block)
84
- opts[:intermediary] = opts.fetch(:intermediary, DEFAULT_INTERMEDIARY)
85
- request(selfid, facts, opts, &block)
61
+ @requester.request_via_intermediary(selfid, facts, opts, &block)
86
62
  end
87
63
 
88
64
  # Adds an observer for a fact response
@@ -90,7 +66,7 @@ module SelfSDK
90
66
  #
91
67
  # @yield [request] Invokes the block with a fact response message.
92
68
  def subscribe(&block)
93
- @messaging.subscribe(:fact_response, &block)
69
+ @requester.subscribe(false, &block)
94
70
  end
95
71
 
96
72
  # Generates a QR code so users can send facts to your app.
@@ -101,10 +77,8 @@ module SelfSDK
101
77
  #
102
78
  # @return [String, String] conversation id or encoded body.
103
79
  def generate_qr(facts, opts = {})
104
- opts[:request] = false
105
- selfid = opts.fetch(:selfid, "-")
106
- req = request(selfid, facts, opts)
107
- ::RQRCode::QRCode.new(req, level: 'l')
80
+ opts[:auth] = false
81
+ @requester.generate_qr(facts, opts)
108
82
  end
109
83
 
110
84
  # Generates a deep link to authenticate with self app.
@@ -116,114 +90,8 @@ module SelfSDK
116
90
  #
117
91
  # @return [String, String] conversation id or encoded body.
118
92
  def generate_deep_link(facts, callback, opts = {})
119
- opts[:request] = false
120
- selfid = opts.fetch(:selfid, "-")
121
- body = @client.jwt.encode(request(selfid, facts, opts))
122
-
123
- if @client.env.empty?
124
- return "https://links.joinself.com/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app"
125
- elsif @client.env == 'development'
126
- return "https://links.joinself.com/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app.dev"
127
- end
128
- "https://#{@client.env}.links.joinself.com/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app.#{@client.env}"
129
- end
130
-
131
- private
132
-
133
- # As request facts can accept an array of strings this populates with necessary
134
- # structure this short fact definitions.
135
- #
136
- # @param facts [Array] an array of strings or hashes.
137
- # @return [Array] a list of hashed facts.
138
- def prepare_facts(facts)
139
- fs = []
140
- facts.each do |f|
141
- fact = if f.is_a?(Hash)
142
- f
143
- else
144
- { fact: f }
145
- end
146
- # validate_fact!(fact)
147
- fs << fact
148
- end
149
- fs
150
- end
151
-
152
- def validate_fact!(f)
153
- errInvalidFactToSource = 'provided source does not support given fact'
154
- errInvalidSource = 'provided fact does not specify a valid source'
155
-
156
- raise 'provided fact does not specify a name' if f[:fact].empty?
157
- return unless f.has_key? :sources
158
-
159
- valid_sources = [SOURCE_USER_SPECIFIED,
160
- SOURCE_PASSPORT,
161
- SOURCE_DRIVING_LICENSE,
162
- SOURCE_IDENTITY_CARD,
163
- SOURCE_TWITTER,
164
- SOURCE_LINKEDIN,
165
- SOURCE_FACEBOK]
166
- fact_for_passport = [FACT_DOCUMENT_NUMBER,
167
- FACT_SURNAME,
168
- FACT_GIVEN_NAMES,
169
- FACT_DATE_OF_BIRTH,
170
- FACT_DATE_OF_EXPIRATION,
171
- FACT_SEX,
172
- FACT_NATIONALITY,
173
- FACT_COUNTRY_OF_ISSUANCE]
174
-
175
- facts_for_dl = [FACT_DOCUMENT_NUMBER,
176
- FACT_SURNAME,
177
- FACT_GIVEN_NAMES,
178
- FACT_DATE_OF_BIRTH,
179
- FACT_DATE_OF_ISSUANCE,
180
- FACT_DATE_OF_EXPIRATION,
181
- FACT_ADDRESS,
182
- FACT_ISSUING_AUTHORITY,
183
- FACT_PLACE_OF_BIRTH,
184
- FACT_COUNTRY_OF_ISSUANCE]
185
-
186
- facts_for_user = [FACT_DOCUMENT_NUMBER,
187
- FACT_DISPLAY_NAME,
188
- FACT_EMAIL,
189
- FACT_PHONE]
190
-
191
- facts_for_twitter = [FACT_ACCOUNT_ID, FACT_NICKNAME]
192
- facts_for_linkedin = [FACT_ACCOUNT_ID, FACT_NICKNAME]
193
- facts_for_facebook = [FACT_ACCOUNT_ID, FACT_NICKNAME]
194
- facts_for_live = [FACT_SELFIE]
195
-
196
- f[:sources].each do |s|
197
- raise errInvalidSource unless valid_sources.include? s.to_s
198
-
199
- if s.to_s == SOURCE_PASSPORT || s.to_s == SOURCE_IDENTITY_CARD
200
- raise errInvalidFactToSource unless fact_for_passport.include? f[:fact]
201
- end
202
-
203
- if s.to_s == SOURCE_DRIVING_LICENSE
204
- raise errInvalidFactToSource unless facts_for_dl.include? f[:fact]
205
- end
206
-
207
- if s.to_s == SOURCE_USER_SPECIFIED
208
- raise errInvalidFactToSource unless facts_for_user.include? f[:fact].to_s
209
- end
210
-
211
- if s.to_s == SOURCE_TWITTER
212
- raise errInvalidFactToSource unless facts_for_twitter.include? f[:fact].to_s
213
- end
214
-
215
- if s.to_s == SOURCE_LINKEDIN
216
- raise errInvalidFactToSource unless facts_for_linkedin.include? f[:fact].to_s
217
- end
218
-
219
- if s.to_s == SOURCE_FACEBOOK
220
- raise errInvalidFactToSource unless facts_for_facebook.include? f[:fact].to_s
221
- end
222
-
223
- if s.to_s == SOURCE_LIVE
224
- raise errInvalidFactToSource unless facts_for_live.include? f[:fact].to_s
225
- end
226
- end
93
+ opts[:auth] = false
94
+ @requester.generate_deep_link(facts, callback, opts)
227
95
  end
228
96
  end
229
97
  end
@@ -26,7 +26,7 @@ module SelfSDK
26
26
  # Subscribes to a specific message type and attaches the given observer
27
27
  # which will be executed when a meeting criteria message is received.
28
28
  #
29
- # @param [String] type message type (ex: SelfSDK::Messages::AuthenticationResp.MSG_TYPE
29
+ # @param [String] type message type (ex: SelfSDK::Messages::FactRequest.MSG_TYPE
30
30
  # @yield [SelfSDK::Messages::Message] receives incoming message.
31
31
  def subscribe(type, &block)
32
32
  @client.subscribe(type, &block)
@@ -0,0 +1,242 @@
1
+ # Copyright 2020 Self Group Ltd. All Rights Reserved.
2
+
3
+ # frozen_string_literal: true
4
+
5
+ # Namespace for classes and modules that handle SelfSDK gem
6
+ module SelfSDK
7
+ # Namespace for classes and modules that handle selfsdk-gem public ui
8
+ module Services
9
+ # Self provides this self-hosted verified intermediary.
10
+ DEFAULT_INTERMEDIARY = "self_intermediary"
11
+ # Input class to handle fact requests on self network.
12
+ class Requester
13
+ # Creates a new facts service.
14
+ # Facts service mainly manages fact requests against self users wanting
15
+ # to share their verified facts with your app.
16
+ #
17
+ # @param messaging [SelfSDK::Messaging] messaging object.
18
+ # @param client [SelfSDK::Client] http client object.
19
+ #
20
+ # @return [SelfSDK::Services::Facts] facts service.
21
+ def initialize(messaging, client)
22
+ @messaging = messaging.client
23
+ @messaging_service = messaging
24
+ @client = client
25
+ end
26
+
27
+ # Sends a fact request to the specified selfid.
28
+ # An fact request allows your app to access trusted facts of your user with its
29
+ # permission.
30
+ #
31
+ # @overload request(selfid, facts, opts = {}, &block)
32
+ # @param selfid [string] the receiver of the authentication request.
33
+ # @param [Hash] opts the options to authenticate.
34
+ # @option opts [String] :cid The unique identifier of the authentication request.
35
+ # @yield [request] Invokes the given block when a response is received.
36
+ # @return [Object] SelfSDK:::Messages::FactRequest
37
+ #
38
+ # @overload request(selfid, facts, opts = {})
39
+ # @param selfid [string] the receiver of the authentication request.
40
+ # @param [Hash] opts the options to authenticate.
41
+ # @option opts [String] :cid The unique identifier of the authentication request.
42
+ # @option opts [Integer] :exp_timeout timeout in seconds to expire the request.
43
+ # @option opts [Integer] :allowed_for number of seconds for enabling recurrent requests.
44
+ # @option opts [Boolean] :auth allows displaying the request as anuthentication request with facts.
45
+ # @return [Object] SelfSDK:::Messages::FactRequest
46
+ def request(selfid, facts, opts = {}, &block)
47
+ SelfSDK.logger.info "authenticating #{selfid}"
48
+ rq = opts.fetch(:request, true)
49
+ if rq
50
+ raise "You're not permitting connections from #{selfid}" unless @messaging_service.is_permitted?(selfid)
51
+ end
52
+
53
+ req = SelfSDK::Messages::FactRequest.new(@messaging)
54
+ req.populate(selfid, prepare_facts(facts), opts)
55
+
56
+ body = @client.jwt.prepare(req.body)
57
+ return body unless rq
58
+
59
+ # when a block is given the request will always be asynchronous.
60
+ if block_given?
61
+ @messaging.set_observer(req, timeout: req.exp_timeout, &block)
62
+ return req.send_message
63
+ end
64
+
65
+ if opts[:async] == true
66
+ return req.send_message
67
+ end
68
+
69
+ # Otherwise the request is synchronous
70
+ req.request
71
+ end
72
+
73
+ # Sends a request through an intermediary.
74
+ # An intermediary is an entity trusted by the user and acting as a proxy between you
75
+ # and the recipient of your fact request.
76
+ # Intermediaries usually do not provide the original user facts, but they create its
77
+ # own assertions based on your request and the user's facts.
78
+ #
79
+ # @param selfid [string] the receiver of the authentication request.
80
+ # @param [Hash] opts the options to authenticate.
81
+ # @option opts [String] intermediary an intermediary identity to be used.
82
+ # @return [Object] SelfSDK:::Messages::FactRequest
83
+ def request_via_intermediary(selfid, facts, opts = {}, &block)
84
+ opts[:intermediary] = opts.fetch(:intermediary, DEFAULT_INTERMEDIARY)
85
+ request(selfid, facts, opts, &block)
86
+ end
87
+
88
+ # Adds an observer for a fact response
89
+ # Whenever you receive a fact response registered observers will receive a notification.
90
+ #
91
+ # @yield [request] Invokes the block with a fact response message.
92
+ def subscribe(auth, &block)
93
+ if auth == true
94
+ @auth_subscription = block
95
+ else
96
+ @fact_subscription = block
97
+ end
98
+
99
+ @messaging.subscribe :fact_response do |res|
100
+ if res.auth_response?
101
+ @auth_subscription&.call(res)
102
+ else
103
+ @fact_subscription&.call(res)
104
+ end
105
+ end
106
+ end
107
+
108
+ # Generates a QR code so users can send facts to your app.
109
+ #
110
+ # @param facts [Array] a list of facts to be requested.
111
+ # @option opts [String] :cid The unique identifier of the authentication request.
112
+ # @option opts [String] :options Options you want to share with the identity.
113
+ #
114
+ # @return [String, String] conversation id or encoded body.
115
+ def generate_qr(facts, opts = {})
116
+ opts[:request] = false
117
+ selfid = opts.fetch(:selfid, "-")
118
+ req = request(selfid, facts, opts)
119
+ ::RQRCode::QRCode.new(req, level: 'l')
120
+ end
121
+
122
+ # Generates a deep link to authenticate with self app.
123
+ #
124
+ # @param facts [Array] a list of facts to be requested.
125
+ # @param callback [String] the url you'll be redirected if the app is not installed.
126
+ # @option opts [String] :selfid the user selfid you want to authenticate.
127
+ # @option opts [String] :cid The unique identifier of the authentication request.
128
+ #
129
+ # @return [String, String] conversation id or encoded body.
130
+ def generate_deep_link(facts, callback, opts = {})
131
+ opts[:request] = false
132
+ selfid = opts.fetch(:selfid, "-")
133
+ body = @client.jwt.encode(request(selfid, facts, opts))
134
+
135
+ if @client.env.empty?
136
+ return "https://links.joinself.com/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app"
137
+ elsif @client.env == 'development'
138
+ return "https://links.joinself.com/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app.dev"
139
+ end
140
+ "https://#{@client.env}.links.joinself.com/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app.#{@client.env}"
141
+ end
142
+
143
+ private
144
+
145
+ # As request facts can accept an array of strings this populates with necessary
146
+ # structure this short fact definitions.
147
+ #
148
+ # @param facts [Array] an array of strings or hashes.
149
+ # @return [Array] a list of hashed facts.
150
+ def prepare_facts(facts)
151
+ fs = []
152
+ facts.each do |f|
153
+ fact = if f.is_a?(Hash)
154
+ f
155
+ else
156
+ { fact: f }
157
+ end
158
+ # validate_fact!(fact)
159
+ fs << fact
160
+ end
161
+ fs
162
+ end
163
+
164
+ def validate_fact!(f)
165
+ errInvalidFactToSource = 'provided source does not support given fact'
166
+ errInvalidSource = 'provided fact does not specify a valid source'
167
+
168
+ raise 'provided fact does not specify a name' if f[:fact].empty?
169
+ return unless f.has_key? :sources
170
+
171
+ valid_sources = [SOURCE_USER_SPECIFIED,
172
+ SOURCE_PASSPORT,
173
+ SOURCE_DRIVING_LICENSE,
174
+ SOURCE_IDENTITY_CARD,
175
+ SOURCE_TWITTER,
176
+ SOURCE_LINKEDIN,
177
+ SOURCE_FACEBOK]
178
+ fact_for_passport = [FACT_DOCUMENT_NUMBER,
179
+ FACT_SURNAME,
180
+ FACT_GIVEN_NAMES,
181
+ FACT_DATE_OF_BIRTH,
182
+ FACT_DATE_OF_EXPIRATION,
183
+ FACT_SEX,
184
+ FACT_NATIONALITY,
185
+ FACT_COUNTRY_OF_ISSUANCE]
186
+
187
+ facts_for_dl = [FACT_DOCUMENT_NUMBER,
188
+ FACT_SURNAME,
189
+ FACT_GIVEN_NAMES,
190
+ FACT_DATE_OF_BIRTH,
191
+ FACT_DATE_OF_ISSUANCE,
192
+ FACT_DATE_OF_EXPIRATION,
193
+ FACT_ADDRESS,
194
+ FACT_ISSUING_AUTHORITY,
195
+ FACT_PLACE_OF_BIRTH,
196
+ FACT_COUNTRY_OF_ISSUANCE]
197
+
198
+ facts_for_user = [FACT_DOCUMENT_NUMBER,
199
+ FACT_DISPLAY_NAME,
200
+ FACT_EMAIL,
201
+ FACT_PHONE]
202
+
203
+ facts_for_twitter = [FACT_ACCOUNT_ID, FACT_NICKNAME]
204
+ facts_for_linkedin = [FACT_ACCOUNT_ID, FACT_NICKNAME]
205
+ facts_for_facebook = [FACT_ACCOUNT_ID, FACT_NICKNAME]
206
+ facts_for_live = [FACT_SELFIE]
207
+
208
+ f[:sources].each do |s|
209
+ raise errInvalidSource unless valid_sources.include? s.to_s
210
+
211
+ if s.to_s == SOURCE_PASSPORT || s.to_s == SOURCE_IDENTITY_CARD
212
+ raise errInvalidFactToSource unless fact_for_passport.include? f[:fact]
213
+ end
214
+
215
+ if s.to_s == SOURCE_DRIVING_LICENSE
216
+ raise errInvalidFactToSource unless facts_for_dl.include? f[:fact]
217
+ end
218
+
219
+ if s.to_s == SOURCE_USER_SPECIFIED
220
+ raise errInvalidFactToSource unless facts_for_user.include? f[:fact].to_s
221
+ end
222
+
223
+ if s.to_s == SOURCE_TWITTER
224
+ raise errInvalidFactToSource unless facts_for_twitter.include? f[:fact].to_s
225
+ end
226
+
227
+ if s.to_s == SOURCE_LINKEDIN
228
+ raise errInvalidFactToSource unless facts_for_linkedin.include? f[:fact].to_s
229
+ end
230
+
231
+ if s.to_s == SOURCE_FACEBOOK
232
+ raise errInvalidFactToSource unless facts_for_facebook.include? f[:fact].to_s
233
+ end
234
+
235
+ if s.to_s == SOURCE_LIVE
236
+ raise errInvalidFactToSource unless facts_for_live.include? f[:fact].to_s
237
+ end
238
+ end
239
+ end
240
+ end
241
+ end
242
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Do not edit this file, autogenerate it with "rake sources:generate" instead
4
+ module SelfSDK
5
+ SOURCE_DATA = {
6
+ "sources" => {
7
+ "user_specified" => [
8
+ "document_number",
9
+ "display_name",
10
+ "email_address",
11
+ "phone_number"
12
+ ],
13
+ "passport" => [
14
+ "document_number",
15
+ "surname",
16
+ "given_names",
17
+ "date_of_birth",
18
+ "date_of_expiration",
19
+ "sex",
20
+ "nationality",
21
+ "country_of_issuance"
22
+ ],
23
+ "driving_license" => [
24
+ "document_number",
25
+ "surname",
26
+ "given_names",
27
+ "date_of_birth",
28
+ "date_of_issuance",
29
+ "date_of_expiration",
30
+ "address",
31
+ "issuing_authority",
32
+ "place_of_birth"
33
+ ],
34
+ "identity_card" => [
35
+ "document_number",
36
+ "surname",
37
+ "given_names",
38
+ "date_of_birth",
39
+ "date_of_expiration",
40
+ "sex",
41
+ "nationality",
42
+ "country_of_issuance"
43
+ ],
44
+ "twitter" => [
45
+ "account_id",
46
+ "nickname"
47
+ ],
48
+ "linkedin" => [
49
+ "account_id",
50
+ "nickname"
51
+ ],
52
+ "facebook" => [
53
+ "account_id",
54
+ "nickname"
55
+ ],
56
+ "live" => [
57
+ "selfie_verification"
58
+ ]
59
+ }
60
+ }
61
+ end
data/lib/sources.rb CHANGED
@@ -3,66 +3,12 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  require "json"
6
+ require_relative "source_definition.rb"
7
+
6
8
  module SelfSDK
7
9
  class Sources
8
10
  def initialize(sources_file)
9
- data = JSON.parse('{
10
- "sources": {
11
- "user_specified": [
12
- "document_number",
13
- "display_name",
14
- "email_address",
15
- "phone_number"
16
- ],
17
- "passport": [
18
- "document_number",
19
- "surname",
20
- "given_names",
21
- "date_of_birth",
22
- "date_of_expiration",
23
- "sex",
24
- "nationality",
25
- "country_of_issuance"
26
- ],
27
- "driving_license": [
28
- "document_number",
29
- "surname",
30
- "given_names",
31
- "date_of_birth",
32
- "date_of_issuance",
33
- "date_of_expiration",
34
- "address",
35
- "issuing_authority",
36
- "place_of_birth"
37
- ],
38
- "identity_card": [
39
- "document_number",
40
- "surname",
41
- "given_names",
42
- "date_of_birth",
43
- "date_of_expiration",
44
- "sex",
45
- "nationality",
46
- "country_of_issuance"
47
- ],
48
- "twitter": [
49
- "account_id",
50
- "nickname"
51
- ],
52
- "linkedin": [
53
- "account_id",
54
- "nickname"
55
- ],
56
- "facebook": [
57
- "account_id",
58
- "nickname"
59
- ],
60
- "live": [
61
- "selfie_verification"
62
- ]
63
- }
64
- }')
65
- @sources = data["sources"]
11
+ @sources = SOURCE_DATA["sources"]
66
12
  @facts = []
67
13
  @sources.each do |source, facts|
68
14
  @facts.push(*facts)
@@ -92,9 +38,7 @@ module SelfSDK
92
38
  end
93
39
 
94
40
  def message_type(s)
95
- types = { authentication_request: SelfSDK::Messages::AuthenticationReq::MSG_TYPE,
96
- authentication_response: SelfSDK::Messages::AuthenticationResp::MSG_TYPE,
97
- fact_request: SelfSDK::Messages::FactRequest::MSG_TYPE,
41
+ types = { fact_request: SelfSDK::Messages::FactRequest::MSG_TYPE,
98
42
  fact_response: SelfSDK::Messages::FactResponse::MSG_TYPE,
99
43
  chat_message: SelfSDK::Messages::ChatMessage::MSG_TYPE,
100
44
  chat_message_deivered: SelfSDK::Messages::ChatMessageDelivered::MSG_TYPE,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: selfsdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.196
4
+ version: 0.0.197
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aldgate Ventures
@@ -334,9 +334,6 @@ files:
334
334
  - lib/jwt_service.rb
335
335
  - lib/log.rb
336
336
  - lib/messages/attestation.rb
337
- - lib/messages/authentication_message.rb
338
- - lib/messages/authentication_req.rb
339
- - lib/messages/authentication_resp.rb
340
337
  - lib/messages/base.rb
341
338
  - lib/messages/chat.rb
342
339
  - lib/messages/chat_invite.rb
@@ -359,7 +356,9 @@ files:
359
356
  - lib/services/facts.rb
360
357
  - lib/services/identity.rb
361
358
  - lib/services/messaging.rb
359
+ - lib/services/requester.rb
362
360
  - lib/signature_graph.rb
361
+ - lib/source_definition.rb
363
362
  - lib/sources.rb
364
363
  homepage: https://www.joinself.com/
365
364
  licenses:
@@ -1,31 +0,0 @@
1
- # Copyright 2020 Self Group Ltd. All Rights Reserved.
2
-
3
- # frozen_string_literal: true
4
-
5
- require_relative 'base'
6
- require_relative '../ntptime'
7
-
8
- module SelfSDK
9
- module Messages
10
- class AuthenticationMessage < Base
11
-
12
- def parse(input, envelope=nil)
13
- @input = input
14
- @typ = @typ
15
- @payload = get_payload input
16
- @id = payload[:cid]
17
- @from = payload[:iss]
18
- @to = payload[:sub]
19
- @audience = payload[:aud]
20
- @from_device = payload[:device_id]
21
- @expires = ::Time.parse(payload[:exp])
22
- @issued = ::Time.parse(payload[:iat])
23
- @status = payload[:status]
24
- if envelope
25
- issuer = envelope.sender.split(":")
26
- @from_device = issuer.last
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,55 +0,0 @@
1
- # Copyright 2020 Self Group Ltd. All Rights Reserved.
2
-
3
- # frozen_string_literal: true
4
-
5
- require 'self_msgproto'
6
- require_relative 'base'
7
- require_relative '../ntptime'
8
- require_relative 'authentication_message'
9
-
10
- module SelfSDK
11
- module Messages
12
- class AuthenticationReq < AuthenticationMessage
13
- MSG_TYPE = "identities.authenticate.req"
14
- DEFAULT_EXP_TIMEOUT = 300
15
-
16
- def initialize(messaging)
17
- @typ = MSG_TYPE
18
- super
19
- end
20
-
21
- def populate(selfid, opts)
22
- @id = SecureRandom.uuid
23
- @from = @client.jwt.id
24
- @to = selfid
25
-
26
- @id = opts[:cid] if opts.include?(:cid)
27
- @description = opts.include?(:description) ? opts[:description] : nil
28
- @exp_timeout = opts.fetch(:exp_timeout, DEFAULT_EXP_TIMEOUT)
29
- end
30
-
31
- def body
32
- { typ: MSG_TYPE,
33
- iss: @jwt.id,
34
- sub: @to,
35
- aud: @to,
36
- iat: SelfSDK::Time.now.strftime('%FT%TZ'),
37
- exp: (SelfSDK::Time.now + @exp_timeout).strftime('%FT%TZ'),
38
- cid: @id,
39
- jti: SecureRandom.uuid }
40
- end
41
-
42
- protected
43
-
44
- def proto(to_device)
45
- m = SelfMsg::Message.new
46
- m.id = @id
47
- m.sender = "#{@jwt.id}:#{@messaging.device_id}"
48
- m.recipient = "#{@to}:#{to_device}"
49
- m.ciphertext = encrypt_message(@jwt.prepare(body), [{ id: @to, device_id: to_device }])
50
- m
51
- end
52
-
53
- end
54
- end
55
- end
@@ -1,25 +0,0 @@
1
- # Copyright 2020 Self Group Ltd. All Rights Reserved.
2
-
3
- # frozen_string_literal: true
4
-
5
- require_relative 'base'
6
- require_relative '../ntptime'
7
- require_relative 'authentication_message'
8
-
9
- module SelfSDK
10
- module Messages
11
- class AuthenticationResp < AuthenticationMessage
12
- MSG_TYPE = "identities.authenticate.resp"
13
- def initialize(messaging)
14
- @typ = MSG_TYPE
15
- super
16
- end
17
-
18
- protected
19
-
20
- def proto(to_device)
21
- nil
22
- end
23
- end
24
- end
25
- end