leeloo 0.2.0 → 0.5.0

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: 117b1ba8a4477a8cf18f5b180110d78627cc29a2d333e3a8e573647aedbbd749
4
- data.tar.gz: 4473cd401838c305e996c486bbc9517d095e237cd8a24edf6a4f1d125ac2f5f5
3
+ metadata.gz: b19454b20e434ee86fcca39a6cdf98f48dec70b5c775daff8709baf9b7359c12
4
+ data.tar.gz: c06c7449acb7c866ef2ee5be22c78fa97ee0d61a530bd575a8059daa1edb6fad
5
5
  SHA512:
6
- metadata.gz: 74d46a23581966899c00be7256054b73fa1a176e5c49ad84dbd9097fd4153c7da4dec98632293f8f022d86955104cd88741f71ebf008faf05f700f3682fc97de
7
- data.tar.gz: 7dd76b5c632308c3ea7c11e8f52c0e447410cfa791ae08fa342b266f8e22b42b355df03184c8d61da6cb4e09a00c2028beac2e7479a99e7034b4858052fecb80
6
+ metadata.gz: 056f03b0d8e76f92555e6a0ff50ed3da651055c9e9a2f246fd8714d907c200739a0d2f1dd013824b037dc24e2034d4e0d8f31aec023d928aa253a52f9b67d470
7
+ data.tar.gz: b872f7ef01b45a69edcb686dbccc5e5e02affc49c518eebde9eae60e7085e44eea8bda720bb68aa9c0766ba69139fb33c0ef48a93db04e2ba7329fc56fc059bc
@@ -9,29 +9,9 @@ end
9
9
 
10
10
  module Leeloo
11
11
 
12
- class OutputFactory
13
- def self.create options
14
- output = nil
15
- if options.ascii
16
- output = Ascii.new
17
- else
18
- output = Terminal.new
19
- end
20
- if options.clipboard
21
- ClipboardOutputDecorator.new output
22
- else
23
- output
24
- end
25
- end
26
- end
27
-
28
12
  class Command
29
13
  include Commander::Methods
30
14
 
31
- def initialize
32
- @preferences = PrivateLocalFileSystemPreferences.new.load
33
- end
34
-
35
15
  def run
36
16
  program :name, 'leeloo'
37
17
  program :version, Leeloo::VERSION
@@ -43,17 +23,29 @@ module Leeloo
43
23
  program :help, 'GitHub', 'https://github.com/sylvek'
44
24
  program :help_formatter, :compact
45
25
 
46
- default_command :"list"
26
+ default_command :wrapper
27
+
28
+ command :wrapper do |c|
29
+ c.action do |args, options|
30
+ unless args == []
31
+ name = args.first
32
+ ctl = SecretController.new(options)
33
+ ctl.read(name)
34
+ ctl.display
35
+ else
36
+ SecretsController.new(options).display
37
+ end
38
+ end
39
+ end
47
40
 
48
41
  command :list do |c|
49
42
  c.syntax = 'leeloo list [options]'
50
- c.description = "Display secrets list of keystore"
43
+ c.description = "Display secrets list of stored on a keystore"
51
44
  c.option '--ascii', nil, 'display secrets without unicode tree'
52
45
  c.option '--keystore STRING', String, 'a selected keystore'
53
46
 
54
47
  c.action do |args, options|
55
- keystore = @preferences.keystore(options.keystore)
56
- OutputFactory.create(options).render_secrets keystore.secrets
48
+ SecretsController.new(options).display
57
49
  end
58
50
  end
59
51
 
@@ -66,10 +58,9 @@ module Leeloo
66
58
  c.action do |args, options|
67
59
  abort "name is missing" unless args.length == 1
68
60
  name = args.first
69
-
70
- keystore = @preferences.keystore(options.keystore)
71
- secrets = keystore.secrets.select { |secret| secret.name.downcase.include? name.downcase } || []
72
- OutputFactory.create(options).render_secrets secrets
61
+ ctl = SecretsController.new(options)
62
+ ctl.search(name)
63
+ ctl.display
73
64
  end
74
65
  end
75
66
 
