leeloo 0.4.1 → 0.5.3
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/leeloo/command.rb +113 -9
- data/lib/leeloo/controller.rb +33 -3
- data/lib/leeloo/keystore.rb +51 -1
- data/lib/leeloo/output.rb +28 -2
- data/lib/leeloo/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 970efe43f2eb851d19e0b84eae77acb8aad964e6cb52f12e99a4acab4403d32c
|
4
|
+
data.tar.gz: 784fbd32ee2a217ddf86e3321beb9ac73d0924438cb4074834f2306490b4de12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9cbe579613ee7f78367e4a513aed089709282c1d11fafc3a2288a56671cecf1436062f5bdae8c409a0fef5e98655c805b8cf0d881a02ce63003fe822a6a2b76f
|
7
|
+
data.tar.gz: 8b20416ae3a71911bb0deabd0c8ab11ae8bf80bd314ee2e73eb8ada3cdb4e4d67d0d5ac59f5e03d7ad697ca75a858731e304da07b307f51e8e742e5d79ed5e7f
|
data/lib/leeloo/command.rb
CHANGED
@@ -23,11 +23,34 @@ module Leeloo
|
|
23
23
|
program :help, 'GitHub', 'https://github.com/sylvek'
|
24
24
|
program :help_formatter, :compact
|
25
25
|
|
26
|
-
default_command :
|
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
|
45
|
+
|
46
|
+
command :init do |c|
|
47
|
+
c.syntax = 'leeloo init'
|
48
|
+
c.description = "Just to be compatible with passwordstore.org"
|
49
|
+
end
|
27
50
|
|
28
51
|
command :list do |c|
|
29
52
|
c.syntax = 'leeloo list [options]'
|
30
|
-
c.description = "Display secrets list of keystore"
|
53
|
+
c.description = "Display secrets list of stored on a keystore"
|
31
54
|
c.option '--ascii', nil, 'display secrets without unicode tree'
|
32
55
|
c.option '--keystore STRING', String, 'a selected keystore'
|
33
56
|
|
@@ -61,7 +84,7 @@ module Leeloo
|
|
61
84
|
end
|
62
85
|
end
|
63
86
|
|
64
|
-
command "keystore remove" do |c|
|
87
|
+
command :"keystore remove" do |c|
|
65
88
|
c.syntax = 'leeloo keystore remove <name>'
|
66
89
|
c.description = "remove a keystore (path/to/keystore is not destroyed)"
|
67
90
|
|
@@ -74,7 +97,7 @@ module Leeloo
|
|
74
97
|
end
|
75
98
|
end
|
76
99
|
|
77
|
-
command "keystore add" do |c|
|
100
|
+
command :"keystore add" do |c|
|
78
101
|
c.syntax = 'leeloo keystore add <name> <path/to/keystore>'
|
79
102
|
c.description = "add a keystore"
|
80
103
|
|
@@ -88,7 +111,7 @@ module Leeloo
|
|
88
111
|
end
|
89
112
|
end
|
90
113
|
|
91
|
-
command "keystore default" do |c|
|
114
|
+
command :"keystore default" do |c|
|
92
115
|
c.syntax = 'leeloo keystore default name'
|
93
116
|
c.description = "set the default keystore"
|
94
117
|
|
@@ -101,12 +124,63 @@ module Leeloo
|
|
101
124
|
end
|
102
125
|
end
|
103
126
|
|
127
|
+
command :key do |c|
|
128
|
+
c.syntax = 'leeloo keys'
|
129
|
+
c.description = "list keys from this keystore"
|
130
|
+
c.option '--ascii', nil, 'display secrets without unicode tree'
|
131
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
132
|
+
|
133
|
+
c.action do |args, options|
|
134
|
+
ctl = KeysController.new(options)
|
135
|
+
ctl.display
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
command :"key sync" do |c|
|
140
|
+
c.syntax = 'leeloo keys sync'
|
141
|
+
c.description = "synchronize secrets with keys"
|
142
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
143
|
+
|
144
|
+
c.action do |args, options|
|
145
|
+
ctl = KeysController.new(options)
|
146
|
+
ctl.sync
|
147
|
+
ctl.display
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
command :"key add" do |c|
|
152
|
+
c.syntax = 'leeloo key add <email>'
|
153
|
+
c.description = "add a dedicated key"
|
154
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
155
|
+
|
156
|
+
c.action do |args, options|
|
157
|
+
abort "email is missing" unless args.length == 1
|
158
|
+
email = args.first
|
159
|
+
ctl = KeysController.new(options)
|
160
|
+
ctl.add_key(email)
|
161
|
+
ctl.display
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
command :"key remove" do |c|
|
166
|
+
c.syntax = 'leeloo key remove <email>'
|
167
|
+
c.description = "remove a dedicated key"
|
168
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
169
|
+
|
170
|
+
c.action do |args, options|
|
171
|
+
abort "email is missing" unless args.length == 1
|
172
|
+
email = args.first
|
173
|
+
ctl = KeysController.new(options)
|
174
|
+
ctl.remove_key(email)
|
175
|
+
ctl.display
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
104
179
|
command :read do |c|
|
105
180
|
c.syntax = 'leeloo read <name>'
|
106
181
|
c.description = "Display a secret from a keystore"
|
107
182
|
c.option '--keystore STRING', String, 'a selected keystore'
|
108
183
|
c.option '--clipboard', nil, 'copy to clipboard'
|
109
|
-
c.option '--keystore STRING', String, 'a selected keystore'
|
110
184
|
|
111
185
|
c.action do |args, options|
|
112
186
|
abort "name is missing" unless args.length == 1
|
@@ -133,6 +207,23 @@ module Leeloo
|
|
133
207
|
ctl.display
|
134
208
|
end
|
135
209
|
end
|
210
|
+
alias_command :insert, :write
|
211
|
+
|
212
|
+
command :generate do |c|
|
213
|
+
c.syntax = 'leeloo generate <name> <number of randomized characters>'
|
214
|
+
c.description = "Generate a secret from a keystore"
|
215
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
216
|
+
c.option '--clipboard', nil, 'copy to clipboard'
|
217
|
+
|
218
|
+
c.action do |args, options|
|
219
|
+
abort "name or number are missing" unless args.length == 2
|
220
|
+
name = args.first
|
221
|
+
options.__hash__[:generate] = args.last.to_i
|
222
|
+
ctl = SecretController.new(options)
|
223
|
+
ctl.write(name)
|
224
|
+
ctl.display
|
225
|
+
end
|
226
|
+
end
|
136
227
|
|
137
228
|
command :translate do |c|
|
138
229
|
c.syntax = 'leeloo translate'
|
@@ -156,11 +247,13 @@ module Leeloo
|
|
156
247
|
name = args.first
|
157
248
|
ctl = SecretController.new(options)
|
158
249
|
ctl.remove(name)
|
159
|
-
ctl.display
|
250
|
+
#ctl.display
|
251
|
+
puts "done."
|
160
252
|
end
|
161
253
|
end
|
254
|
+
alias_command :rm, :remove
|
162
255
|
|
163
|
-
command :sync do |c|
|
256
|
+
command :"keystore sync" do |c|
|
164
257
|
c.syntax = 'leeloo sync'
|
165
258
|
c.description = "Synchronize a keystore"
|
166
259
|
c.option '--keystore STRING', String, 'a selected keystore'
|
@@ -172,7 +265,18 @@ module Leeloo
|
|
172
265
|
end
|
173
266
|
end
|
174
267
|
|
175
|
-
command :
|
268
|
+
command :"keystore export" do |c|
|
269
|
+
c.syntax = 'leeloo export'
|
270
|
+
c.description = "Export all secrets from a keystore"
|
271
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
272
|
+
|
273
|
+
c.action do |args, options|
|
274
|
+
ctl = ExportController.new(options)
|
275
|
+
ctl.display
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
command :"keystore init" do |c|
|
176
280
|
c.syntax = 'leeloo init'
|
177
281
|
c.description = "Initialize a keystore"
|
178
282
|
c.option '--keystore STRING', String, 'a selected keystore'
|
data/lib/leeloo/controller.rb
CHANGED
@@ -32,16 +32,46 @@ module Leeloo
|
|
32
32
|
class SecretsController < PrivateLocalFileSystemController
|
33
33
|
def initialize options
|
34
34
|
super options
|
35
|
-
@secrets = @
|
35
|
+
@secrets = @keystore.secrets
|
36
36
|
end
|
37
37
|
def search name
|
38
38
|
@secrets = @secrets.select { |secret| secret.name.downcase.include? name.downcase } || []
|
39
39
|
end
|
40
|
+
def list
|
41
|
+
@secrets
|
42
|
+
end
|
40
43
|
def display
|
41
44
|
@output.render_secrets @secrets
|
42
45
|
end
|
43
46
|
end
|
44
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
|
+
|
45
75
|
class SecretController < PrivateLocalFileSystemController
|
46
76
|
def read name
|
47
77
|
@secret = @keystore.secret_from_name(name)
|
@@ -53,8 +83,8 @@ module Leeloo
|
|
53
83
|
phrase = SecureRandom.base64(32).truncate(@options.generate.to_i) if @options.generate
|
54
84
|
|
55
85
|
unless phrase
|
56
|
-
phrase = password "
|
57
|
-
confirm = password "
|
86
|
+
phrase = password "Enter password for #{name}"
|
87
|
+
confirm = password "Confirm it"
|
58
88
|
abort "not the same secret" unless phrase == confirm
|
59
89
|
end
|
60
90
|
|
data/lib/leeloo/keystore.rb
CHANGED
@@ -72,6 +72,7 @@ module Leeloo
|
|
72
72
|
def initialize name, path
|
73
73
|
super name
|
74
74
|
@path = path
|
75
|
+
File.write("#{@path}/.gpg-id", 'empty')
|
75
76
|
FileUtils.mkdir_p "#{@path}/secrets"
|
76
77
|
end
|
77
78
|
|
@@ -79,6 +80,10 @@ module Leeloo
|
|
79
80
|
find_secrets "#{@path}/secrets"
|
80
81
|
end
|
81
82
|
|
83
|
+
def keys
|
84
|
+
[]
|
85
|
+
end
|
86
|
+
|
82
87
|
def find_secrets path
|
83
88
|
elements = []
|
84
89
|
Dir.glob("#{path}/**") do |element|
|
@@ -121,7 +126,10 @@ module Leeloo
|
|
121
126
|
def initialize name, path
|
122
127
|
super name, path
|
123
128
|
FileUtils.mkdir_p "#{@path}/keys"
|
129
|
+
populate_recipients
|
130
|
+
end
|
124
131
|
|
132
|
+
def populate_recipients
|
125
133
|
@recipients = []
|
126
134
|
Dir.glob("#{path}/keys/*") { |key| @recipients << File.basename(key) }
|
127
135
|
@recipients.each { |key| GPGME::Key.import(File.open("#{path}/keys/#{key}")) }
|
@@ -129,7 +137,30 @@ module Leeloo
|
|
129
137
|
|
130
138
|
def init
|
131
139
|
super
|
132
|
-
|
140
|
+
File.write("#{@path}/keys/do_not_remove_me", "do not remove me")
|
141
|
+
end
|
142
|
+
|
143
|
+
def keys
|
144
|
+
available = GPGME::Key.find(:public, nil, ).map { |key| key.email }
|
145
|
+
actual = Dir.glob("#{@path}/keys/**").map { |path| path.split('/').last }
|
146
|
+
available.map { |email| actual.include?(email) ? "#{email}::true" : "#{email}::false" }
|
147
|
+
end
|
148
|
+
|
149
|
+
def add_key email
|
150
|
+
paths = []
|
151
|
+
GPGME::Key.find(:public, email).each do |key|
|
152
|
+
key.export(:output => File.open("#{path}/keys/#{key.uids.first.email}", "w+"))
|
153
|
+
paths << "#{path}/keys/#{key.uids.first.email}"
|
154
|
+
end
|
155
|
+
return paths
|
156
|
+
end
|
157
|
+
|
158
|
+
def remove_key email
|
159
|
+
if File.exist?("#{path}/keys/#{email}")
|
160
|
+
File.delete("#{path}/keys/#{email}")
|
161
|
+
return "#{path}/keys/#{email}"
|
162
|
+
end
|
163
|
+
return nil
|
133
164
|
end
|
134
165
|
|
135
166
|
def secret_of path
|
@@ -172,6 +203,25 @@ module Leeloo
|
|
172
203
|
secret_of @keystore.secret_from_name(element)
|
173
204
|
end
|
174
205
|
|
206
|
+
def keys
|
207
|
+
@keystore.keys
|
208
|
+
end
|
209
|
+
|
210
|
+
def add_key email
|
211
|
+
@keystore.add_key(email).each do |path|
|
212
|
+
@git.add path
|
213
|
+
@git.commit "#{email} added"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def remove_key email
|
218
|
+
deleted = @keystore.remove_key email
|
219
|
+
if deleted
|
220
|
+
@git.add deleted
|
221
|
+
@git.commit "#{email} removed"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
175
225
|
def secrets
|
176
226
|
@keystore.secrets
|
177
227
|
end
|
data/lib/leeloo/output.rb
CHANGED
@@ -21,6 +21,12 @@ module Leeloo
|
|
21
21
|
def render_text text
|
22
22
|
end
|
23
23
|
|
24
|
+
def render_name_and_secret name, secret
|
25
|
+
end
|
26
|
+
|
27
|
+
def render_keys keys
|
28
|
+
end
|
29
|
+
|
24
30
|
def render_footprint footprint
|
25
31
|
end
|
26
32
|
|
@@ -46,10 +52,20 @@ module Leeloo
|
|
46
52
|
end
|
47
53
|
end
|
48
54
|
|
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
|
+
|
49
61
|
def render_text text
|
50
62
|
puts text
|
51
63
|
end
|
52
64
|
|
65
|
+
def render_keys keys
|
66
|
+
self.render_text keys
|
67
|
+
end
|
68
|
+
|
53
69
|
def render_footprint footprint
|
54
70
|
puts "token:"
|
55
71
|
puts Base64.strict_encode64 footprint.to_json
|
@@ -69,11 +85,21 @@ module Leeloo
|
|
69
85
|
end
|
70
86
|
|
71
87
|
def render_secrets secrets
|
72
|
-
hash = {
|
73
|
-
secrets.sort_by(&:name).each { |secret| sort(hash[
|
88
|
+
hash = {'Password Store' => []}
|
89
|
+
secrets.sort_by(&:name).each { |secret| sort(hash['Password Store'], secret.name) }
|
74
90
|
puts TTY::Tree.new(hash).render
|
75
91
|
end
|
76
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
|
+
|
77
103
|
def sort array, element
|
78
104
|
if element
|
79
105
|
e = element.split("/", 2)
|
data/lib/leeloo/version.rb
CHANGED
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.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sylvek
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: commander
|
@@ -201,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
201
201
|
- !ruby/object:Gem::Version
|
202
202
|
version: '0'
|
203
203
|
requirements: []
|
204
|
-
rubygems_version: 3.
|
204
|
+
rubygems_version: 3.3.3
|
205
205
|
signing_key:
|
206
206
|
specification_version: 4
|
207
207
|
summary: The easiest way to share securely your secrets
|