selfsdk 0.0.124
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 +7 -0
- data/lib/acl.rb +52 -0
- data/lib/authenticated.rb +26 -0
- data/lib/client.rb +95 -0
- data/lib/jwt_service.rb +91 -0
- data/lib/log.rb +15 -0
- data/lib/messages/attestation.rb +53 -0
- data/lib/messages/authentication_message.rb +25 -0
- data/lib/messages/authentication_req.rb +52 -0
- data/lib/messages/authentication_resp.rb +23 -0
- data/lib/messages/base.rb +89 -0
- data/lib/messages/fact.rb +55 -0
- data/lib/messages/fact_request.rb +112 -0
- data/lib/messages/fact_response.rb +91 -0
- data/lib/messages/message.rb +39 -0
- data/lib/messaging.rb +441 -0
- data/lib/ntptime.rb +51 -0
- data/lib/proto/acl_pb.rb +19 -0
- data/lib/proto/aclcommand_pb.rb +16 -0
- data/lib/proto/auth_pb.rb +19 -0
- data/lib/proto/errtype_pb.rb +19 -0
- data/lib/proto/header_pb.rb +16 -0
- data/lib/proto/message_pb.rb +22 -0
- data/lib/proto/msgtype_pb.rb +18 -0
- data/lib/proto/notification_pb.rb +19 -0
- data/lib/selfsdk.rb +109 -0
- data/lib/services/auth.rb +163 -0
- data/lib/services/facts.rb +138 -0
- data/lib/services/identity.rb +44 -0
- data/lib/services/messaging.rb +100 -0
- data/lib/sources.rb +78 -0
- metadata +354 -0
data/lib/ntptime.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'time'
|
4
|
+
require 'net/ntp'
|
5
|
+
|
6
|
+
module SelfSDK
|
7
|
+
class Time
|
8
|
+
@@last_check = nil
|
9
|
+
@diff = nil
|
10
|
+
def self.now
|
11
|
+
timeout = 1
|
12
|
+
ntp_time = nil
|
13
|
+
5.times do
|
14
|
+
begin
|
15
|
+
ntp_time = get_ntp_current_time
|
16
|
+
break
|
17
|
+
rescue Timeout::Error
|
18
|
+
puts "time.google.com timed out, retrying in #{timeout} seconds..."
|
19
|
+
sleep timeout
|
20
|
+
timeout = timeout+1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
raise Timeout::Error.new("ntp sync timed out") if ntp_time.nil?
|
24
|
+
ntp_time
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def self.get_ntp_current_time
|
30
|
+
seconds_to_expire = 60
|
31
|
+
|
32
|
+
return ::Time.now.utc if ENV["RAKE_ENV"] == "test"
|
33
|
+
|
34
|
+
if @diff.nil?
|
35
|
+
self.sync
|
36
|
+
return @now
|
37
|
+
end
|
38
|
+
@now = (::Time.now + @diff).utc
|
39
|
+
if @@last_check + seconds_to_expire < @now
|
40
|
+
self.sync
|
41
|
+
end
|
42
|
+
@now
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.sync
|
46
|
+
@@last_check = ::Time.parse(Net::NTP.get("time.google.com", "ntp", 2).time.to_s).utc
|
47
|
+
@diff = (@@last_check - ::Time.now.utc).abs
|
48
|
+
@now = (::Time.now + @diff).utc
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/proto/acl_pb.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: acl.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
require_relative 'msgtype_pb'
|
7
|
+
require_relative 'aclcommand_pb'
|
8
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
9
|
+
add_message "msgproto.AccessControlList" do
|
10
|
+
optional :type, :enum, 1, "msgproto.MsgType"
|
11
|
+
optional :id, :string, 2
|
12
|
+
optional :command, :enum, 3, "msgproto.ACLCommand"
|
13
|
+
optional :payload, :bytes, 4
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Msgproto
|
18
|
+
AccessControlList = Google::Protobuf::DescriptorPool.generated_pool.lookup("msgproto.AccessControlList").msgclass
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: aclcommand.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
7
|
+
add_enum "msgproto.ACLCommand" do
|
8
|
+
value :LIST, 0
|
9
|
+
value :PERMIT, 1
|
10
|
+
value :REVOKE, 2
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Msgproto
|
15
|
+
ACLCommand = Google::Protobuf::DescriptorPool.generated_pool.lookup("msgproto.ACLCommand").enummodule
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: auth.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
require_relative 'msgtype_pb'
|
7
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
8
|
+
add_message "msgproto.Auth" do
|
9
|
+
optional :type, :enum, 1, "msgproto.MsgType"
|
10
|
+
optional :id, :string, 2
|
11
|
+
optional :token, :string, 3
|
12
|
+
optional :device, :string, 4
|
13
|
+
optional :offset, :int64, 5
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Msgproto
|
18
|
+
Auth = Google::Protobuf::DescriptorPool.generated_pool.lookup("msgproto.Auth").msgclass
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: errtype.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
7
|
+
add_enum "msgproto.ErrType" do
|
8
|
+
value :ErrConnection, 0
|
9
|
+
value :ErrBadRequest, 1
|
10
|
+
value :ErrInternal, 2
|
11
|
+
value :ErrMessage, 3
|
12
|
+
value :ErrAuth, 4
|
13
|
+
value :ErrACL, 5
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Msgproto
|
18
|
+
ErrType = Google::Protobuf::DescriptorPool.generated_pool.lookup("msgproto.ErrType").enummodule
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: header.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
require_relative 'msgtype_pb'
|
7
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
8
|
+
add_message "msgproto.Header" do
|
9
|
+
optional :type, :enum, 1, "msgproto.MsgType"
|
10
|
+
optional :id, :string, 2
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Msgproto
|
15
|
+
Header = Google::Protobuf::DescriptorPool.generated_pool.lookup("msgproto.Header").msgclass
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: message.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
require_relative 'msgtype_pb'
|
7
|
+
require 'google/protobuf/timestamp_pb'
|
8
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
9
|
+
add_message "msgproto.Message" do
|
10
|
+
optional :type, :enum, 1, "msgproto.MsgType"
|
11
|
+
optional :id, :string, 2
|
12
|
+
optional :sender, :string, 3
|
13
|
+
optional :recipient, :string, 4
|
14
|
+
optional :ciphertext, :bytes, 5
|
15
|
+
optional :timestamp, :message, 6, "google.protobuf.Timestamp"
|
16
|
+
optional :offset, :int64, 7
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Msgproto
|
21
|
+
Message = Google::Protobuf::DescriptorPool.generated_pool.lookup("msgproto.Message").msgclass
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: msgtype.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
7
|
+
add_enum "msgproto.MsgType" do
|
8
|
+
value :MSG, 0
|
9
|
+
value :ACK, 1
|
10
|
+
value :ERR, 2
|
11
|
+
value :AUTH, 3
|
12
|
+
value :ACL, 4
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module Msgproto
|
17
|
+
MsgType = Google::Protobuf::DescriptorPool.generated_pool.lookup("msgproto.MsgType").enummodule
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: notification.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
require_relative 'msgtype_pb'
|
7
|
+
require_relative 'errtype_pb'
|
8
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
9
|
+
add_message "msgproto.Notification" do
|
10
|
+
optional :type, :enum, 1, "msgproto.MsgType"
|
11
|
+
optional :id, :string, 2
|
12
|
+
optional :error, :string, 3
|
13
|
+
optional :errtype, :enum, 4, "msgproto.ErrType"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Msgproto
|
18
|
+
Notification = Google::Protobuf::DescriptorPool.generated_pool.lookup("msgproto.Notification").msgclass
|
19
|
+
end
|
data/lib/selfsdk.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require "ed25519"
|
5
|
+
require 'json'
|
6
|
+
require 'net/http'
|
7
|
+
require 'rqrcode'
|
8
|
+
require_relative 'log'
|
9
|
+
require_relative 'jwt_service'
|
10
|
+
require_relative 'client'
|
11
|
+
require_relative 'messaging'
|
12
|
+
require_relative 'ntptime'
|
13
|
+
require_relative 'authenticated'
|
14
|
+
require_relative 'acl'
|
15
|
+
require_relative 'sources'
|
16
|
+
require_relative 'services/auth'
|
17
|
+
require_relative 'services/facts'
|
18
|
+
require_relative 'services/identity'
|
19
|
+
require_relative 'services/messaging'
|
20
|
+
|
21
|
+
# Namespace for classes and modules that handle Self interactions.
|
22
|
+
module SelfSDK
|
23
|
+
# Abstract base class for CLI utilities. Provides some helper methods for
|
24
|
+
# the option parser
|
25
|
+
#
|
26
|
+
# @attr_reader [Types] app_id the identifier of the current app.
|
27
|
+
# @attr_reader [Types] app_key the api key for the current app.
|
28
|
+
class App
|
29
|
+
BASE_URL = "https://api.selfid.net".freeze
|
30
|
+
MESSAGING_URL = "wss://messaging.selfid.net/v1/messaging".freeze
|
31
|
+
|
32
|
+
attr_reader :client
|
33
|
+
attr_accessor :messaging_client
|
34
|
+
|
35
|
+
# Initializes a SelfSDK App
|
36
|
+
#
|
37
|
+
# @param app_id [string] the app id.
|
38
|
+
# @param app_key [string] the app api key provided by developer portal.
|
39
|
+
# @param storage_key [string] the key to be used to encrypt persisted data.
|
40
|
+
# @param [Hash] opts the options to authenticate.
|
41
|
+
# @option opts [String] :base_url The self provider url.
|
42
|
+
# @option opts [String] :messaging_url The messaging self provider url.
|
43
|
+
# @option opts [Bool] :auto_reconnect Automatically reconnects to websocket if connection is lost (defaults to true).
|
44
|
+
# @option opts [Symbol] :env The environment to be used, defaults to ":production".
|
45
|
+
# @option opts [String] :storage_dir The folder where encryption sessions and settings will be stored
|
46
|
+
def initialize(app_id, app_key, storage_key, opts = {})
|
47
|
+
SelfSDK.logger.debug "syncing ntp times #{SelfSDK::Time.now}"
|
48
|
+
env = opts.fetch(:env, "")
|
49
|
+
|
50
|
+
@client = RestClient.new(base_url(opts), app_id, app_key, env)
|
51
|
+
messaging_url = messaging_url(opts)
|
52
|
+
unless messaging_url.nil?
|
53
|
+
@messaging_client = MessagingClient.new(messaging_url,
|
54
|
+
@client,
|
55
|
+
storage_dir: opts.fetch(:storage_dir, MessagingClient::DEFAULT_STORAGE_DIR),
|
56
|
+
auto_reconnect: opts.fetch(:auto_reconnect, MessagingClient::DEFAULT_AUTO_RECONNECT),
|
57
|
+
device_id: opts.fetch(:device_id, MessagingClient::DEFAULT_DEVICE))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Provides access to SelfSDK::Services::Facts service
|
62
|
+
def facts
|
63
|
+
@facts ||= SelfSDK::Services::Facts.new(@messaging_client, @client)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Provides access to SelfSDK::Services::Authentication service
|
67
|
+
def authentication
|
68
|
+
@authentication ||= SelfSDK::Services::Authentication.new(@messaging_client, @client)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Provides access to SelfSDK::Services::Identity service
|
72
|
+
def identity
|
73
|
+
@identity ||= SelfSDK::Services::Identity.new(@client)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Provides access to SelfSDK::Services::Messaging service
|
77
|
+
def messaging
|
78
|
+
@messaging ||= SelfSDK::Services::Messaging.new(@messaging_client)
|
79
|
+
end
|
80
|
+
|
81
|
+
def app_id
|
82
|
+
client.jwt.id
|
83
|
+
end
|
84
|
+
|
85
|
+
def app_key
|
86
|
+
client.jwt.key
|
87
|
+
end
|
88
|
+
|
89
|
+
# Closes the websocket connection
|
90
|
+
def close
|
91
|
+
@messaging_client.close
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
|
96
|
+
def base_url(opts)
|
97
|
+
return opts[:base_url] if opts.key? :base_url
|
98
|
+
return "https://api.#{opts[:env].to_s}.selfid.net" if opts.key? :env
|
99
|
+
BASE_URL
|
100
|
+
end
|
101
|
+
|
102
|
+
def messaging_url(opts)
|
103
|
+
return opts[:messaging_url] if opts.key? :messaging_url
|
104
|
+
return "wss://messaging.#{opts[:env].to_s}.selfid.net/v1/messaging" if opts.key? :env
|
105
|
+
MESSAGING_URL
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Namespace for classes and modules that handle SelfSDK gem
|
4
|
+
module SelfSDK
|
5
|
+
# Namespace for classes and modules that handle selfsdk-gem public ui
|
6
|
+
module Services
|
7
|
+
# Input class to handle authentication requests on self network.
|
8
|
+
class Authentication
|
9
|
+
# Creates a new authentication service.
|
10
|
+
# Authentication service mainly manages authentication requests against self
|
11
|
+
# users wanting to authenticate on your app.
|
12
|
+
#
|
13
|
+
# @param messaging [SelfSDK::Messaging] messaging object.
|
14
|
+
# @param client [SelfSDK::Client] http client object.
|
15
|
+
#
|
16
|
+
# @return [SelfSDK::Services::Authentication] authentication service.
|
17
|
+
def initialize(messaging, client)
|
18
|
+
@messaging = messaging
|
19
|
+
@client = client
|
20
|
+
end
|
21
|
+
|
22
|
+
# Sends an authentication request to the specified selfid.
|
23
|
+
# An authentication requests allows your users to authenticate on your app using
|
24
|
+
# a secure self app.
|
25
|
+
#
|
26
|
+
# @overload request(selfid, opts = {}, &block)
|
27
|
+
# @param [String] selfid the receiver of the authentication request.
|
28
|
+
# @param [Hash] opts the options to authenticate.
|
29
|
+
# @option opts [String] :cid The unique identifier of the authentication request.
|
30
|
+
# @yield [request] Invokes the block with an authentication response for each result.
|
31
|
+
# @return [String, String] conversation id or encoded body.
|
32
|
+
#
|
33
|
+
# @overload request(selfid, opts = {})
|
34
|
+
# @param [String] selfid the receiver of the authentication request.
|
35
|
+
# @param [Hash] opts the options to authenticate.
|
36
|
+
# @option [Boolean] :async if the request is asynchronous.
|
37
|
+
# @option opts [String] :cid The unique identifier of the authentication request.
|
38
|
+
# @return [String, String] conversation id or encoded body.
|
39
|
+
def request(selfid, opts = {}, &block)
|
40
|
+
SelfSDK.logger.info "authenticating #{selfid}"
|
41
|
+
|
42
|
+
req = SelfSDK::Messages::AuthenticationReq.new(@messaging)
|
43
|
+
req.populate(selfid, opts)
|
44
|
+
|
45
|
+
body = @client.jwt.prepare(req.body)
|
46
|
+
return body unless opts.fetch(:request, true)
|
47
|
+
return req.send_message if opts.fetch(:async, false)
|
48
|
+
|
49
|
+
# when a block is given the request will always be asynchronous.
|
50
|
+
if block_given?
|
51
|
+
@messaging.set_observer(req, timeout: req.exp_timeout, &block)
|
52
|
+
return req.send_message
|
53
|
+
end
|
54
|
+
|
55
|
+
# Otherwise the request is synchronous
|
56
|
+
req.request
|
57
|
+
end
|
58
|
+
|
59
|
+
# Generates a QR code so users can authenticate to your app.
|
60
|
+
#
|
61
|
+
# @option opts [String] :selfid the user selfid you want to authenticate.
|
62
|
+
# @option opts [String] :cid The unique identifier of the authentication request.
|
63
|
+
#
|
64
|
+
# @return [String, String] conversation id or encoded body.
|
65
|
+
def generate_qr(opts = {})
|
66
|
+
opts[:request] = false
|
67
|
+
selfid = opts.fetch(:selfid, "-")
|
68
|
+
req = request(selfid, opts)
|
69
|
+
::RQRCode::QRCode.new(req, level: 'l')
|
70
|
+
end
|
71
|
+
|
72
|
+
# Generates a deep link to authenticate with self app.
|
73
|
+
#
|
74
|
+
# @param callback [String] the url you'll be redirected if the app is not installed.
|
75
|
+
# @option opts [String] :selfid the user selfid you want to authenticate.
|
76
|
+
# @option opts [String] :cid The unique identifier of the authentication request.
|
77
|
+
#
|
78
|
+
# @return [String, String] conversation id or encoded body.
|
79
|
+
def generate_deep_link(callback, opts = {})
|
80
|
+
opts[:request] = false
|
81
|
+
selfid = opts.fetch(:selfid, "-")
|
82
|
+
body = @client.jwt.encode(request(selfid, opts))
|
83
|
+
|
84
|
+
if @client.env.empty?
|
85
|
+
return "https://selfid.page.link/?link=#{callback}%3Fqr=#{body}&apn=net.selfid.app"
|
86
|
+
elsif @client.env == 'development'
|
87
|
+
return "https://selfid.page.link/?link=#{callback}%3Fqr=#{body}&apn=net.selfid.app.dev"
|
88
|
+
end
|
89
|
+
"https://selfid.page.link/?link=#{callback}%3Fqr=#{body}&apn=net.selfid.app.#{@client.env}"
|
90
|
+
end
|
91
|
+
|
92
|
+
# Adds an observer for an authentication response
|
93
|
+
def subscribe(&block)
|
94
|
+
@messaging.subscribe :authentication_response do |res|
|
95
|
+
valid_payload(res.input)
|
96
|
+
yield(res)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
# Checks if the given input is an accepted authentication request.
|
103
|
+
#
|
104
|
+
# @param response [string] the response to an authentication request from self-api.
|
105
|
+
# @return [Hash] Details response.
|
106
|
+
# * :accepted [Boolean] a bool describing if authentication is accepted or not.
|
107
|
+
# * :uuid [String] the request identifier.
|
108
|
+
def authenticated?(response)
|
109
|
+
Authenticated.new(valid_payload(response))
|
110
|
+
end
|
111
|
+
|
112
|
+
# checks if a payload is valid or not.
|
113
|
+
#
|
114
|
+
# @param response [string] the response to an authentication request from self-api.
|
115
|
+
def valid_payload(response)
|
116
|
+
parse_payload(response)
|
117
|
+
rescue StandardError => e
|
118
|
+
uuid = ""
|
119
|
+
uuid = response[:cid] unless response.nil?
|
120
|
+
SelfSDK.logger.error "error checking authentication for #{uuid} : #{e.message}"
|
121
|
+
p e.backtrace
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
|
125
|
+
# Prepares an authentication payload to be sent to a user.
|
126
|
+
#
|
127
|
+
# @param selfid [string] the selfid of the user you want to send the auth request to.
|
128
|
+
# @param cid [string] the conversation id to be used.
|
129
|
+
def prepare_payload(selfid, cid)
|
130
|
+
# TODO should this be moved to its own message/auth_req.rb?
|
131
|
+
body = {
|
132
|
+
typ: 'identities.authenticate.req',
|
133
|
+
aud: @client.self_url,
|
134
|
+
iss: @client.jwt.id,
|
135
|
+
sub: selfid,
|
136
|
+
iat: SelfSDK::Time.now.strftime('%FT%TZ'),
|
137
|
+
exp: (SelfSDK::Time.now + 3600).strftime('%FT%TZ'),
|
138
|
+
cid: cid,
|
139
|
+
jti: SecureRandom.uuid,
|
140
|
+
device_id: @messaging.device_id,
|
141
|
+
}
|
142
|
+
|
143
|
+
@client.jwt.prepare(body)
|
144
|
+
end
|
145
|
+
|
146
|
+
def parse_payload(response)
|
147
|
+
jws = @client.jwt.parse(response)
|
148
|
+
return unless jws.include? :payload
|
149
|
+
|
150
|
+
payload = JSON.parse(@client.jwt.decode(jws[:payload]), symbolize_names: true)
|
151
|
+
return if payload.nil?
|
152
|
+
|
153
|
+
identity = @client.entity(payload[:sub])
|
154
|
+
return if identity.nil?
|
155
|
+
|
156
|
+
identity[:public_keys].each do |key|
|
157
|
+
return payload if @client.jwt.verify(jws, key[:key])
|
158
|
+
end
|
159
|
+
nil
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|