@@ -79,7 +70,20 @@ module Leeloo
79
70
  c.option '--ascii', nil, 'display secrets without unicode tree'
80
71
 
81
72
  c.action do |args, options|
82
- OutputFactory.create(options).render_preferences @preferences
73
+ KeystoreController.new(options).display
74
+ end
75
+ end
76
+
77
+ command "keystore remove" do |c|
78
+ c.syntax = 'leeloo keystore remove <name>'
79
+ c.description = "remove a keystore (path/to/keystore is not destroyed)"
80
+
81
+ c.action do |args, options|args
82
+ abort "name is missing" unless args.length == 1
83
+ name = args.first
84
+ ctl = KeystoreController.new(options)
85
+ ctl.remove(name)
86
+ ctl.display
83
87
  end
84
88
  end
85
89
 
@@ -89,10 +93,11 @@ module Leeloo
89
93
 
90
94
  c.action do |args, options|
91
95
  abort "name or path is missing" unless args.length == 2
92
-
93
- @preferences.add_keystore({"name" => args.first, "path" => args.last, "cypher" => "gpg", "vc" => "git"})
94
- @preferences.keystore(args.first).init
95
- OutputFactory.create(options).render_preferences @preferences
96
+ name = args.first
97
+ path = args.last
98
+ ctl = KeystoreController.new(options)
99
+ ctl.add(name, path)
100
+ ctl.display
96
101
  end
97
102
  end
98
103
 
@@ -102,9 +107,62 @@ module Leeloo
102
107
 
103
108
  c.action do |args, options|
104
109
  abort "name is missing" unless args.length == 1
110
+ name = args.first
111
+ ctl = KeystoreController.new(options)
112
+ ctl.set_default(name)
113
+ ctl.display
114
+ end
115
+ end
116
+
117
+ command :key do |c|
118
+ c.syntax = 'leeloo keys'
119
+ c.description = "list keys from this keystore"
120
+ c.option '--ascii', nil, 'display secrets without unicode tree'
121
+ c.option '--keystore STRING', String, 'a selected keystore'
122
+
123
+ c.action do |args, options|
124
+ ctl = KeysController.new(options)
125
+ ctl.display
126
+ end
127
+ end
105
128
 
106
- @preferences.set_default_keystore args.first
107
- OutputFactory.create(options).render_preferences @preferences
129
+ command "key sync" do |c|
130
+ c.syntax = 'leeloo keys sync'
131
+ c.description = "synchronize secrets with keys"
132
+ c.option '--keystore STRING', String, 'a selected keystore'
133
+
134
+ c.action do |args, options|
135
+ ctl = KeysController.new(options)
136
+ ctl.sync
137
+ ctl.display
138
+ end
139
+ end
140
+
141
+ command "key add" do |c|
142
+ c.syntax = 'leeloo key add <email>'
143
+ c.description = "add a dedicated key"
144
+ c.option '--keystore STRING', String, 'a selected keystore'
145
+
146
+ c.action do |args, options|
147
+ abort "email is missing" unless args.length == 1
148
+ email = args.first
149
+ ctl = KeysController.new(options)
150
+ ctl.add_key(email)
151
+ ctl.display
152
+ end
153
+ end
154
+
155
+ command "key remove" do |c|
156
+ c.syntax = 'leeloo key remove <email>'
157
+ c.description = "remove a dedicated key"
158
+ c.option '--keystore STRING', String, 'a selected keystore'
159
+
160
+ c.action do |args, options|
161
+ abort "email is missing" unless args.length == 1
162
+ email = args.first
163
+ ctl = KeysController.new(options)
164
+ ctl.remove_key(email)
165
+ ctl.display
108
166
  end
109
167
  end
110
168
 
@@ -118,10 +176,9 @@ module Leeloo
118
176
  c.action do |args, options|
119
177
  abort "name is missing" unless args.length == 1
120
178
  name = args.first
121
-
122
- keystore = @preferences.keystore(options.keystore)
123
- secret = keystore.secret_from_name(name)
124
- OutputFactory.create(options).render_secret secret
179
+ ctl = SecretController.new(options)
180
+ ctl.read(name)
181
+ ctl.display
125
182
  end
