leeloo 0.3.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f395de66b0d5e6550921e66339d5dcd2df759bc38662d09b4bc650a510cb4dd8
4
- data.tar.gz: 9b311918a29972cd5bca9dc0c856bf37e8bacf59db8b6b954ff1ebd5d4790eeb
3
+ metadata.gz: 236ca14fba0124365c37165ecd103e9342bc8c981ef4ed23bbf4afb73752e7b4
4
+ data.tar.gz: 53d104d94f393fb44e2532f7e59b91164461b14710d504b71730d5a8e549c8d9
5
5
  SHA512:
6
- metadata.gz: 36703d60d92d086540d33d16171d1aa290595f4d408db707ac22fdeb11077f8d393ffd861c25aaafa331441586b27b98a8b4f16ac33f61da654c6e27b992ff3f
7
- data.tar.gz: dde8201181fbfb863f091accb97bd2fea285e1cdb7bc75c7ec94ee2c9ce4c1783b8b0c55d593b55b5446506c3826862f32d989657a64873205d4052dbba2ea1b
6
+ metadata.gz: 82d0d1f608c8adece27b0ff8e40c6eb01a953b1d46cdc3e28f7bfa86031a73b4989f11c9519491b6a9c1db7b3a05bd8d15f32ddb3b42aad805652fd459bb115a
7
+ data.tar.gz: 12b643a433090504e471723ed2aa519c4aee77f5fb70151a9766f78a7f62b52b6db909b6c377a3cb4762fb2959b93ea5715fbe42887e782353cc68f4a0674aca
@@ -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,34 @@ 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.syntax = 'leeloo [options]'
30
+ c.description = "Display secrets"
31
+ c.option '--ascii', nil, 'display secrets without unicode tree'
32
+ c.option '--keystore STRING', String, 'a selected keystore'
33
+ c.option '--clipboard', nil, 'copy to clipboard'
34
+ c.action do |args, options|
35
+ unless args == []
36
+ name = args.first
37
+ ctl = SecretController.new(options)
38
+ ctl.read(name)
39
+ ctl.display
40
+ else
41
+ SecretsController.new(options).display
42
+ end
43
+ end
44
+ end
47
45
 
48
46
  command :list do |c|
49
47
  c.syntax = 'leeloo list [options]'
50
- c.description = "Display secrets list of keystore"
48
+ c.description = "Display secrets list of stored on a keystore"
51
49
  c.option '--ascii', nil, 'display secrets without unicode tree'
52
50
  c.option '--keystore STRING', String, 'a selected keystore'
53
51
 
54
52
  c.action do |args, options|
55
- keystore = @preferences.keystore(options.keystore)
56
- OutputFactory.create(options).render_secrets keystore.secrets
53
+ SecretsController.new(options).display
57
54
  end
58
55
  end
59
56
 
@@ -66,10 +63,9 @@ module Leeloo
66
63
  c.action do |args, options|
67
64
  abort "name is missing" unless args.length == 1
68
65
  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
66
+ ctl = SecretsController.new(options)
67
+ ctl.search(name)
68
+ ctl.display
73
69
  end
74
70
  end
75
71
 
@@ -79,7 +75,7 @@ module Leeloo
79
75
  c.option '--ascii', nil, 'display secrets without unicode tree'
80
76
 
81
77
  c.action do |args, options|
82
- OutputFactory.create(options).render_preferences @preferences
78
+ KeystoreController.new(options).display
83
79
  end
84
80
  end
85
81
 
@@ -87,10 +83,12 @@ module Leeloo
87
83
  c.syntax = 'leeloo keystore remove <name>'
88
84
  c.description = "remove a keystore (path/to/keystore is not destroyed)"
89
85
 
90
- c.action do |args, options|
86
+ c.action do |args, options|args
91
87
  abort "name is missing" unless args.length == 1
92
- @preferences.remove_keystore args.first
93
- OutputFactory.create(options).render_preferences @preferences
88
+ name = args.first
89
+ ctl = KeystoreController.new(options)
90
+ ctl.remove(name)
91
+ ctl.display
94
92
  end
95
93
  end
96
94
 
@@ -100,10 +98,11 @@ module Leeloo
100
98
 
101
99
  c.action do |args, options|
102
100
  abort "name or path is missing" unless args.length == 2
103
-
104
- @preferences.add_keystore({"name" => args.first, "path" => args.last, "cypher" => "gpg", "vc" => "git"})
105
- @preferences.keystore(args.first).init
106
- OutputFactory.create(options).render_preferences @preferences
101
+ name = args.first
102
+ path = args.last
103
+ ctl = KeystoreController.new(options)
104
+ ctl.add(name, path)
105
+ ctl.display
107
106
  end
