leeloo 0.0.16 → 0.4.1
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.rb +5 -3
- data/lib/leeloo/command.rb +127 -120
- data/lib/leeloo/controller.rb +122 -0
- data/lib/leeloo/keystore.rb +188 -21
- data/lib/leeloo/output.rb +149 -0
- data/lib/leeloo/preferences.rb +100 -0
- data/lib/leeloo/secret.rb +93 -57
- data/lib/leeloo/server.rb +37 -0
- data/lib/leeloo/version.rb +1 -1
- metadata +40 -24
- data/lib/leeloo/config.rb +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7117e8aaf24a2b7dec0e8d516f81aa6491b9d1e8360907d99e1f41848fdeae87
|
4
|
+
data.tar.gz: e687c77e4e8a17f9bbe9ece480da789c80327f1d6bc8831da04ddd1a7b0d677a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8690b0dd0e1e8788332c30ae6c54a144749aba2b04574ddaabfd3336b5fbf1a3b289943d3b8ec098ec07d139c73ff0095667c2cfc7588c9eeef60a5807d72754
|
7
|
+
data.tar.gz: 5e5f54a09b03a45e9b574adbad70268d1aec1cdc4fbc7adf0228798a115130bbddd88ca560cf70c54fb6960dc0d719be86513b5d01acb6f36f8e5d0724abcf18
|
data/lib/leeloo.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'leeloo/version'
|
2
|
+
require 'leeloo/controller'
|
2
3
|
require 'leeloo/command'
|
3
|
-
require 'leeloo/
|
4
|
+
require 'leeloo/preferences'
|
4
5
|
require 'leeloo/keystore'
|
5
|
-
require 'leeloo/
|
6
|
+
require 'leeloo/secret'
|
7
|
+
require 'leeloo/output'
|
8
|
+
require 'leeloo/server'
|
6
9
|
|
7
10
|
module Leeloo
|
8
11
|
def self.start
|
9
|
-
Config.load
|
10
12
|
Command.new.run
|
11
13
|
end
|
12
14
|
end
|
data/lib/leeloo/command.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'commander/import'
|
2
2
|
require 'securerandom'
|
3
|
-
require 'clipboard'
|
4
|
-
|
5
3
|
|
6
4
|
class String
|
7
5
|
def truncate(max)
|
@@ -27,106 +25,101 @@ module Leeloo
|
|
27
25
|
|
28
26
|
default_command :"list"
|
29
27
|
|
30
|
-
command :
|
31
|
-
c.syntax = 'leeloo
|
32
|
-
c.description = "
|
28
|
+
command :list do |c|
|
29
|
+
c.syntax = 'leeloo list [options]'
|
30
|
+
c.description = "Display secrets list of keystore"
|
31
|
+
c.option '--ascii', nil, 'display secrets without unicode tree'
|
32
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
33
|
+
|
33
34
|
c.action do |args, options|
|
34
|
-
|
35
|
-
Config::init
|
36
|
-
say "Initialization completed"
|
35
|
+
SecretsController.new(options).display
|
37
36
|
end
|
38
37
|
end
|
39
38
|
|
40
|
-
command :
|
41
|
-
c.syntax = 'leeloo
|
42
|
-
c.description = "Display
|
39
|
+
command :search do |c|
|
40
|
+
c.syntax = 'leeloo search name'
|
41
|
+
c.description = "Display secrets containing name pattern"
|
43
42
|
c.option '--ascii', nil, 'display secrets without unicode tree'
|
43
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
44
44
|
|
45
45
|
c.action do |args, options|
|
46
|
-
|
47
|
-
|
46
|
+
abort "name is missing" unless args.length == 1
|
47
|
+
name = args.first
|
48
|
+
ctl = SecretsController.new(options)
|
49
|
+
ctl.search(name)
|
50
|
+
ctl.display
|
48
51
|
end
|
49
52
|
end
|
50
|
-
alias_command :keystore, :"list-keystore"
|
51
53
|
|
52
|
-
command :
|
53
|
-
c.syntax = 'leeloo
|
54
|
-
c.description = "Display
|
55
|
-
c.option '--keystore STRING', String, 'a selected keystore'
|
54
|
+
command :keystore do |c|
|
55
|
+
c.syntax = 'leeloo keystores'
|
56
|
+
c.description = "Display current keystores"
|
56
57
|
c.option '--ascii', nil, 'display secrets without unicode tree'
|
57
58
|
|
58
59
|
c.action do |args, options|
|
59
|
-
options.
|
60
|
-
|
61
|
-
Secret::list Config.get_keystore(options.keystore), options.ascii
|
60
|
+
KeystoreController.new(options).display
|
62
61
|
end
|
63
62
|
end
|
64
|
-
alias_command :list, :"list-secret"
|
65
|
-
alias_command :secrets, :"list-secret"
|
66
63
|
|
67
|
-
command
|
68
|
-
c.syntax = 'leeloo
|
69
|
-
c.description = "
|
64
|
+
command "keystore remove" do |c|
|
65
|
+
c.syntax = 'leeloo keystore remove <name>'
|
66
|
+
c.description = "remove a keystore (path/to/keystore is not destroyed)"
|
70
67
|
|
71
|
-
c.action do |args, options|
|
72
|
-
|
73
|
-
abort "name or path are missing" unless args.length == 2
|
68
|
+
c.action do |args, options|args
|
69
|
+
abort "name is missing" unless args.length == 1
|
74
70
|
name = args.first
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
Config.add_keystore name, keystore
|
79
|
-
say "keystore #{name} added"
|
71
|
+
ctl = KeystoreController.new(options)
|
72
|
+
ctl.remove(name)
|
73
|
+
ctl.display
|
80
74
|
end
|
81
75
|
end
|
82
76
|
|
83
|
-
command
|
84
|
-
c.syntax =
|
85
|
-
c.description = "add a
|
86
|
-
c.option '--keystore STRING', String, 'a selected keystore'
|
77
|
+
command "keystore add" do |c|
|
78
|
+
c.syntax = 'leeloo keystore add <name> <path/to/keystore>'
|
79
|
+
c.description = "add a keystore"
|
87
80
|
|
88
81
|
c.action do |args, options|
|
89
|
-
abort "
|
90
|
-
|
91
|
-
|
92
|
-
|
82
|
+
abort "name or path is missing" unless args.length == 2
|
83
|
+
name = args.first
|
84
|
+
path = args.last
|
85
|
+
ctl = KeystoreController.new(options)
|
86
|
+
ctl.add(name, path)
|
87
|
+
ctl.display
|
93
88
|
end
|
94
89
|
end
|
95
|
-
alias_command :remote, :"remote-keystore"
|
96
90
|
|
97
|
-
command
|
98
|
-
c.syntax =
|
99
|
-
c.description = "
|
100
|
-
c.option '--keystore STRING', String, 'a selected keystore'
|
91
|
+
command "keystore default" do |c|
|
92
|
+
c.syntax = 'leeloo keystore default name'
|
93
|
+
c.description = "set the default keystore"
|
101
94
|
|
102
95
|
c.action do |args, options|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
abort "call remote-keystore before sync-keystore"
|
109
|
-
end
|
96
|
+
abort "name is missing" unless args.length == 1
|
97
|
+
name = args.first
|
98
|
+
ctl = KeystoreController.new(options)
|
99
|
+
ctl.set_default(name)
|
100
|
+
ctl.display
|
110
101
|
end
|
111
102
|
end
|
112
|
-
alias_command :sync, :"sync-keystore"
|
113
103
|
|
114
|
-
command :
|
115
|
-
c.syntax = 'leeloo
|
116
|
-
c.description = "
|
104
|
+
command :read do |c|
|
105
|
+
c.syntax = 'leeloo read <name>'
|
106
|
+
c.description = "Display a secret from a keystore"
|
107
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
108
|
+
c.option '--clipboard', nil, 'copy to clipboard'
|
117
109
|
c.option '--keystore STRING', String, 'a selected keystore'
|
118
110
|
|
119
111
|
c.action do |args, options|
|
120
|
-
|
121
|
-
|
122
|
-
|
112
|
+
abort "name is missing" unless args.length == 1
|
113
|
+
name = args.first
|
114
|
+
ctl = SecretController.new(options)
|
115
|
+
ctl.read(name)
|
116
|
+
ctl.display
|
123
117
|
end
|
124
118
|
end
|
125
|
-
alias_command :sign, :"sign-secret"
|
126
119
|
|
127
|
-
command :
|
128
|
-
c.syntax = 'leeloo
|
129
|
-
c.description = "
|
120
|
+
command :write do |c|
|
121
|
+
c.syntax = 'leeloo write <name> <secret>'
|
122
|
+
c.description = "Write a secret from a keystore"
|
130
123
|
c.option '--keystore STRING', String, 'a selected keystore'
|
131
124
|
c.option '--generate INTEGER', Integer, 'a number of randomized characters'
|
132
125
|
c.option '--stdin', nil, 'secret given by stdin pipe'
|
@@ -135,87 +128,101 @@ module Leeloo
|
|
135
128
|
c.action do |args, options|
|
136
129
|
abort "name is missing" unless args.length == 1
|
137
130
|
name = args.first
|
131
|
+
ctl = SecretController.new(options)
|
132
|
+
ctl.write(name)
|
133
|
+
ctl.display
|
134
|
+
end
|
135
|
+
end
|
138
136
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
secret = STDIN.read if options.stdin
|
144
|
-
secret = SecureRandom.base64(32).truncate(options.generate.to_i) if options.generate
|
145
|
-
|
146
|
-
unless secret
|
147
|
-
secret = password "secret"
|
148
|
-
confirm = password "confirm it"
|
149
|
-
abort "not the same secret" unless secret == confirm
|
150
|
-
end
|
137
|
+
command :translate do |c|
|
138
|
+
c.syntax = 'leeloo translate'
|
139
|
+
c.description = "translate stdin by replacing key ${my/secret} by the current value"
|
140
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
151
141
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
142
|
+
c.action do |args, options|
|
143
|
+
ctl = TranslateController.new(options)
|
144
|
+
ctl.translate
|
145
|
+
ctl.display
|
156
146
|
end
|
157
147
|
end
|
158
|
-
alias_command :write, :"add-secret"
|
159
|
-
alias_command :add, :"add-secret"
|
160
|
-
alias_command :insert, :"add-secret"
|
161
|
-
alias_command :set, :"add-secret"
|
162
148
|
|
163
|
-
command :
|
164
|
-
c.syntax = 'leeloo
|
165
|
-
c.description = "
|
149
|
+
command :remove do |c|
|
150
|
+
c.syntax = 'leeloo delete <name>'
|
151
|
+
c.description = "Delete a secret from a keystore"
|
166
152
|
c.option '--keystore STRING', String, 'a selected keystore'
|
167
|
-
c.option '--clipboard', nil, 'copy to clipboard'
|
168
|
-
c.option '--to /path/to/file', String, 'for binary file'
|
169
153
|
|
170
154
|
c.action do |args, options|
|
171
155
|
abort "name is missing" unless args.length == 1
|
172
156
|
name = args.first
|
157
|
+
ctl = SecretController.new(options)
|
158
|
+
ctl.remove(name)
|
159
|
+
ctl.display
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
command :sync do |c|
|
164
|
+
c.syntax = 'leeloo sync'
|
165
|
+
c.description = "Synchronize a keystore"
|
166
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
167
|
+
|
168
|
+
c.action do |args, options|
|
169
|
+
ctl = KeystoreController.new(options)
|
170
|
+
ctl.sync
|
171
|
+
ctl.display
|
172
|
+
end
|
173
|
+
end
|
173
174
|
|
174
|
-
|
175
|
-
|
175
|
+
command :init do |c|
|
176
|
+
c.syntax = 'leeloo init'
|
177
|
+
c.description = "Initialize a keystore"
|
178
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
176
179
|
|
177
|
-
|
178
|
-
|
180
|
+
c.action do |args, options|
|
181
|
+
ctl = KeystoreController.new(options)
|
182
|
+
ctl.init
|
183
|
+
ctl.display
|
184
|
+
end
|
185
|
+
end
|
179
186
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
say secret unless options.clipboard
|
185
|
-
Clipboard.copy secret if options.clipboard
|
186
|
-
end
|
187
|
+
command :share do |c|
|
188
|
+
c.syntax = 'leeloo share <name>'
|
189
|
+
c.description = "share a secret with someone"
|
190
|
+
c.option '--keystore STRING', String, 'a selected keystore'
|
187
191
|
|
188
|
-
|
189
|
-
|
190
|
-
|
192
|
+
c.action do |args, options|
|
193
|
+
abort "name is missing" unless args.length == 1
|
194
|
+
name = args.first
|
195
|
+
ctl = ShareController.new(options)
|
196
|
+
ctl.token(name)
|
197
|
+
ctl.display
|
198
|
+
ctl.start_server
|
191
199
|
end
|
192
|
-
alias_command :read, :"read-secret"
|
193
|
-
alias_command :get, :"read-secret"
|
194
200
|
end
|
195
201
|
|
196
|
-
command :
|
197
|
-
c.syntax = 'leeloo
|
198
|
-
c.description = "
|
202
|
+
command :token do |c|
|
203
|
+
c.syntax = 'leeloo token <name>'
|
204
|
+
c.description = "generate an access token for a given secret"
|
199
205
|
c.option '--keystore STRING', String, 'a selected keystore'
|
200
206
|
|
201
207
|
c.action do |args, options|
|
202
208
|
abort "name is missing" unless args.length == 1
|
203
209
|
name = args.first
|
210
|
+
ctl = ShareController.new(options)
|
211
|
+
ctl.token(name)
|
212
|
+
ctl.display
|
213
|
+
end
|
214
|
+
end
|
204
215
|
|
205
|
-
|
206
|
-
|
216
|
+
command :server do |c|
|
217
|
+
c.syntax = 'leeloo server'
|
218
|
+
c.description = "start a server access token"
|
207
219
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
rescue
|
212
|
-
abort "unable to find #{name}"
|
213
|
-
end
|
220
|
+
c.action do |args, options|
|
221
|
+
ctl = ShareController.new(options)
|
222
|
+
ctl.start_server
|
214
223
|
end
|
215
|
-
alias_command :remove, :"remove-secret"
|
216
|
-
alias_command :delete, :"remove-secret"
|
217
|
-
alias_command :erase, :"remove-secret"
|
218
224
|
end
|
225
|
+
|
219
226
|
end
|
220
227
|
end
|
221
228
|
end
|
@@ -0,0 +1,122 @@
|
|
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 = @preferences.keystore(@options.keystore).secrets
|
36
|
+
end
|
37
|
+
def search name
|
38
|
+
@secrets = @secrets.select { |secret| secret.name.downcase.include? name.downcase } || []
|
39
|
+
end
|
40
|
+
def display
|
41
|
+
@output.render_secrets @secrets
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class SecretController < PrivateLocalFileSystemController
|
46
|
+
def read name
|
47
|
+
@secret = @keystore.secret_from_name(name)
|
48
|
+
end
|
49
|
+
def write name
|
50
|
+
phrase = nil
|
51
|
+
|
52
|
+
phrase = STDIN.read if @options.stdin
|
53
|
+
phrase = SecureRandom.base64(32).truncate(@options.generate.to_i) if @options.generate
|
54
|
+
|
55
|
+
unless phrase
|
56
|
+
phrase = password "secret"
|
57
|
+
confirm = password "confirm it"
|
58
|
+
abort "not the same secret" unless phrase == confirm
|
59
|
+
end
|
60
|
+
|
61
|
+
@secret = @keystore.secret_from_name(name)
|
62
|
+
@secret.write(phrase)
|
63
|
+
end
|
64
|
+
def remove name
|
65
|
+
@secret = @keystore.secret_from_name(name)
|
66
|
+
@secret.erase
|
67
|
+
end
|
68
|
+
def display
|
69
|
+
@output.render_secret @secret
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class TranslateController < PrivateLocalFileSystemController
|
74
|
+
def translate
|
75
|
+
@text = STDIN.read
|
76
|
+
@text.scan(/\$\{.*\}/).each do |secret|
|
77
|
+
begin
|
78
|
+
@text.gsub! secret, (@keystore.secret_from_name(secret[2..-2])).read.to_s.strip
|
79
|
+
rescue => exception
|
80
|
+
# silent
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
def display
|
85
|
+
@output.render_text @text
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class KeystoreController < PrivateLocalFileSystemController
|
90
|
+
def add name, path
|
91
|
+
@preferences.add_keystore({"name" => name, "path" => path, "cypher" => "gpg", "vc" => "git"})
|
92
|
+
@preferences.keystore(name).init
|
93
|
+
end
|
94
|
+
def remove name
|
95
|
+
@preferences.remove_keystore name
|
96
|
+
end
|
97
|
+
def set_default name
|
98
|
+
@preferences.set_default_keystore name
|
99
|
+
end
|
100
|
+
def sync
|
101
|
+
@keystore.sync
|
102
|
+
end
|
103
|
+
def init
|
104
|
+
@keystore.init
|
105
|
+
end
|
106
|
+
def display
|
107
|
+
@output.render_preferences @preferences
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class ShareController < PrivateLocalFileSystemController
|
112
|
+
def token name
|
113
|
+
@footprint = @keystore.footprint_of(name)
|
114
|
+
end
|
115
|
+
def start_server
|
116
|
+
Server.new.start @preferences
|
117
|
+
end
|
118
|
+
def display
|
119
|
+
@output.render_footprint @footprint
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|