126
183
  end
127
184
 
@@ -136,22 +193,9 @@ module Leeloo
136
193
  c.action do |args, options|
137
194
  abort "name is missing" unless args.length == 1
138
195
  name = args.first
139
- phrase = nil
140
-
141
- phrase = STDIN.read if options.stdin
142
- phrase = SecureRandom.base64(32).truncate(options.generate.to_i) if options.generate
143
-
144
- unless phrase
145
- phrase = password "secret"
146
- confirm = password "confirm it"
147
- abort "not the same secret" unless phrase == confirm
148
- end
149
-
150
- keystore = @preferences.keystore(options.keystore)
151
- secret = keystore.secret_from_name(name)
152
- secret.write(phrase)
153
-
154
- OutputFactory.create(options).render_secret secret
196
+ ctl = SecretController.new(options)
197
+ ctl.write(name)
198
+ ctl.display
155
199
  end
156
200
  end
157
201
 
@@ -161,9 +205,9 @@ module Leeloo
161
205
  c.option '--keystore STRING', String, 'a selected keystore'
162
206
 
163
207
  c.action do |args, options|
164
- keystore = @preferences.keystore(options.keystore)
165
- text = STDIN.read
166
- OutputFactory.create(options).render_translate keystore, text
208
+ ctl = TranslateController.new(options)
209
+ ctl.translate
210
+ ctl.display
167
211
  end
168
212
  end
169
213
 
@@ -175,32 +219,83 @@ module Leeloo
175
219
  c.action do |args, options|
176
220
  abort "name is missing" unless args.length == 1
177
221
  name = args.first
178
-
179
- keystore = @preferences.keystore(options.keystore)
180
- secret = keystore.secret_from_name(name)
181
- secret.erase
222
+ ctl = SecretController.new(options)
223
+ ctl.remove(name)
224
+ ctl.display
182
225
  end
183
226
  end
184
227
 
185
- command :sync do |c|
228
+ command "keystore sync" do |c|
186
229
  c.syntax = 'leeloo sync'
187
230
  c.description = "Synchronize a keystore"
188
231
  c.option '--keystore STRING', String, 'a selected keystore'
189
232
 
190
233
  c.action do |args, options|
191
- keystore = @preferences.keystore(options.keystore)
192
- keystore.sync
234
+ ctl = KeystoreController.new(options)
235
+ ctl.sync
236
+ ctl.display
237
+ end
238
+ end
239
+
240
+ command "keystore export" do |c|
241
+ c.syntax = 'leeloo export'
242
+ c.description = "Export all secrets from a keystore"
243
+ c.option '--keystore STRING', String, 'a selected keystore'
244
+
245
+ c.action do |args, options|
246
+ ctl = ExportController.new(options)
247
+ ctl.display
193
248
  end
194
249
  end
195
250
 
196
- command :init do |c|
251
+ command "keystore init" do |c|
197
252
  c.syntax = 'leeloo init'
198
253
  c.description = "Initialize a keystore"
199
254
  c.option '--keystore STRING', String, 'a selected keystore'
200
255
 
201
256
  c.action do |args, options|
202
- keystore = @preferences.keystore(options.keystore)
203
- keystore.init
257
+ ctl = KeystoreController.new(options)
258
+ ctl.init
259
+ ctl.display
260
+ end
261
+ end
262
+
263
+ command :share do |c|
264
+ c.syntax = 'leeloo share <name>'
265
+ c.description = "share a secret with someone"
266
+ c.option '--keystore STRING', String, 'a selected keystore'
267
+
268
+ c.action do |args, options|
269
+ abort "name is missing" unless args.length == 1
270
+ name = args.first
271
+ ctl = ShareController.new(options)
272
+ ctl.token(name)
273
+ ctl.display
274
+ ctl.start_server
275
+ end
276
+ end
277
+
278
+ command :token do |c|
279
+ c.syntax = 'leeloo token <name>'
280
+ c.description = "generate an access token for a given secret"
281
+ c.option '--keystore STRING', String, 'a selected keystore'
282
+
283
+ c.action do |args, options|
284
+ abort "name is missing" unless args.length == 1
285
+ name = args.first
286
+ ctl = ShareController.new(options)
287
+ ctl.token(name)
288
+ ctl.display
289
+ end
290
+ end
291
+
292
+ command :server do |c|
293
+ c.syntax = 'leeloo server'
294
+ c.description = "start a server access token"
295
+
296
+ c.action do |args, options|
297
+ ctl = ShareController.new(options)
298
+ ctl.start_server
204
299
  end