108
107
  end
109
108
 
@@ -113,9 +112,62 @@ module Leeloo
113
112
 
114
113
  c.action do |args, options|
115
114
  abort "name is missing" unless args.length == 1
115
+ name = args.first
116
+ ctl = KeystoreController.new(options)
117
+ ctl.set_default(name)
118
+ ctl.display
119
+ end
120
+ end
121
+
122
+ command :key do |c|
123
+ c.syntax = 'leeloo keys'
124
+ c.description = "list keys from this keystore"
125
+ c.option '--ascii', nil, 'display secrets without unicode tree'
126
+ c.option '--keystore STRING', String, 'a selected keystore'
127
+
128
+ c.action do |args, options|
129
+ ctl = KeysController.new(options)
130
+ ctl.display
131
+ end
132
+ end
133
+
134
+ command "key sync" do |c|
135
+ c.syntax = 'leeloo keys sync'
136
+ c.description = "synchronize secrets with keys"
137
+ c.option '--keystore STRING', String, 'a selected keystore'
138
+
139
+ c.action do |args, options|
140
+ ctl = KeysController.new(options)
141
+ ctl.sync
142
+ ctl.display
143
+ end
144
+ end
116
145
 
117
- @preferences.set_default_keystore args.first
118
- OutputFactory.create(options).render_preferences @preferences
146
+ command "key add" do |c|
147
+ c.syntax = 'leeloo key add <email>'
148
+ c.description = "add a dedicated key"
149
+ c.option '--keystore STRING', String, 'a selected keystore'
150
+
151
+ c.action do |args, options|
152
+ abort "email is missing" unless args.length == 1
153
+ email = args.first
154
+ ctl = KeysController.new(options)
155
+ ctl.add_key(email)
156
+ ctl.display
157
+ end
158
+ end
159
+
160
+ command "key remove" do |c|
161
+ c.syntax = 'leeloo key remove <email>'
162
+ c.description = "remove a dedicated key"
163
+ c.option '--keystore STRING', String, 'a selected keystore'
164
+
165
+ c.action do |args, options|
166
+ abort "email is missing" unless args.length == 1
167
+ email = args.first
168
+ ctl = KeysController.new(options)
169
+ ctl.remove_key(email)
170
+ ctl.display
119
171
  end
120
172
  end
121
173
 
@@ -124,15 +176,13 @@ module Leeloo
124
176
  c.description = "Display a secret from a keystore"
125
177
  c.option '--keystore STRING', String, 'a selected keystore'
126
178
  c.option '--clipboard', nil, 'copy to clipboard'
127
- c.option '--keystore STRING', String, 'a selected keystore'
128
179
 
129
180
  c.action do |args, options|
130
181
  abort "name is missing" unless args.length == 1
131
182
  name = args.first
132
-
133
- keystore = @preferences.keystore(options.keystore)
134
- secret = keystore.secret_from_name(name)
135
- OutputFactory.create(options).render_secret secret
183
+ ctl = SecretController.new(options)
184
+ ctl.read(name)
185
+ ctl.display
136
186
  end
137
187
  end
138
188
 
@@ -147,22 +197,9 @@ module Leeloo
147
197
  c.action do |args, options|
148
198
  abort "name is missing" unless args.length == 1
149
199
  name = args.first
150
- phrase = nil
151
-
152
- phrase = STDIN.read if options.stdin
153
- phrase = SecureRandom.base64(32).truncate(options.generate.to_i) if options.generate
154
-
155
- unless phrase
156
- phrase = password "secret"
157
- confirm = password "confirm it"
158
- abort "not the same secret" unless phrase == confirm
159
- end
160
-
161
- keystore = @preferences.keystore(options.keystore)
162
- secret = keystore.secret_from_name(name)
163
- secret.write(phrase)
164
-
165
- OutputFactory.create(options).render_secret secret
200
+ ctl = SecretController.new(options)
201
+ ctl.write(name)
202
+ ctl.display
166
203
  end
167
204
  end
168
205
 
@@ -172,9 +209,9 @@ module Leeloo
172
209
  c.option '--keystore STRING', String, 'a selected keystore'
173
210
 
174
211
  c.action do |args, options|
175
- keystore = @preferences.keystore(options.keystore)
176
- text = STDIN.read
177
- OutputFactory.create(options).render_translate keystore, text
212
+ ctl = TranslateController.new(options)
213
+ ctl.translate
214
+ ctl.display
178
215
  end
