selfsdk 0.0.132 → 0.0.137
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 +4 -4
- data/lib/client.rb +16 -14
- data/lib/crypto.rb +102 -0
- data/lib/messages/authentication_req.rb +1 -1
- data/lib/messages/base.rb +4 -0
- data/lib/messages/fact_request.rb +8 -7
- data/lib/messages/message.rb +2 -1
- data/lib/messaging.rb +11 -4
- data/lib/selfsdk.rb +3 -2
- data/lib/services/auth.rb +6 -4
- data/lib/services/facts.rb +6 -4
- data/lib/services/messaging.rb +9 -0
- metadata +16 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4b5f44ffce4a1ad4c61c20b752e97173f2cc0c96091138683ddb56c2dca2f73
|
4
|
+
data.tar.gz: 841ad78f32bcb7434126eac7bdea3e3eb9d7abf4cc35fd41d0d243fa7f05fffa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 04f00c82b5f64dc8f23597e28fc11eee64db02deacfbeedb328d3f766048e40d3a625c3ae25b7a5a888969272883650e63ce9425d5056f2ed98f5beae1712987
|
7
|
+
data.tar.gz: 2dfa4e9f4e3796393adfda66d994ef39fa2de8f37b08b2274b4fcdaa1ccd752e7aafdec5f7eb80b1b4f336ecaeb74350a42464c785c5026eb82e8ffd3458761f
|
data/lib/client.rb
CHANGED
@@ -65,6 +65,22 @@ module SelfSDK
|
|
65
65
|
i[:public_keys]
|
66
66
|
end
|
67
67
|
|
68
|
+
def post(endpoint, body)
|
69
|
+
p HTTParty.post("#{@self_url}#{endpoint}",
|
70
|
+
headers: {
|
71
|
+
'Content-Type' => 'application/json',
|
72
|
+
'Authorization' => "Bearer #{@jwt.auth_token}"
|
73
|
+
},
|
74
|
+
body: body)
|
75
|
+
end
|
76
|
+
|
77
|
+
def get(endpoint)
|
78
|
+
HTTParty.get("#{@self_url}#{endpoint}", headers: {
|
79
|
+
'Content-Type' => 'application/json',
|
80
|
+
'Authorization' => "Bearer #{@jwt.auth_token}"
|
81
|
+
})
|
82
|
+
end
|
83
|
+
|
68
84
|
# Lists all public keys stored on self for the given ID
|
69
85
|
#
|
70
86
|
# @param id [string] identity id
|
@@ -86,20 +102,6 @@ module SelfSDK
|
|
86
102
|
body
|
87
103
|
end
|
88
104
|
|
89
|
-
def get(endpoint)
|
90
|
-
HTTParty.get("#{@self_url}#{endpoint}", headers: {
|
91
|
-
'Content-Type' => 'application/json',
|
92
|
-
'Authorization' => "Bearer #{@jwt.auth_token}"
|
93
|
-
})
|
94
|
-
end
|
95
105
|
|
96
|
-
def post(endpoint, body)
|
97
|
-
HTTParty.post("#{@self_url}#{endpoint}",
|
98
|
-
headers: {
|
99
|
-
'Content-Type' => 'application/json',
|
100
|
-
'Authorization' => "Bearer #{@jwt.auth_token}"
|
101
|
-
},
|
102
|
-
body: body)
|
103
|
-
end
|
104
106
|
end
|
105
107
|
end
|
data/lib/crypto.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'self_crypto'
|
2
|
+
|
3
|
+
module SelfSDK
|
4
|
+
class Crypto
|
5
|
+
def initialize(client, device, storage_folder, storage_key)
|
6
|
+
@client = client
|
7
|
+
@device = device
|
8
|
+
@storage_key = storage_key
|
9
|
+
@storage_folder = storage_folder
|
10
|
+
|
11
|
+
if File.exist?('account.pickle')
|
12
|
+
# 1a) if alice's account file exists load the pickle from the file
|
13
|
+
@account = SelfCrypto::Account.from_pickle(File.read('account.pickle'), @storage_key)
|
14
|
+
else
|
15
|
+
# 1b-i) if create a new account for alice if one doesn't exist already
|
16
|
+
@account = SelfCrypto::Account.from_seed(@client.jwt.key)
|
17
|
+
|
18
|
+
# 1b-ii) generate some keys for alice and publish them
|
19
|
+
@account.gen_otk(100)
|
20
|
+
|
21
|
+
# 1b-iii) convert those keys to json
|
22
|
+
keys = @account.otk['curve25519'].map{|k,v| {id: k, key: v}}.to_json
|
23
|
+
|
24
|
+
# 1b-iv) post those keys to POST /v1/identities/<selfid>/devices/1/pre_keys/
|
25
|
+
@client.post("/v1/apps/#{@client.jwt.id}/devices/#{@device}/pre_keys", keys)
|
26
|
+
|
27
|
+
# 1b-v) store the account to a file
|
28
|
+
File.write('account.pickle', @account.to_pickle(storage_key))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def encrypt(message, recipient, recipient_device)
|
33
|
+
session_file_name = "#{recipient}:#{recipient_device}-session.pickle"
|
34
|
+
|
35
|
+
if File.exist?(session_file_name)
|
36
|
+
# 2a) if bob's session file exists load the pickle from the file
|
37
|
+
session_with_bob = SelfCrypto::Session.from_pickle(File.read(session_file_name), @storage_key)
|
38
|
+
else
|
39
|
+
# 2b-i) if you have not previously sent or recevied a message to/from bob,
|
40
|
+
# you must get his identity key from GET /v1/identities/bob/
|
41
|
+
ed25519_identity_key = @client.public_keys(recipient).first[:key]
|
42
|
+
|
43
|
+
# 2b-ii) get a one time key for bob
|
44
|
+
res = @client.get("/v1/identities/#{recipient}/devices/#{recipient_device}/pre_keys")
|
45
|
+
|
46
|
+
if res.code != 200
|
47
|
+
Selfid.logger.error "identity response : #{res.body[:message]}"
|
48
|
+
raise "could not get identity pre_keys"
|
49
|
+
end
|
50
|
+
|
51
|
+
one_time_key = JSON.parse(res.body)["key"]
|
52
|
+
|
53
|
+
# 2b-iii) convert bobs ed25519 identity key to a curve25519 key
|
54
|
+
curve25519_identity_key = SelfCrypto::Util.ed25519_pk_to_curve25519(ed25519_identity_key)
|
55
|
+
|
56
|
+
# 2b-iv) create the session with bob
|
57
|
+
session_with_bob = @account.outbound_session(curve25519_identity_key, one_time_key)
|
58
|
+
|
59
|
+
# 2b-v) store the session to a file
|
60
|
+
File.write(session_file_name, session_with_bob.to_pickle(@storage_key))
|
61
|
+
end
|
62
|
+
|
63
|
+
# 3) create a group session and set the identity of the account youre using
|
64
|
+
gs = SelfCrypto::GroupSession.new("#{@client.jwt.id}:#{@device}")
|
65
|
+
|
66
|
+
# 4) add all recipients and their sessions
|
67
|
+
gs.add_participant("#{recipient}:#{recipient_device}", session_with_bob)
|
68
|
+
|
69
|
+
# 5) encrypt a message
|
70
|
+
gs.encrypt(message).to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
def decrypt(message, sender, sender_device)
|
74
|
+
session_file_name = "#{sender}:#{sender_device}-session.pickle"
|
75
|
+
|
76
|
+
if File.exist?(session_file_name)
|
77
|
+
# 7a) if carol's session file exists load the pickle from the file
|
78
|
+
session_with_bob = SelfCrypto::Session.from_pickle(File.read(session_file_name), @storage_key)
|
79
|
+
else
|
80
|
+
# 7b-i) if you have not previously sent or received a message to/from bob,
|
81
|
+
# you should extract the initial message from the group message intended
|
82
|
+
# for your account id.
|
83
|
+
m = SelfCrypto::GroupMessage.new(message.to_s).get_message("#{@client.jwt.id}:#{@device}")
|
84
|
+
|
85
|
+
# 7b-ii) use the initial message to create a session for bob or carol
|
86
|
+
session_with_bob = @account.inbound_session(m)
|
87
|
+
|
88
|
+
# 7b-iii) store the session to a file
|
89
|
+
File.write(session_file_name, session_with_bob.to_pickle(@storage_key))
|
90
|
+
end
|
91
|
+
|
92
|
+
# 8) create a group session and set the identity of the account you're using
|
93
|
+
gs = SelfCrypto::GroupSession.new("#{@client.jwt.id}:#{@device}")
|
94
|
+
|
95
|
+
# 9) add all recipients and their sessions
|
96
|
+
gs.add_participant("#{sender}:#{sender_device}", session_with_bob)
|
97
|
+
|
98
|
+
# 10) decrypt the message ciphertext
|
99
|
+
gs.decrypt("#{sender}:#{sender_device}", message).to_s
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/messages/base.rb
CHANGED
@@ -93,19 +93,20 @@ module SelfSDK
|
|
93
93
|
end
|
94
94
|
@to_device = devices.first
|
95
95
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
96
|
+
if @intermediary.nil?
|
97
|
+
recipient = "#{@to}:#{@to_device}"
|
98
|
+
ciphertext = encrypt_message(@jwt.prepare(body), @to, @to_device)
|
99
|
+
else
|
100
|
+
recipient = "#{@intermediary}:#{@to_device}"
|
101
|
+
ciphertext = encrypt_message(@jwt.prepare(body), @intermediary, @to_device)
|
102
|
+
end
|
101
103
|
|
102
104
|
Msgproto::Message.new(
|
103
105
|
type: Msgproto::MsgType::MSG,
|
104
106
|
id: @id,
|
105
107
|
sender: "#{@jwt.id}:#{@messaging.device_id}",
|
106
108
|
recipient: recipient,
|
107
|
-
ciphertext:
|
108
|
-
)
|
109
|
+
ciphertext: ciphertext )
|
109
110
|
end
|
110
111
|
end
|
111
112
|
end
|
data/lib/messages/message.rb
CHANGED
@@ -11,7 +11,8 @@ module SelfSDK
|
|
11
11
|
body = if input.is_a? String
|
12
12
|
input
|
13
13
|
else
|
14
|
-
input.
|
14
|
+
issuer = input.recipient.split(":")
|
15
|
+
messaging.encryption_client.decrypt(input.ciphertext, issuer.first, issuer.last)
|
15
16
|
end
|
16
17
|
|
17
18
|
jwt = JSON.parse(body, symbolize_names: true)
|
data/lib/messaging.rb
CHANGED
@@ -4,6 +4,7 @@ require 'json'
|
|
4
4
|
require 'monitor'
|
5
5
|
require 'faye/websocket'
|
6
6
|
require 'fileutils'
|
7
|
+
require_relative 'crypto'
|
7
8
|
require_relative 'messages/message'
|
8
9
|
require_relative 'proto/auth_pb'
|
9
10
|
require_relative 'proto/message_pb'
|
@@ -18,16 +19,18 @@ module SelfSDK
|
|
18
19
|
DEFAULT_STORAGE_DIR="./.self_storage"
|
19
20
|
ON_DEMAND_CLOSE_CODE=3999
|
20
21
|
|
21
|
-
attr_accessor :client, :jwt, :device_id, :ack_timeout, :timeout, :type_observer, :uuid_observer
|
22
|
+
attr_accessor :client, :jwt, :device_id, :ack_timeout, :timeout, :type_observer, :uuid_observer, :encryption_client
|
22
23
|
|
23
24
|
# RestClient initializer
|
24
25
|
#
|
25
26
|
# @param url [string] self-messaging url
|
26
27
|
# @params client [Object] SelfSDK::Client object
|
27
28
|
# @option opts [string] :storage_dir the folder where encryption sessions and settings will be stored
|
29
|
+
# @params storage_key [String] seed to encrypt messaging
|
30
|
+
# @params storage_folder [String] folder to perist messaging encryption
|
28
31
|
# @option opts [Bool] :auto_reconnect Automatically reconnects to websocket if connection is lost (defaults to true).
|
29
32
|
# @option opts [String] :device_id The device id to be used by the app defaults to "1".
|
30
|
-
def initialize(url, client, options = {})
|
33
|
+
def initialize(url, client, storage_key, storage_folder, options = {})
|
31
34
|
@mon = Monitor.new
|
32
35
|
@url = url
|
33
36
|
@messages = {}
|
@@ -45,6 +48,9 @@ module SelfSDK
|
|
45
48
|
@offset = read_offset
|
46
49
|
|
47
50
|
FileUtils.mkdir_p @storage_dir unless File.exist? @storage_dir
|
51
|
+
unless options.include? :no_crypto
|
52
|
+
@encryption_client = Crypto.new(@client, @device_id, storage_folder, storage_key)
|
53
|
+
end
|
48
54
|
|
49
55
|
if options.include? :ws
|
50
56
|
@ws = options[:ws]
|
@@ -367,6 +373,8 @@ module SelfSDK
|
|
367
373
|
|
368
374
|
def process_incomming_message(input)
|
369
375
|
message = SelfSDK::Messages.parse(input, self)
|
376
|
+
@offset = input.offset
|
377
|
+
write_offset(@offset)
|
370
378
|
|
371
379
|
if @messages.include? message.id
|
372
380
|
message.validate! @messages[message.id][:original_message]
|
@@ -378,8 +386,6 @@ module SelfSDK
|
|
378
386
|
notify_observer(message)
|
379
387
|
end
|
380
388
|
|
381
|
-
@offset = input.offset
|
382
|
-
write_offset(@offset)
|
383
389
|
rescue StandardError => e
|
384
390
|
p "Error processing incoming message #{input.to_json}"
|
385
391
|
SelfSDK.logger.info e
|
@@ -434,6 +440,7 @@ module SelfSDK
|
|
434
440
|
|
435
441
|
def write_offset(offset)
|
436
442
|
File.open(@offset_file, 'wb') do |f|
|
443
|
+
f.flock(File::LOCK_EX)
|
437
444
|
f.write([offset].pack('q'))
|
438
445
|
end
|
439
446
|
end
|
data/lib/selfsdk.rb
CHANGED
@@ -53,6 +53,7 @@ module SelfSDK
|
|
53
53
|
unless messaging_url.nil?
|
54
54
|
@messaging_client = MessagingClient.new(messaging_url,
|
55
55
|
@client,
|
56
|
+
storage_key,
|
56
57
|
storage_dir: opts.fetch(:storage_dir, MessagingClient::DEFAULT_STORAGE_DIR),
|
57
58
|
auto_reconnect: opts.fetch(:auto_reconnect, MessagingClient::DEFAULT_AUTO_RECONNECT),
|
58
59
|
device_id: opts.fetch(:device_id, MessagingClient::DEFAULT_DEVICE))
|
@@ -61,12 +62,12 @@ module SelfSDK
|
|
61
62
|
|
62
63
|
# Provides access to SelfSDK::Services::Facts service
|
63
64
|
def facts
|
64
|
-
@facts ||= SelfSDK::Services::Facts.new(
|
65
|
+
@facts ||= SelfSDK::Services::Facts.new(messaging, @client)
|
65
66
|
end
|
66
67
|
|
67
68
|
# Provides access to SelfSDK::Services::Authentication service
|
68
69
|
def authentication
|
69
|
-
@authentication ||= SelfSDK::Services::Authentication.new(
|
70
|
+
@authentication ||= SelfSDK::Services::Authentication.new(messaging, @client)
|
70
71
|
end
|
71
72
|
|
72
73
|
# Provides access to SelfSDK::Services::Identity service
|
data/lib/services/auth.rb
CHANGED
@@ -15,7 +15,8 @@ module SelfSDK
|
|
15
15
|
#
|
16
16
|
# @return [SelfSDK::Services::Authentication] authentication service.
|
17
17
|
def initialize(messaging, client)
|
18
|
-
@messaging = messaging
|
18
|
+
@messaging = messaging.client
|
19
|
+
@messaging_service = messaging
|
19
20
|
@client = client
|
20
21
|
end
|
21
22
|
|
@@ -38,6 +39,7 @@ module SelfSDK
|
|
38
39
|
# @return [String, String] conversation id or encoded body.
|
39
40
|
def request(selfid, opts = {}, &block)
|
40
41
|
SelfSDK.logger.info "authenticating #{selfid}"
|
42
|
+
raise "You're not permitting connections from #{selfid}" unless @messaging_service.is_permitted?(selfid)
|
41
43
|
|
42
44
|
req = SelfSDK::Messages::AuthenticationReq.new(@messaging)
|
43
45
|
req.populate(selfid, opts)
|
@@ -82,11 +84,11 @@ module SelfSDK
|
|
82
84
|
body = @client.jwt.encode(request(selfid, opts))
|
83
85
|
|
84
86
|
if @client.env.empty?
|
85
|
-
return "https://
|
87
|
+
return "https://joinself.page.link/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app"
|
86
88
|
elsif @client.env == 'development'
|
87
|
-
return "https://
|
89
|
+
return "https://joinself.page.link/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app.dev"
|
88
90
|
end
|
89
|
-
"https://
|
91
|
+
"https://joinself.page.link/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app.#{@client.env}"
|
90
92
|
end
|
91
93
|
|
92
94
|
# Adds an observer for an authentication response
|
data/lib/services/facts.rb
CHANGED
@@ -17,7 +17,8 @@ module SelfSDK
|
|
17
17
|
#
|
18
18
|
# @return [SelfSDK::Services::Facts] facts service.
|
19
19
|
def initialize(messaging, client)
|
20
|
-
@messaging = messaging
|
20
|
+
@messaging = messaging.client
|
21
|
+
@messaging_service = messaging
|
21
22
|
@client = client
|
22
23
|
end
|
23
24
|
|
@@ -40,6 +41,7 @@ module SelfSDK
|
|
40
41
|
# @return [Object] SelfSDK:::Messages::FactRequest
|
41
42
|
def request(selfid, facts, opts = {}, &block)
|
42
43
|
SelfSDK.logger.info "authenticating #{selfid}"
|
44
|
+
raise "You're not permitting connections from #{selfid}" unless @messaging_service.is_permitted?(selfid)
|
43
45
|
|
44
46
|
req = SelfSDK::Messages::FactRequest.new(@messaging)
|
45
47
|
req.populate(selfid, prepare_facts(facts), opts)
|
@@ -108,11 +110,11 @@ module SelfSDK
|
|
108
110
|
body = @client.jwt.encode(request(selfid, facts, opts))
|
109
111
|
|
110
112
|
if @client.env.empty?
|
111
|
-
return "https://
|
113
|
+
return "https://joinself.page.link/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app"
|
112
114
|
elsif @client.env == 'development'
|
113
|
-
return "https://
|
115
|
+
return "https://joinself.page.link/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app.dev"
|
114
116
|
end
|
115
|
-
"https://
|
117
|
+
"https://joinself.page.link/?link=#{callback}%3Fqr=#{body}&apn=com.joinself.app.#{@client.env}"
|
116
118
|
end
|
117
119
|
|
118
120
|
private
|
data/lib/services/messaging.rb
CHANGED
@@ -44,6 +44,15 @@ module SelfSDK
|
|
44
44
|
acl.list
|
45
45
|
end
|
46
46
|
|
47
|
+
# Checks if you're permitting messages from a specific self identifier
|
48
|
+
# @return [Boolean] yes|no
|
49
|
+
def is_permitted?(id)
|
50
|
+
conns = allowed_connections
|
51
|
+
return true if conns.include? "*"
|
52
|
+
return true if conns.include? id
|
53
|
+
return false
|
54
|
+
end
|
55
|
+
|
47
56
|
# Revokes incoming messages from the given identity.
|
48
57
|
#
|
49
58
|
# @param [String] selfid to be denied
|
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.
|
4
|
+
version: 0.0.137
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aldgate Ventures
|
@@ -10,6 +10,20 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2011-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: self_crypto
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: async
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -299,6 +313,7 @@ files:
|
|
299
313
|
- lib/acl.rb
|
300
314
|
- lib/authenticated.rb
|
301
315
|
- lib/client.rb
|
316
|
+
- lib/crypto.rb
|
302
317
|
- lib/jwt_service.rb
|
303
318
|
- lib/log.rb
|
304
319
|
- lib/messages/attestation.rb
|