205
300
  end
206
301
 
@@ -0,0 +1,152 @@
1
+ module Leeloo
2
+ class OutputFactory
3
+ def self.create options
4
+ output = nil
5
+ if options.ascii
6
+ output = Ascii.new
7
+ else
8
+ output = Terminal.new
9
+ end
10
+ if options.clipboard
11
+ ClipboardOutputDecorator.new output
12
+ else
13
+ output
14
+ end
15
+ end
16
+ end
17
+
18
+ class Controller
19
+ def display
20
+ end
21
+ end
22
+
23
+ class PrivateLocalFileSystemController < Controller
24
+ def initialize options
25
+ @preferences = PrivateLocalFileSystemPreferences.new.load
26
+ @keystore = @preferences.keystore(options.keystore)
27
+ @output = OutputFactory.create(options)
28
+ @options = options
29
+ end
30
+ end
31
+
32
+ class SecretsController < PrivateLocalFileSystemController
33
+ def initialize options
34
+ super options
35
+ @secrets = @keystore.secrets
36
+ end
37
+ def search name
38
+ @secrets = @secrets.select { |secret| secret.name.downcase.include? name.downcase } || []
39
+ end
40
+ def list
41
+ @secrets
42
+ end
43
+ def display
44
+ @output.render_secrets @secrets
45
+ end
46
+ end
47
+
48
+ class ExportController < PrivateLocalFileSystemController
49
+ def display
50
+ @keystore.secrets.each do |secret|
51
+ @output.render_name_and_secret(secret.name, @keystore.secret_from_name(secret.name))
52
+ end
53
+ end
54
+ end
55
+
56
+ class KeysController < PrivateLocalFileSystemController
57
+ def add_key email
58
+ @keystore.add_key(email)
59
+ end
60
+ def remove_key email
61
+ @keystore.remove_key(email)
62
+ end
63
+ def sync
64
+ @keystore.secrets.each do |secret|
65
+ phrase = @keystore.secret_from_name(secret.name).read
66
+ @keystore.secret_from_name(secret.name).write(phrase)
67
+ end
68
+ end
69
+ def display
70
+ @keys = @keystore.keys
71
+ @output.render_keys @keys
72
+ end
73
+ end
74
+
75
+ class SecretController < PrivateLocalFileSystemController
76
+ def read name
77
+ @secret = @keystore.secret_from_name(name)
78
+ end
79
+ def write name
80
+ phrase = nil
81
+
82
+ phrase = STDIN.read if @options.stdin
83
+ phrase = SecureRandom.base64(32).truncate(@options.generate.to_i) if @options.generate
84
+
85
+ unless phrase
86
+ phrase = password "secret"
87
+ confirm = password "confirm it"
88
+ abort "not the same secret" unless phrase == confirm
89
+ end
90
+
91
+ @secret = @keystore.secret_from_name(name)
92
+ @secret.write(phrase)
93
+ end
94
+ def remove name
95
+ @secret = @keystore.secret_from_name(name)
96
+ @secret.erase
97
+ end
98
+ def display
99
+ @output.render_secret @secret
100
+ end
101
+ end
102
+
103
+ class TranslateController < PrivateLocalFileSystemController
104
+ def translate
105
+ @text = STDIN.read
106
+ @text.scan(/\$\{.*\}/).each do |secret|
107
+ begin
108
+ @text.gsub! secret, (@keystore.secret_from_name(secret[2..-2])).read.to_s.strip
109
+ rescue => exception
110
+ # silent
111
+ end
112
+ end
113
+ end
114
+ def display
115
+ @output.render_text @text
116
+ end
117
+ end
118
+
119
+ class KeystoreController < PrivateLocalFileSystemController
120
+ def add name, path
121
+ @preferences.add_keystore({"name" => name, "path" => path, "cypher" => "gpg", "vc" => "git"})
122
+ @preferences.keystore(name).init
123
+ end
124
+ def remove name
125
+ @preferences.remove_keystore name
126
+ end
127
+ def set_default name
128
+ @preferences.set_default_keystore name
129
+ end
130
+ def sync
131
+ @keystore.sync
132
+ end
133
+ def init
134
+ @keystore.init
135
+ end
136
+ def display
137
+ @output.render_preferences @preferences
138
+ end
139
+ end
140
+
141
+ class ShareController < PrivateLocalFileSystemController
142
+ def token name
143
+ @footprint = @keystore.footprint_of(name)
144
+ end
145
+ def start_server
146
+ Server.new.start @preferences
147
+ end
148
+ def display
149
+ @output.render_footprint @footprint
150
+ end
151
+ end
152
+ end
@@ -1,6 +1,7 @@
1
1
  require 'gpgme'
