duse 0.0.7 → 0.0.8
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 +8 -8
- data/.gitignore +3 -0
- data/.travis.yml +3 -0
- data/Gemfile +5 -2
- data/README.md +12 -3
- data/bin/duse +2 -1
- data/config/warble.rb +183 -0
- data/duse.gemspec +2 -0
- data/lib/duse.rb +1 -0
- data/lib/duse/cli.rb +1 -0
- data/lib/duse/cli/cli_config.rb +2 -0
- data/lib/duse/cli/folder.rb +18 -0
- data/lib/duse/cli/folder_add.rb +24 -0
- data/lib/duse/cli/folder_list.rb +17 -0
- data/lib/duse/cli/folder_remove.rb +19 -0
- data/lib/duse/cli/folder_update.rb +18 -0
- data/lib/duse/cli/register.rb +1 -1
- data/lib/duse/cli/secret.rb +2 -0
- data/lib/duse/cli/secret_add.rb +5 -0
- data/lib/duse/cli/secret_list.rb +1 -3
- data/lib/duse/cli/secret_tree.rb +15 -0
- data/lib/duse/cli/secret_update.rb +2 -1
- data/lib/duse/client/folder.rb +34 -0
- data/lib/duse/client/secret.rb +13 -2
- data/lib/duse/encryption.rb +32 -8
- data/lib/duse/version.rb +1 -1
- data/spec/cli/cli_config_spec.rb +1 -1
- data/spec/cli/commands/account_spec.rb +1 -1
- data/spec/cli/commands/config_spec.rb +1 -1
- data/spec/cli/commands/login_spec.rb +2 -2
- data/spec/cli/commands/register_spec.rb +1 -1
- data/spec/cli/commands/secret_spec.rb +23 -6
- data/spec/client/secret_spec.rb +20 -32
- data/spec/client/user_spec.rb +3 -4
- data/spec/encryption_spec.rb +10 -0
- data/spec/spec_helper.rb +7 -3
- data/spec/support/key_helper.rb +27 -0
- data/spec/support/mock_api.rb +93 -111
- metadata +26 -2
data/lib/duse/cli/secret.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'duse/cli/secret_add'
|
2
2
|
require 'duse/cli/secret_get'
|
3
3
|
require 'duse/cli/secret_list'
|
4
|
+
require 'duse/cli/secret_tree'
|
4
5
|
require 'duse/cli/secret_remove'
|
5
6
|
require 'duse/cli/secret_update'
|
6
7
|
|
@@ -10,6 +11,7 @@ module Duse
|
|
10
11
|
subcommand SecretAdd
|
11
12
|
subcommand SecretGet
|
12
13
|
subcommand SecretList
|
14
|
+
subcommand SecretTree
|
13
15
|
subcommand SecretRemove
|
14
16
|
subcommand SecretUpdate
|
15
17
|
|
data/lib/duse/cli/secret_add.rb
CHANGED
@@ -16,6 +16,7 @@ module Duse
|
|
16
16
|
on('-s', '--secret [SECRET]', 'The secret to save')
|
17
17
|
on('-g', '--generate-secret', 'Automatically generate the secret')
|
18
18
|
on('-f', '--file [FILE]', 'Read the secret to save from this file')
|
19
|
+
on('--folder [FOLDER]', 'The folder to put the secret in')
|
19
20
|
|
20
21
|
def run
|
21
22
|
self.title ||= terminal.ask 'What do you want to call this secret? '
|
@@ -23,6 +24,9 @@ module Duse
|
|
23
24
|
self.secret = SecretGenerator.new.generated_password if generate_secret?
|
24
25
|
self.secret ||= terminal.ask 'Secret to save: '
|
25
26
|
users = who_to_share_with
|
27
|
+
if self.folder.nil? && terminal.agree('Put secret in a folder other than the root folder?[y/n] ')
|
28
|
+
self.folder = terminal.ask 'Which folder do you want to put the secret in? (provide the id) '
|
29
|
+
end
|
26
30
|
|
27
31
|
user = Duse::User.current
|
28
32
|
ensure_matching_keys_for user
|
@@ -30,6 +34,7 @@ module Duse
|
|
30
34
|
secret_hash = Duse::Client::CreateSecret.with(
|
31
35
|
title: self.title,
|
32
36
|
secret_text: self.secret,
|
37
|
+
folder_id: self.folder,
|
33
38
|
users: users
|
34
39
|
).sign_with(private_key).build
|
35
40
|
|
data/lib/duse/cli/secret_list.rb
CHANGED
@@ -8,9 +8,7 @@ module Duse
|
|
8
8
|
|
9
9
|
def run
|
10
10
|
secrets = Duse::Secret.all
|
11
|
-
secrets.each
|
12
|
-
say "#{s.id}: #{s.title}"
|
13
|
-
end
|
11
|
+
secrets.each { |s| say s.to_s }
|
14
12
|
if secrets.empty?
|
15
13
|
say 'You have not yet saved any secrets, ' \
|
16
14
|
"you can do so with \"duse #{SecretAdd.full_command}\"."
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'duse/cli'
|
2
|
+
require 'tree_outline'
|
3
|
+
|
4
|
+
module Duse
|
5
|
+
module CLI
|
6
|
+
class SecretTree < ApiCommand
|
7
|
+
description 'Print all secrets you have access to in a tree'
|
8
|
+
|
9
|
+
def run
|
10
|
+
root_folders = Duse::Folder.all
|
11
|
+
say TreeOutline.new(root_folders.first).to_s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -36,7 +36,8 @@ module Duse
|
|
36
36
|
title = terminal.ask 'What do you want to call this secret? ' if terminal.agree 'Change the title? '
|
37
37
|
secret_text = terminal.ask 'Secret to save: ' if terminal.agree 'Change the secret? '
|
38
38
|
users = who_to_share_with if terminal.agree 'Change accessible users? '
|
39
|
-
|
39
|
+
folder = terminal.ask 'Which folder do you want to put the secret in? (provide the id) ' if terminal.agree 'Change the folder the secret lies in?[y/n] '
|
40
|
+
{ title: title, secret_text: secret_text, users: users, folder_id: folder }.delete_if { |k, v| v.nil? }
|
40
41
|
end
|
41
42
|
end
|
42
43
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'duse/client/entity'
|
4
|
+
|
5
|
+
module Duse
|
6
|
+
module Client
|
7
|
+
class Folder < Entity
|
8
|
+
FOLDER_SYMBOL = '📂'
|
9
|
+
|
10
|
+
attributes :id, :name
|
11
|
+
has :secrets
|
12
|
+
has :subfolders
|
13
|
+
|
14
|
+
id_field :id
|
15
|
+
one :folder
|
16
|
+
one :subfolder
|
17
|
+
many :folders
|
18
|
+
many :subfolders
|
19
|
+
|
20
|
+
def children
|
21
|
+
self.subfolders + self.secrets
|
22
|
+
end
|
23
|
+
|
24
|
+
def id_name
|
25
|
+
return "#{FOLDER_SYMBOL} #{self.name}" if self.id.nil?
|
26
|
+
"#{FOLDER_SYMBOL} #{self.id}: #{self.name}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
"#{FOLDER_SYMBOL} #{self.name}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/duse/client/secret.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
require 'duse/client/entity'
|
2
4
|
require 'duse/encryption'
|
3
5
|
require 'secret_sharing'
|
@@ -23,6 +25,7 @@ module Duse
|
|
23
25
|
def build
|
24
26
|
result = {}
|
25
27
|
result[:title] = @values[:title] if @values[:title]
|
28
|
+
result[:folder_id] = @values[:folder_id].to_i if @values[:folder_id]
|
26
29
|
if @values[:secret_text]
|
27
30
|
users = @secret.users || @values[:current_users]
|
28
31
|
cipher_text, shares = Encryption.encrypt(@values[:secret_text], users, @private_key)
|
@@ -53,7 +56,8 @@ module Duse
|
|
53
56
|
{
|
54
57
|
title: @options[:title],
|
55
58
|
cipher_text: cipher_text,
|
56
|
-
shares: shares
|
59
|
+
shares: shares,
|
60
|
+
folder_id: @options[:folder_id]
|
57
61
|
}
|
58
62
|
end
|
59
63
|
end
|
@@ -66,6 +70,8 @@ module Duse
|
|
66
70
|
@title = options.fetch(:title)
|
67
71
|
@secret_text = options.fetch(:secret_text)
|
68
72
|
@users = options.fetch(:users)
|
73
|
+
@folder_id = options.fetch(:folder_id, nil)
|
74
|
+
@folder_id = @folder_id.to_i if !@folder_id.nil?
|
69
75
|
end
|
70
76
|
|
71
77
|
def sign_with(private_key)
|
@@ -73,7 +79,8 @@ module Duse
|
|
73
79
|
title: @title,
|
74
80
|
secret_text: @secret_text,
|
75
81
|
users: @users,
|
76
|
-
private_key: private_key
|
82
|
+
private_key: private_key,
|
83
|
+
folder_id: @folder_id
|
77
84
|
)
|
78
85
|
end
|
79
86
|
end
|
@@ -101,6 +108,10 @@ module Duse
|
|
101
108
|
end
|
102
109
|
true
|
103
110
|
end
|
111
|
+
|
112
|
+
def to_s
|
113
|
+
"🔐 #{self.id}: #{self.title}"
|
114
|
+
end
|
104
115
|
end
|
105
116
|
|
106
117
|
class Share < Entity
|
data/lib/duse/encryption.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
1
|
require 'openssl'
|
2
2
|
require 'digest/sha2'
|
3
3
|
require 'base64'
|
4
|
+
require 'secret_sharing'
|
4
5
|
|
5
6
|
module Duse
|
6
7
|
module Encryption
|
8
|
+
module Digest
|
9
|
+
def digest
|
10
|
+
OpenSSL::Digest::SHA256.new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
7
14
|
module Encoding
|
8
15
|
def encode(plain_text)
|
9
16
|
Base64.encode64(plain_text).encode('utf-8')
|
@@ -17,9 +24,11 @@ module Duse
|
|
17
24
|
module Asymmetric
|
18
25
|
extend self
|
19
26
|
extend Duse::Encryption::Encoding
|
27
|
+
extend Duse::Encryption::Digest
|
28
|
+
PADDING = OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
|
20
29
|
|
21
30
|
def encrypt(private_key, public_key, text)
|
22
|
-
encrypted = public_key.public_encrypt text.force_encoding('ascii-8bit')
|
31
|
+
encrypted = public_key.public_encrypt text.force_encoding('ascii-8bit'), PADDING
|
23
32
|
signature = sign(private_key, encrypted)
|
24
33
|
[encode(encrypted), signature]
|
25
34
|
end
|
@@ -29,16 +38,12 @@ module Duse
|
|
29
38
|
end
|
30
39
|
|
31
40
|
def decrypt(private_key, text)
|
32
|
-
private_key.private_decrypt(decode(text)).force_encoding('utf-8')
|
41
|
+
private_key.private_decrypt(decode(text), PADDING).force_encoding('utf-8')
|
33
42
|
end
|
34
43
|
|
35
44
|
def verify(public_key, signature, encrypted)
|
36
45
|
public_key.verify digest, decode(signature), decode(encrypted)
|
37
46
|
end
|
38
|
-
|
39
|
-
def digest
|
40
|
-
OpenSSL::Digest::SHA256.new
|
41
|
-
end
|
42
47
|
end
|
43
48
|
|
44
49
|
module Symmetric
|
@@ -78,7 +83,22 @@ module Duse
|
|
78
83
|
end
|
79
84
|
end
|
80
85
|
|
86
|
+
module CryptographicHash
|
87
|
+
extend self
|
88
|
+
extend Duse::Encryption::Encoding
|
89
|
+
extend Duse::Encryption::Digest
|
90
|
+
|
91
|
+
def hmac(key, data)
|
92
|
+
encode(OpenSSL::HMAC.digest(digest, key, data))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
81
96
|
extend self
|
97
|
+
extend Duse::Encryption::Encoding
|
98
|
+
|
99
|
+
def hmac(key, data)
|
100
|
+
Duse::Encryption::CryptographicHash.hmac(key, data)
|
101
|
+
end
|
82
102
|
|
83
103
|
def encrypt(secret_text, users, private_key)
|
84
104
|
key, iv, cipher_text = Encryption::Symmetric.encrypt secret_text
|
@@ -95,8 +115,12 @@ module Duse
|
|
95
115
|
raw_shares = SecretSharing.split(symmetric_key, 2, users.length)
|
96
116
|
users.map.with_index do |user, index|
|
97
117
|
share = raw_shares[index]
|
98
|
-
|
99
|
-
{
|
118
|
+
cipher, signature = Encryption::Asymmetric.encrypt(private_key, user.public_key, share)
|
119
|
+
{
|
120
|
+
"user_id" => user.id,
|
121
|
+
"content" => cipher,
|
122
|
+
"signature" => signature
|
123
|
+
}
|
100
124
|
end
|
101
125
|
end
|
102
126
|
|
data/lib/duse/version.rb
CHANGED
data/spec/cli/cli_config_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
describe 'duse login' do
|
1
|
+
describe 'duse login', :fs => :fake do
|
2
2
|
before :each do
|
3
3
|
FileUtils.mkdir_p Duse::CLIConfig.config_dir
|
4
4
|
open(Duse::CLIConfig.config_file, 'w') do |f|
|
@@ -10,7 +10,7 @@ describe 'duse login' do
|
|
10
10
|
context 'correct credentials' do
|
11
11
|
it 'writes the auth token in the config file' do
|
12
12
|
open(File.join(Duse::CLIConfig.config_dir, 'flower-pot'), 'w') do |f|
|
13
|
-
f.puts
|
13
|
+
f.puts user_private_key.to_s
|
14
14
|
end
|
15
15
|
stub_user_me_get
|
16
16
|
stub_request(:post, "https://example.com/users/token").
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
RSpec.describe 'duse secret', :fs => :fake do
|
2
4
|
before :each do
|
3
5
|
FileUtils.mkdir_p Duse::CLIConfig.config_dir
|
4
6
|
open(Duse::CLIConfig.config_file, 'w') do |f|
|
@@ -7,7 +9,7 @@ RSpec.describe 'duse secret' do
|
|
7
9
|
f.puts 'token: token'
|
8
10
|
end
|
9
11
|
open(File.join(Duse::CLIConfig.config_dir, 'flower-pot'), 'w') do |f|
|
10
|
-
f.puts
|
12
|
+
f.puts user_private_key.to_s
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
@@ -61,7 +63,7 @@ RSpec.describe 'duse secret' do
|
|
61
63
|
stub_secret_get
|
62
64
|
stub_user_me_get
|
63
65
|
stub_server_user_get
|
64
|
-
|
66
|
+
stub_user_get2
|
65
67
|
stub_user_get2
|
66
68
|
|
67
69
|
run_cli('secret', 'get') { |i| i.puts('1') }
|
@@ -74,12 +76,24 @@ RSpec.describe 'duse secret' do
|
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
79
|
+
describe 'tree' do
|
80
|
+
xit 'prints the secrets in folder/secrets tree' do
|
81
|
+
stub_get_folders
|
82
|
+
|
83
|
+
expect(run_cli('secret', 'tree').out).to eq(
|
84
|
+
"1: test\n"
|
85
|
+
)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
77
89
|
describe 'list' do
|
78
|
-
it 'lists secrets' do
|
90
|
+
it 'lists secrets as id:secret pairs' do
|
79
91
|
stub_get_secrets
|
80
92
|
|
81
|
-
|
82
|
-
|
93
|
+
run_cli('secret', 'list')
|
94
|
+
output = last_run.out
|
95
|
+
expect(output).to eq(
|
96
|
+
"🔐 1: test\n"
|
83
97
|
)
|
84
98
|
end
|
85
99
|
end
|
@@ -106,6 +120,7 @@ RSpec.describe 'duse secret' do
|
|
106
120
|
i.puts 'test'
|
107
121
|
i.puts 'test'
|
108
122
|
i.puts 'n'
|
123
|
+
i.puts 'n'
|
109
124
|
end.success?).to be true
|
110
125
|
end
|
111
126
|
end
|
@@ -123,6 +138,7 @@ RSpec.describe 'duse secret' do
|
|
123
138
|
i.puts 'test'
|
124
139
|
i.puts 'y'
|
125
140
|
i.puts '1'
|
141
|
+
i.puts 'n'
|
126
142
|
end.success?).to be true
|
127
143
|
|
128
144
|
expect(last_run.out).to match(
|
@@ -145,6 +161,7 @@ RSpec.describe 'duse secret' do
|
|
145
161
|
i.puts 'Y'
|
146
162
|
i.puts '3'
|
147
163
|
i.puts '1'
|
164
|
+
i.puts 'n'
|
148
165
|
end.success?).to be true
|
149
166
|
end
|
150
167
|
end
|
data/spec/client/secret_spec.rb
CHANGED
@@ -25,12 +25,11 @@ RSpec.describe Duse::Client::Secret do
|
|
25
25
|
context 'secret exists' do
|
26
26
|
it 'loads a single secret with shares' do
|
27
27
|
stub_secret_get
|
28
|
-
private_key = OpenSSL::PKey::RSA.new "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAmMm3Ovh7gU0rLHK4NiHhWaYRrV9PH6XtHqV0GoiHH7awrjVk\nT1aZiS+nlBxckfuvuQjRXakVCZh18UdQadVQ7FLTWMZNoZ/uh41g4Iv17Wh1I3Fg\nqihdm83cSWvJ81qQCVGBaKeVitSa49zT/MmooBvYFwulaqJjhqFc3862Rl3WowzG\nVqGf+OiYhFrBbnIqXijDmVKsbqkG5AILGo1nng06HIAvMqUcGMebgoju9SuKaR+C\n46KT0K5sPpNw/tNcDEZqZAd25QjAroGnpRHSI9hTEuPopPSyRqz/EVQfbhi0Lbkd\nDW9S5ECw7GfFPFpRp2239fjl/9ybL6TkeZL7AwIDAQABAoIBAQCGSVyLLxRWC/4z\nPc0cfuCyy5xj1g4UEeD7+421OGQTAp39L54vgTzG76SJL/hIsn660b46ZL7BxUd8\nPiK2Mi/C1fU95GUc9hVO/Hq2QS1wcUvrT94XEA1eQCwqN9uy0Nkh54om8owkDkLo\nnRGQ76kOuApQDwNfWsTA8phPeT6JTtr+2K2yc0H4G5G0+py2GDclq56E99SljAqq\nwjFKGazqF0pxJvqLRCR9uVt0FgrRANOLGvxPMNZtnkVBVHmXs1iRD7BUALfESGS1\nHXZxjvD487E2h0Vjkli7rqnu6FZNgQ8Mq5TOfIm5i04LeGCgSTNP9sw7vdZgaYgT\nDPK9BIlZAoGBAMlhenDUOkT1dm28CjGCkygM1kUgDTQDLyBXW/JacotRp3GVZLr2\nV/2rZ3JPxva0cjjs3X4q/CxYsHvqI/ImXbsTBOYIT1/y1fgmXvN6AbiVW5Qne1UD\nneEGqCyB6YfKV2/8CX5Ru01Ay1EYVQDU4APkR1P4H38CuTMeu8SHK/BHAoGBAMI6\nR6TeEIdLprWRmUKU8Iuiwwm0SVxle2trSj6mknsJ93sK7gQkoKNzw0qwZdM6ApKH\nbJo/LiwiZ1Znx1NOyDsKT/ET6CSl59jOBuSUoxqTJ8XvrWlSD8pkbOJ2zWF8WqFR\ncC74bNFgd+n0tftR/7dwkriebITrp5IpF6P2Z9llAoGAAqO3ciEl/l9lRPzw+UMn\n4J+Cc3d/FM5x4K+kceHDnJXeZvu5TUYLUzTa70Gibvtgf+SC5rNziLVE4urnu7XL\nBreyGb3EJJLPQShnmDNiMGQsxh1aXXvlptxqeeLeB7ycNsiL607w8ItH3vE9s/wW\nT5a/ZJdc+lIz0Tq25VWMOuMCgYAejVZZu8izz5WguA94pr8T5/1wGFj13MzGP/FE\n26TtD8tLIpQAONa//2S36fmKeXSQIhdWSBv2O08wC1ESbLEYgG3EyVHZ+fL3aqkw\n6aSieIVoIGSRzaPIPXXXRcLW093ZxFq2OMO9R8R1G9ZIe0STUXTy75C4c+0/E5Gx\nbAA39QKBgDLjtjmG3nJGpQuaftAAjJR+AcA3svSdVug7w5k6D+lxBeM/x4pGP9z4\nkdOrqeD6bv1cctouVVywK/ZQ8dyLczJoGfJIlCvacI1L7fyVUpBp2Lby/uwYMd5w\ngswew+6Xnvtx15SirvYQmDRzA71KBSA4GxpaFwthRIxIwn881m5U\n-----END RSA PRIVATE KEY-----\n"
|
29
28
|
|
30
29
|
secret = Duse::Secret.find 1
|
31
30
|
|
32
31
|
expect(secret.title).to eq 'test'
|
33
|
-
expect(secret.decrypt(
|
32
|
+
expect(secret.decrypt(user_private_key)).to eq 'test'
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
@@ -63,45 +62,38 @@ RSpec.describe Duse::Client::Secret do
|
|
63
62
|
describe '.create' do
|
64
63
|
it 'builds a secret' do
|
65
64
|
stub_create_secret
|
66
|
-
|
67
|
-
|
68
|
-
server_user_public_key = OpenSSL::PKey::RSA.new "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvyvyAf7lnVx9eQcAS7JL\nYRHrqJJe51rAdanaUiiy8eek2Iyh6JG551EK7x4n9/Y7r0fW2sNmy+Bp3FpL8E/p\ncxutggTWCnUQUvXmEEm5qZ1KOIIlEQNp5glToAenJ7pxotJsTMlVw4tizsKScenc\n8w+02wpcmWuzWKjoY/G5KV33UDz/LxVo1RJdJp94JiL/OinIl+uk+Vf7VZj/E8g/\n7DyXIuiBosVpj9E9T4kpxs3/7RmUfDzUisVq0UvgflRjvP1V+1KdpNnjVB+H08mb\nSVO6yf2YOcrPDRa3pgz7PIr225QJ+HmVjPTg5VAy7rUxhCK+q+HNd2oz35zA70SO\npQIDAQAB\n-----END PUBLIC KEY-----\n"
|
69
|
-
current_user = OpenStruct.new id: 1, public_key: current_user_public_key
|
70
|
-
server_user = OpenStruct.new id: 2, public_key: server_user_public_key
|
65
|
+
current_user = OpenStruct.new id: 1, public_key: user_public_key
|
66
|
+
server_user = OpenStruct.new id: 2, public_key: server_public_key
|
71
67
|
|
72
68
|
secret_json = Duse::Client::CreateSecret.with(
|
73
69
|
title: 'secret title',
|
74
70
|
secret_text: 'test',
|
75
71
|
users: [current_user, server_user]
|
76
|
-
).sign_with(
|
72
|
+
).sign_with(user_private_key).build
|
77
73
|
secret = Duse::Secret.create secret_json
|
78
74
|
|
79
75
|
expect(secret.title).to eq 'test'
|
80
|
-
expect(secret.decrypt(
|
76
|
+
expect(secret.decrypt(user_private_key)).to eq 'test'
|
81
77
|
end
|
82
78
|
end
|
83
79
|
|
84
80
|
describe 'creation process' do
|
85
81
|
context 'own and server user' do
|
86
82
|
def test_working_encryption_and_decryption_for(plaintext)
|
87
|
-
|
88
|
-
|
89
|
-
server_user_private_key = OpenSSL::PKey::RSA.new "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAvyvyAf7lnVx9eQcAS7JLYRHrqJJe51rAdanaUiiy8eek2Iyh\n6JG551EK7x4n9/Y7r0fW2sNmy+Bp3FpL8E/pcxutggTWCnUQUvXmEEm5qZ1KOIIl\nEQNp5glToAenJ7pxotJsTMlVw4tizsKScenc8w+02wpcmWuzWKjoY/G5KV33UDz/\nLxVo1RJdJp94JiL/OinIl+uk+Vf7VZj/E8g/7DyXIuiBosVpj9E9T4kpxs3/7RmU\nfDzUisVq0UvgflRjvP1V+1KdpNnjVB+H08mbSVO6yf2YOcrPDRa3pgz7PIr225QJ\n+HmVjPTg5VAy7rUxhCK+q+HNd2oz35zA70SOpQIDAQABAoIBAQCHXFJrX1St64Nc\nYryu3HvLK6k1Hw7bucJ0jePsMK0j4+Uw/8LUrfp380ZOsYeTZ2IzZiaXl6v9x9St\nFbKXYb3mpz5fxZTYqrL4Suyvs8QmeRzIjj44obYmD4yKz2BoHPfBVkUgyZ5Uayl3\nRQX0aqbr478nKVsPttayfEawHcQBqTHPE9dfavuT14/64iqkrIya4ejFVXd1vYG2\nx+oKedPAnD3jr9foEHTqj1D4AeORwonbxFllh3K91IcabV3zdIZH0ICvYaaryceU\n2npp1H0mqETMZ97o3uMo8S5AEK7TsyB26WlD1IUSfwaP3apkog2WMNvgU4c2OD/q\nX8l3mA2BAoGBAOHGaZtBXQUSUD95eQAG/03F1Non21dD+aUtMbDn1Li6aOD+C+a4\ncJVZ+D2nMMIoQz3nEBIVoEdK4prugQXZJ87pvWwpZ/afRmTNSYWHnJmmg5/rvrZ5\nuvR17DwmS5ucTVOWcdryoG0O5KZqyAnpshLecr5PALY+cfG+fjo6KxNpAoGBANjD\noeFiSZ5a9aS8QR4pHkHz4zjDh/JglN4F7QFSLBLdnn54HHguq8oyg6VXQVMv6IA6\nnFv4wcypyjO+wRktwW+pklpoIuPaTNbHykBTjWD+Ew82iEIzh2m9j43UdGM+Kfmh\nGUSCYorwZG41v2GyepnCDWC5H3RslmxZ6+e9XcXdAoGALz3GAS93GEWRtwZi1Cei\nqhJYDGHEmojlprNDL4IC17hhk5p0wQ0cuZN+xt/B6w5jq4M6sJ4H0IMR0VtQcfnT\nQ49TDFvJnigLobH2zVLn6JqX9hFs8V+dR+OYz6kvrtrQr0nOfwK/oLI6E7xKKRDW\nKu6S0dFUE84TJ4M1hFeBhekCgYEAnYX9vBZ7PXMIlECiadKjxHYCKBwgTUlWpcpU\no+MdWFBpf6q1tbjk6rmu5Zb1SAjGw3jUbBnobFzvLo9vMGcJ7aWjT8PhpwfbUzI5\njmmpklTRcPrGJqXfwD4bdoxwUDa6tkgWXq0KA8ISmezBObREWDynECU38JmA7xih\n0PTSkpkCgYBUUASKsz2ThzQiAU+Ivu2Y/QON78N0ZyQ/0kDhxZ8AUnbtGZAOq5pV\nRMj053t5oJMr2eWkMZ5aBYmjo0Uy4vrRCV6SXrlAs3YsN1mh1P+xGRRmX99xwalJ\n6dQaTBdtQ33MhY0+17EXr6WUGRZHIcFM6uGa32MKSmeqkATuV7eyzg==\n-----END RSA PRIVATE KEY-----\n"
|
90
|
-
server_user_public_key = OpenSSL::PKey::RSA.new "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvyvyAf7lnVx9eQcAS7JL\nYRHrqJJe51rAdanaUiiy8eek2Iyh6JG551EK7x4n9/Y7r0fW2sNmy+Bp3FpL8E/p\ncxutggTWCnUQUvXmEEm5qZ1KOIIlEQNp5glToAenJ7pxotJsTMlVw4tizsKScenc\n8w+02wpcmWuzWKjoY/G5KV33UDz/LxVo1RJdJp94JiL/OinIl+uk+Vf7VZj/E8g/\n7DyXIuiBosVpj9E9T4kpxs3/7RmUfDzUisVq0UvgflRjvP1V+1KdpNnjVB+H08mb\nSVO6yf2YOcrPDRa3pgz7PIr225QJ+HmVjPTg5VAy7rUxhCK+q+HNd2oz35zA70SO\npQIDAQAB\n-----END PUBLIC KEY-----\n"
|
91
|
-
current_user = OpenStruct.new id: 1, public_key: current_user_public_key
|
92
|
-
server_user = OpenStruct.new id: 2, public_key: server_user_public_key
|
83
|
+
current_user = OpenStruct.new id: 1, public_key: user_public_key
|
84
|
+
server_user = OpenStruct.new id: 2, public_key: server_public_key
|
93
85
|
secret = Duse::Client::CreateSecret.with(
|
94
86
|
title: 'test',
|
95
87
|
secret_text: plaintext,
|
96
88
|
users: [current_user, server_user]
|
97
|
-
).sign_with(
|
89
|
+
).sign_with(user_private_key).build
|
98
90
|
|
99
|
-
|
100
|
-
|
101
|
-
shares[1].content, _ = Duse::Encryption::Asymmetric.encrypt(current_user_private_key, current_user_public_key, server_share)
|
91
|
+
server_share = Duse::Encryption::Asymmetric.decrypt(server_private_key, secret[:shares][1]['content'])
|
92
|
+
secret[:shares][1]['content'], secret[:shares][1]['signature'] = Duse::Encryption::Asymmetric.encrypt(user_private_key, user_public_key, server_share)
|
102
93
|
|
94
|
+
shares = secret[:shares].map { |s| Duse::Client::Share.new(s) }
|
103
95
|
secret = Duse::Client::Secret.new shares: shares, cipher_text: secret[:cipher_text]
|
104
|
-
decrypted_secret = secret.decrypt(
|
96
|
+
decrypted_secret = secret.decrypt(user_private_key)
|
105
97
|
|
106
98
|
expect(decrypted_secret).to eq plaintext
|
107
99
|
end
|
@@ -111,8 +103,8 @@ RSpec.describe Duse::Client::Secret do
|
|
111
103
|
test_working_encryption_and_decryption_for(secret_text)
|
112
104
|
end
|
113
105
|
|
114
|
-
it 'can
|
115
|
-
secret_text =
|
106
|
+
it 'can hanle 4096 bit rsa keys' do
|
107
|
+
secret_text = OpenSSL::PKey::RSA.generate(4096).to_s
|
116
108
|
test_working_encryption_and_decryption_for(secret_text)
|
117
109
|
end
|
118
110
|
|
@@ -127,24 +119,20 @@ RSpec.describe Duse::Client::Secret do
|
|
127
119
|
context 'changin users' do
|
128
120
|
it 'leaves the cipher text unchanged and generates new shares' do
|
129
121
|
stub_secret_get
|
130
|
-
|
131
|
-
|
132
|
-
server_user_private_key = OpenSSL::PKey::RSA.new "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAvyvyAf7lnVx9eQcAS7JLYRHrqJJe51rAdanaUiiy8eek2Iyh\n6JG551EK7x4n9/Y7r0fW2sNmy+Bp3FpL8E/pcxutggTWCnUQUvXmEEm5qZ1KOIIl\nEQNp5glToAenJ7pxotJsTMlVw4tizsKScenc8w+02wpcmWuzWKjoY/G5KV33UDz/\nLxVo1RJdJp94JiL/OinIl+uk+Vf7VZj/E8g/7DyXIuiBosVpj9E9T4kpxs3/7RmU\nfDzUisVq0UvgflRjvP1V+1KdpNnjVB+H08mbSVO6yf2YOcrPDRa3pgz7PIr225QJ\n+HmVjPTg5VAy7rUxhCK+q+HNd2oz35zA70SOpQIDAQABAoIBAQCHXFJrX1St64Nc\nYryu3HvLK6k1Hw7bucJ0jePsMK0j4+Uw/8LUrfp380ZOsYeTZ2IzZiaXl6v9x9St\nFbKXYb3mpz5fxZTYqrL4Suyvs8QmeRzIjj44obYmD4yKz2BoHPfBVkUgyZ5Uayl3\nRQX0aqbr478nKVsPttayfEawHcQBqTHPE9dfavuT14/64iqkrIya4ejFVXd1vYG2\nx+oKedPAnD3jr9foEHTqj1D4AeORwonbxFllh3K91IcabV3zdIZH0ICvYaaryceU\n2npp1H0mqETMZ97o3uMo8S5AEK7TsyB26WlD1IUSfwaP3apkog2WMNvgU4c2OD/q\nX8l3mA2BAoGBAOHGaZtBXQUSUD95eQAG/03F1Non21dD+aUtMbDn1Li6aOD+C+a4\ncJVZ+D2nMMIoQz3nEBIVoEdK4prugQXZJ87pvWwpZ/afRmTNSYWHnJmmg5/rvrZ5\nuvR17DwmS5ucTVOWcdryoG0O5KZqyAnpshLecr5PALY+cfG+fjo6KxNpAoGBANjD\noeFiSZ5a9aS8QR4pHkHz4zjDh/JglN4F7QFSLBLdnn54HHguq8oyg6VXQVMv6IA6\nnFv4wcypyjO+wRktwW+pklpoIuPaTNbHykBTjWD+Ew82iEIzh2m9j43UdGM+Kfmh\nGUSCYorwZG41v2GyepnCDWC5H3RslmxZ6+e9XcXdAoGALz3GAS93GEWRtwZi1Cei\nqhJYDGHEmojlprNDL4IC17hhk5p0wQ0cuZN+xt/B6w5jq4M6sJ4H0IMR0VtQcfnT\nQ49TDFvJnigLobH2zVLn6JqX9hFs8V+dR+OYz6kvrtrQr0nOfwK/oLI6E7xKKRDW\nKu6S0dFUE84TJ4M1hFeBhekCgYEAnYX9vBZ7PXMIlECiadKjxHYCKBwgTUlWpcpU\no+MdWFBpf6q1tbjk6rmu5Zb1SAjGw3jUbBnobFzvLo9vMGcJ7aWjT8PhpwfbUzI5\njmmpklTRcPrGJqXfwD4bdoxwUDa6tkgWXq0KA8ISmezBObREWDynECU38JmA7xih\n0PTSkpkCgYBUUASKsz2ThzQiAU+Ivu2Y/QON78N0ZyQ/0kDhxZ8AUnbtGZAOq5pV\nRMj053t5oJMr2eWkMZ5aBYmjo0Uy4vrRCV6SXrlAs3YsN1mh1P+xGRRmX99xwalJ\n6dQaTBdtQ33MhY0+17EXr6WUGRZHIcFM6uGa32MKSmeqkATuV7eyzg==\n-----END RSA PRIVATE KEY-----\n"
|
133
|
-
server_user_public_key = OpenSSL::PKey::RSA.new "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvyvyAf7lnVx9eQcAS7JL\nYRHrqJJe51rAdanaUiiy8eek2Iyh6JG551EK7x4n9/Y7r0fW2sNmy+Bp3FpL8E/p\ncxutggTWCnUQUvXmEEm5qZ1KOIIlEQNp5glToAenJ7pxotJsTMlVw4tizsKScenc\n8w+02wpcmWuzWKjoY/G5KV33UDz/LxVo1RJdJp94JiL/OinIl+uk+Vf7VZj/E8g/\n7DyXIuiBosVpj9E9T4kpxs3/7RmUfDzUisVq0UvgflRjvP1V+1KdpNnjVB+H08mb\nSVO6yf2YOcrPDRa3pgz7PIr225QJ+HmVjPTg5VAy7rUxhCK+q+HNd2oz35zA70SO\npQIDAQAB\n-----END PUBLIC KEY-----\n"
|
134
|
-
current_user = OpenStruct.new id: 1, public_key: current_user_public_key
|
135
|
-
server_user = OpenStruct.new id: 2, public_key: server_user_public_key
|
122
|
+
current_user = OpenStruct.new id: 1, public_key: user_public_key
|
123
|
+
server_user = OpenStruct.new id: 2, public_key: server_public_key
|
136
124
|
secret = Duse::Secret.find(1)
|
137
125
|
secret_hash = Duse::Client::UpdateSecret.values(
|
138
126
|
secret,
|
139
127
|
{ users: [current_user, server_user] }
|
140
|
-
).encrypt_with(
|
128
|
+
).encrypt_with(user_private_key).build
|
141
129
|
|
142
130
|
shares = secret_hash[:shares].map { |s| Duse::Client::Share.new(s) }
|
143
|
-
server_share = Duse::Encryption::Asymmetric.decrypt(
|
144
|
-
shares[1].content,
|
131
|
+
server_share = Duse::Encryption::Asymmetric.decrypt(server_private_key, shares[1].content)
|
132
|
+
shares[1].content, shares[1].signature = Duse::Encryption::Asymmetric.encrypt(user_private_key, user_public_key, server_share)
|
145
133
|
|
146
134
|
new_secret = Duse::Client::Secret.new shares: shares, cipher_text: secret.cipher_text
|
147
|
-
decrypted_secret = new_secret.decrypt(
|
135
|
+
decrypted_secret = new_secret.decrypt(user_private_key)
|
148
136
|
|
149
137
|
expect(decrypted_secret).to eq 'test'
|
150
138
|
expect(new_secret.shares).not_to eq secret.shares
|