179
216
  end
180
217
 
@@ -186,32 +223,84 @@ module Leeloo
186
223
  c.action do |args, options|
187
224
  abort "name is missing" unless args.length == 1
188
225
  name = args.first
189
-
190
- keystore = @preferences.keystore(options.keystore)
191
- secret = keystore.secret_from_name(name)
192
- secret.erase
226
+ ctl = SecretController.new(options)
227
+ ctl.remove(name)
228
+ #ctl.display
229
+ puts "done."
193
230
  end
194
231
  end
195
232
 
196
- command :sync do |c|
233
+ command "keystore sync" do |c|
197
234
  c.syntax = 'leeloo sync'
198
235
  c.description = "Synchronize a keystore"
199
236
  c.option '--keystore STRING', String, 'a selected keystore'
200
237
 
201
238
  c.action do |args, options|
202
- keystore = @preferences.keystore(options.keystore)
203
- keystore.sync
239
+ ctl = KeystoreController.new(options)
240
+ ctl.sync
241
+ ctl.display
242
+ end
243
+ end
244
+
245
+ command "keystore export" do |c|
246
+ c.syntax = 'leeloo export'
247
+ c.description = "Export all secrets from a keystore"
248
+ c.option '--keystore STRING', String, 'a selected keystore'
249
+
250
+ c.action do |args, options|
251
+ ctl = ExportController.new(options)
252
+ ctl.display
204
253
  end
205
254
  end
206
255
 
207
- command :init do |c|
256
+ command "keystore init" do |c|
208
257
  c.syntax = 'leeloo init'
209
258
  c.description = "Initialize a keystore"
210
259
  c.option '--keystore STRING', String, 'a selected keystore'
211
260
 
212
261
  c.action do |args, options|
213
- keystore = @preferences.keystore(options.keystore)
214
- keystore.init
262
+ ctl = KeystoreController.new(options)
263
+ ctl.init
264
+ ctl.display
265
+ end
266
+ end
267
+
268
+ command :share do |c|
269
+ c.syntax = 'leeloo share <name>'
270
+ c.description = "share a secret with someone"
271
+ c.option '--keystore STRING', String, 'a selected keystore'
272
+
273
+ c.action do |args, options|
274
+ abort "name is missing" unless args.length == 1
275
+ name = args.first
276
+ ctl = ShareController.new(options)
277
+ ctl.token(name)
278
+ ctl.display
279
+ ctl.start_server
280
+ end
281
+ end
282
+
283
+ command :token do |c|
284
+ c.syntax = 'leeloo token <name>'
285
+ c.description = "generate an access token for a given secret"
286
+ c.option '--keystore STRING', String, 'a selected keystore'
287
+
288
+ c.action do |args, options|
289
+ abort "name is missing" unless args.length == 1
290
+ name = args.first
291
+ ctl = ShareController.new(options)
292
+ ctl.token(name)
293
+ ctl.display
294
+ end
295
+ end
296
+
297
+ command :server do |c|
298
+ c.syntax = 'leeloo server'
299
+ c.description = "start a server access token"
300
+
301
+ c.action do |args, options|
302
+ ctl = ShareController.new(options)
303
+ ctl.start_server
215
304
  end
216
305
  end
217
306
 
@@ -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
@@ -34,8 +34,9 @@ module Leeloo
34
34
  end
35
35
 
36
36
  def remove_keystore name
37
+ abort "you can not remove default keystore" if name == @default
37
38
  keystore = @keystores.find { |k| k["name"] == name }
38
- if keystore !=nil
39
+ if keystore != nil
39
40
  @keystores.delete keystore
40
41
  end
41
42
  end
@@ -70,8 +71,8 @@ module Leeloo
70
71
  self
71
72
  end
72
73
 
73
- def keystore_of keystore_name
74
- keystore = @keystores.find { |keystore| keystore["name"] == keystore_name }
74
+ def keystore_of name
75
+ keystore = @keystores.find { |keystore| keystore["name"] == name }
75
76
  KeystoreFactory::create keystore
76
77
  end
77
78
 
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.3.0'.freeze
2
+ VERSION = '0.5.1'.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.3.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - sylvek
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-09-15 00:00:00.000000000 Z
11
+ date: 2022-02-18 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
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.3.3
205
+ signing_key:
176
206
  specification_version: 4
177
207
  summary: The easiest way to share securely your secrets
178
208
  test_files: []