2
2
  require 'fileutils'
3
3
  require 'git'
4
+ require 'base64'
4
5
 
5
6
  module Leeloo
6
7
 
@@ -51,6 +52,14 @@ module Leeloo
51
52
  # initialize the keystore
52
53
  end
53
54
 
55
+ def footprint name
56
+ # footprint a given secret path
57
+ end
58
+
59
+ def secret_from_footprint footprint
60
+ # returns a secret object
61
+ end
62
+
54
63
  def == keystore
55
64
  self.name == keystore.name
56
65
  end
@@ -70,6 +79,10 @@ module Leeloo
70
79
  find_secrets "#{@path}/secrets"
71
80
  end
72
81
 
82
+ def keys
83
+ []
84
+ end
85
+
73
86
  def find_secrets path
74
87
  elements = []
75
88
  Dir.glob("#{path}/**") do |element|
@@ -92,6 +105,19 @@ module Leeloo
92
105
  secret_of "#{path}/secrets/#{name}"
93
106
  end
94
107
 
108
+ def footprint_of name
109
+ secret = secret_from_name name
110
+ { "footprint" => secret.footprint, "keystore" => self.name, "secret" => secret.name }
111
+ end
112
+
113
+ def secret_from_footprint footprint
114
+ secret = secret_from_name footprint["secret"]
115
+ unless secret.footprint == footprint["footprint"]
116
+ raise "footprint is not valid"
117
+ end
118
+ secret
119
+ end
120
+
95
121
  end
96
122
 
97
123
  class GpgPrivateLocalFileSystemKeystore < PrivateLocalFileSystemKeystore
@@ -99,7 +125,10 @@ module Leeloo
99
125
  def initialize name, path
100
126
  super name, path
101
127
  FileUtils.mkdir_p "#{@path}/keys"
128
+ populate_recipients
129
+ end
102
130
 
131
+ def populate_recipients
103
132
  @recipients = []
104
133
  Dir.glob("#{path}/keys/*") { |key| @recipients << File.basename(key) }
105
134
  @recipients.each { |key| GPGME::Key.import(File.open("#{path}/keys/#{key}")) }
@@ -107,7 +136,30 @@ module Leeloo
107
136
 
108
137
  def init
109
138
  super
110
- GPGME::Key.find(:public, nil, ).each { |key| key.export(:output => File.open("#{path}/keys/#{key.uids.first.email}", "w+")) }
139
+ File.write("#{@path}/keys/do_not_remove_me", "do not remove me")
140
+ end
141
+
142
+ def keys
143
+ available = GPGME::Key.find(:public, nil, ).map { |key| key.email }
144
+ actual = Dir.glob("#{@path}/keys/**").map { |path| path.split('/').last }
145
+ available.map { |email| actual.include?(email) ? "#{email}::true" : "#{email}::false" }
146
+ end
147
+
148
+ def add_key email
149
+ paths = []
150
+ GPGME::Key.find(:public, email).each do |key|
151
+ key.export(:output => File.open("#{path}/keys/#{key.uids.first.email}", "w+"))
152
+ paths << "#{path}/keys/#{key.uids.first.email}"
153
+ end
154
+ return paths
155
+ end
156
+
157
+ def remove_key email
158
+ if File.exist?("#{path}/keys/#{email}")
159
+ File.delete("#{path}/keys/#{email}")
160
+ return "#{path}/keys/#{email}"
161
+ end
162
+ return nil
111
163
  end
