selfsdk 0.0.196 → 0.0.197

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 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