112
164
 
113
165
  def secret_of path
@@ -119,6 +171,20 @@ module Leeloo
119
171
  secret_of "#{path}/secrets/#{name}.gpg"
120
172
  end
121
173
 
174
+ def footprint_of name
175
+ footprint = super name
176
+ footprint["sign"] = Base64.strict_encode64 GPGME::Crypto.new.sign(footprint["footprint"]).to_s
177
+ footprint
178
+ end
179
+
180
+ def secret_from_footprint footprint
181
+ data = GPGME::Crypto.new.verify(Base64.strict_decode64 footprint["sign"]) { |signature| signature.valid? }
182
+ if data.read == footprint["footprint"]
183
+ super footprint
184
+ else
185
+ raise "signature is not valid"
186
+ end
187
+ end
122
188
  end
123
189
 
124
190
  class GitKeystoreDecorator < Keystore
@@ -136,6 +202,25 @@ module Leeloo
136
202
  secret_of @keystore.secret_from_name(element)
137
203
  end
138
204
 
205
+ def keys
206
+ @keystore.keys
207
+ end
208
+
209
+ def add_key email
210
+ @keystore.add_key(email).each do |path|
211
+ @git.add path
212
+ @git.commit "#{email} added"
213
+ end
214
+ end
215
+
216
+ def remove_key email
217
+ deleted = @keystore.remove_key email
218
+ if deleted
219
+ @git.add deleted
220
+ @git.commit "#{email} removed"
221
+ end
222
+ end
223
+
139
224
  def secrets
140
225
  @keystore.secrets
141
226
  end
@@ -148,6 +233,14 @@ module Leeloo
148
233
  @keystore.path
149
234
  end
150
235
 
236
+ def footprint_of element
237
+ @keystore.footprint_of element
238
+ end
239
+
240
+ def secret_from_footprint footprint
241
+ @keystore.secret_from_footprint footprint
242
+ end
243
+
151
244
  def sync
152
245
  @git.pull
153
246
  @keystore.sync
data/lib/leeloo/output.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require 'clipboard'
2
2
  require 'tty-table'
3
3
  require 'tty-tree'
4
+ require 'json'
5
+ require 'base64'
6
+ require 'socket'
4
7
 
5
8
  module Leeloo
6
9
 
@@ -15,7 +18,19 @@ module Leeloo
15
18
  def render_secret secret
16
19
  end
17
20
 
18
- def render_translate keystore, text
21
+ def render_text text
22
+ end
23
+
24
+ def render_name_and_secret name, secret
25
+ end
26
+
27
+ def render_keys keys
28
+ end
29
+
30
+ def render_footprint footprint
31
+ end
32
+
33
+ def render_share footprint
19
34
  end
20
35
  end
21
36
 
@@ -37,16 +52,24 @@ module Leeloo
37
52
  end
38
53
  end
39
54
 
40
- def render_translate keystore, text
41
- text.scan(/\$\{.*\}/).each do |secret|
42
- begin
43
- text.gsub! secret, (keystore.secret_from_name(secret[2..-2])).read.to_s.strip
44
- rescue => exception
45
- # silent
46
- end
47
- end
55
+ def render_name_and_secret name, secret
56
+ self.render_text name
57
+ self.render_secret secret
58
+ self.render_text '------'
59
+ end
60
+
61
+ def render_text text
48
62
  puts text
49
63
  end
64
+
65
+ def render_keys keys
66
+ self.render_text keys
67
+ end
68
+
69
+ def render_footprint footprint
70
+ puts "token:"
71
+ puts Base64.strict_encode64 footprint.to_json
72
+ end
50
73
  end
51
74
 
52
75
  class Terminal < Ascii
@@ -62,11 +85,21 @@ module Leeloo
62
85
  end
63
86
 
64
87
  def render_secrets secrets
65
- hash = {:secrets => []}
66
- secrets.sort_by(&:name).each { |secret| sort(hash[:secrets], secret.name) }
88
+ hash = {'Password Store' => []}
89
+ secrets.sort_by(&:name).each { |secret| sort(hash['Password Store'], secret.name) }
67
90
  puts TTY::Tree.new(hash).render
68
91
  end
69
92
 
93
+ def render_keys keys
94
+ rows = []
95
+ keys.each do |key|
96
+ splitted = key.split('::')
97
+ is_present = '*' if splitted[1] == 'true'
98
+ rows << [splitted[0], is_present]
99
+ end
100
+ puts TTY::Table.new(header: ['Email', 'Selected'], rows: rows).render(:ascii)
101
+ end
102
+
70
103
  def sort array, element
71
104
  if element
72
105
  e = element.split("/", 2)
@@ -107,16 +140,16 @@ module Leeloo
107
140
  @output.render_secrets secrets
108
141
  end
109
142
 
110
- def render_translate keystore, text
111
- @output.render_translate keystore, text
143
+ def render_text text
144
+ @output.render_text text
112
145
  end
113
146
 
114
147
  def render_secret secret
115
148
 
116
149
  Signal.trap("INT") do
117
150
  Clipboard.clear
118
- abort "ciao"
119
- end
151
+ abort "cleared"
152
+ end
120
153
 
121
154
  Clipboard.copy secret.read
122
155
  wait = Thread.new do
@@ -129,6 +162,14 @@ module Leeloo
129
162
  wait.join
130
163
  Clipboard.clear
131
164
  end
165
+
166
+ def render_footprint footprint
167
+ @output.render_footprint footprint
168
+ end
169
+
170
+ def render_share footprint
171
+ @output.render_share footprint
172
+ end
132
173
  end
133
174
 
134
175
  end
@@ -32,6 +32,14 @@ module Leeloo
32
32
  @keystores << keystore
33
33
  end
34
34
  end
35
+
36
+ def remove_keystore name
37
+ abort "you can not remove default keystore" if name == @default
38
+ keystore = @keystores.find { |k| k["name"] == name }
39
+ if keystore != nil
40
+ @keystores.delete keystore
41
+ end
42
+ end
35
43
  end
36
44
 
37
45
  class PrivateLocalFileSystemPreferences < Preferences
@@ -63,8 +71,8 @@ module Leeloo
63
71
  self
64
72
  end
65
73
 
66
- def keystore_of keystore_name
67
- keystore = @keystores.find { |keystore| keystore["name"] == keystore_name }
74
+ def keystore_of name
75
+ keystore = @keystores.find { |keystore| keystore["name"] == name }
68
76
  KeystoreFactory::create keystore
69
77
  end
70
78
 
@@ -82,6 +90,11 @@ module Leeloo
82
90
  File.write("#{@path}/keystores", @keystores.to_yaml)
83
91
  end
84
92
 
93
+ def remove_keystore name
94
+ super name
95
+ File.write("#{@path}/keystores", @keystores.to_yaml)
96
+ end
97
+
85
98
  end
86
99
 
87
100
  end
data/lib/leeloo/secret.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'gpgme'
2
2
  require 'fileutils'
3
+ require 'digest'
3
4
 
4
5
  module Leeloo
5
6
  class Secret
@@ -26,6 +27,9 @@ module Leeloo
26
27
  # erase the secret
27
28
  end
28
29
 
30
+ def footprint
31
+ # a footprint is a token proving the authenticity of a secret
32
+ end
29
33
  end
30
34
 
31
35
  class LocalFileSystemSecret < Secret
@@ -50,6 +54,13 @@ module Leeloo
50
54
  File.delete @pathname
51
55
  end
52
56
 
57
+ def footprint
58
+ secret = File.read @pathname
59
+ md5 = Digest::MD5.new
60
+ md5 << secret
61
+ md5.hexdigest
62
+ end
63
+
53
64
  end
54
65
 
55
66
  class GpgLocalFileSystemSecret < LocalFileSystemSecret
@@ -88,6 +99,10 @@ module Leeloo
88
99
  @secret.read
89
100
  end
90
101
 
102
+ def footprint
103
+ @secret.footprint
104
+ end
105
+
91
106
  def write phrase
92
107
  @secret.write phrase
93
108
  @git.add @secret.pathname
@@ -0,0 +1,37 @@
1
+ require 'webrick'
2
+ require 'json'
3
+ require 'base64'
4
+
5
+ class Server
6
+
7
+ def start preferences
8
+
9
+ puts """
10
+ Please share this url :
11
+ http://your_ip:8000\?q=YOUR_TOKEN
12
+
13
+ run ssh -R:localhost:8000 ssh.localhost.run
14
+ if you want to share your password through tunneling
15
+ """
16
+
17
+ server = WEBrick::HTTPServer.new :Port => 8000
18
+ server.mount_proc '/' do |req, res|
19
+ query = req.query()["q"] || req.body()
20
+ if query
21
+ begin
22
+ body = JSON.parse(Base64.strict_decode64 query)
23
+ key = body["body"] ? JSON.parse(body["body"]) : body
24
+ res.body = preferences.keystore(key["keystore"]).secret_from_footprint(key).read.to_s
25
+ rescue => exception
26
+ puts exception
27
+ res.status = 400
28
+ end
29
+ else
30
+ res.status = 400
31
+ end
32
+ end
33
+
34
+ trap 'INT' do server.shutdown end
35
+ server.start
36
+ end
37
+ end
@@ -1,4 +1,4 @@
1
1
  module Leeloo
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '0.5.0'.freeze
3
3
  DESCRIPTION = "The easiest way to share securely your secrets".freeze
4
4
  end
data/lib/leeloo.rb CHANGED
@@ -1,9 +1,11 @@
1
1
  require 'leeloo/version'
2
+ require 'leeloo/controller'
2
3
  require 'leeloo/command'
3
4
  require 'leeloo/preferences'
4
5
  require 'leeloo/keystore'
5
6
  require 'leeloo/secret'
6
7
  require 'leeloo/output'
8
+ require 'leeloo/server'
7
9
 
8
10
  module Leeloo
9
11
  def self.start
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leeloo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
- - Sylvek
8
- autorequire:
7
+ - sylvek
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-30 00:00:00.000000000 Z
11
+ date: 2021-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: commander
@@ -94,20 +94,34 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webrick
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.7'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.7'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: bundler
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: '2.0'
117
+ version: '2'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
- version: '2.0'
124
+ version: '2'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: rake
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -136,6 +150,20 @@ dependencies:
136
150
  - - "~>"
137
151
  - !ruby/object:Gem::Version
138
152
  version: '3.0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rspec_junit_formatter
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.4'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.4'
139
167
  description: The easiest way to share securely your secrets
140
168
  email:
141
169
  - smaucourt@gmail.com
@@ -147,16 +175,18 @@ files:
147
175
  - exe/leeloo
148
176
  - lib/leeloo.rb
149
177
  - lib/leeloo/command.rb
178
+ - lib/leeloo/controller.rb
150
179
  - lib/leeloo/keystore.rb
151
180
  - lib/leeloo/output.rb
152
181
  - lib/leeloo/preferences.rb
153
182
  - lib/leeloo/secret.rb
183
+ - lib/leeloo/server.rb
154
184
  - lib/leeloo/version.rb
155
- homepage: https://github.com/sylvek
185
+ homepage: https://github.com/sylvek/leeloo
156
186
  licenses:
157
187
  - MIT
158
188
  metadata: {}
159
- post_install_message:
189
+ post_install_message:
160
190
  rdoc_options: []
161
191
  require_paths:
162
192
  - lib
@@ -171,8 +201,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
201
  - !ruby/object:Gem::Version
172
202
  version: '0'
173
203
  requirements: []
174
- rubygems_version: 3.0.4
175
- signing_key:
204
+ rubygems_version: 3.2.32
205
+ signing_key:
176
206
  specification_version: 4
177
207
  summary: The easiest way to share securely your secrets
178
208
  test_files: []