trocla 0.3.0 → 0.4.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 +5 -5
- data/.travis.yml +2 -7
- data/CHANGELOG.md +12 -0
- data/Gemfile +7 -34
- data/README.md +46 -3
- data/bin/trocla +22 -5
- data/lib/VERSION +1 -1
- data/lib/trocla.rb +9 -1
- data/lib/trocla/formats/sshkey.rb +46 -0
- data/lib/trocla/formats/x509.rb +2 -0
- data/lib/trocla/store.rb +10 -0
- data/lib/trocla/stores/memory.rb +9 -0
- data/lib/trocla/stores/moneta.rb +26 -0
- data/lib/trocla/stores/vault.rb +50 -0
- data/spec/spec_helper.rb +13 -1
- data/spec/trocla/formats/sshkey_spec.rb +52 -0
- data/spec/trocla/formats/x509_spec.rb +8 -1
- data/spec/trocla_spec.rb +40 -0
- data/trocla.gemspec +22 -23
- metadata +42 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 18cb6a02ca556208840b6370287987e72fc18e01e199b7fe1b5b72c463a91ee4
|
4
|
+
data.tar.gz: d2f8068ab15baf1a5cbbfd3370543ff03ad2f2c1baf564ba43f824589920fcf6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5829218248d2d9f7f4f3ddfc5bca4f35f8839871fd18074ede34f9281eae086a79c858987285da7839b5699961b417244fc5d86a696b355a8fd4c96d0145bf8
|
7
|
+
data.tar.gz: fc4c6e7ce2cf53009ee3db4f8791b820dca9c696223567fac1367cc3e80b8558a2b5d430f6a255d0f7e07403f9be06ee3e895310971303dc571be6a82d908404
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## to 0.4.0
|
4
|
+
|
5
|
+
* Add vault backend (#61) - Thank you [Steffy Fort](https://github.com/fe80)
|
6
|
+
* Add sshkey format similar to the OpenSSL - Thank you [Raphaël Rondeau](https://github.com/rrondeau)
|
7
|
+
* format/x509 allow to render 'publickeyonly' (#62) - Thank you [Thomas Weißschuh](https://github.com/t-8ch)
|
8
|
+
* Add a method to search for keys and list all formats of a key (#49) - Thank you - [Steffy Fort](https://github.com/fe80)
|
9
|
+
* Proper return code on cli (#57) - Thank you [Steffy Fort](https://github.com/fe80)
|
10
|
+
* expand search path for sample config file to fix autopkgtest (#64) - Thank you [anarcat](https://github.com/anarcat)
|
11
|
+
* drop support for ruby < 2.7 & update dependencies
|
12
|
+
* skip self-signed cert verification test on newer openssl version (#63)
|
13
|
+
* Fix reseting passwords when using SSL encryption (#52)
|
14
|
+
|
3
15
|
## to 0.3.0
|
4
16
|
|
5
17
|
* Add open method to be able to immediately close a trocla store after using it - thanks martinpfeiffer
|
data/Gemfile
CHANGED
@@ -3,48 +3,21 @@ source "http://rubygems.org"
|
|
3
3
|
# Example:
|
4
4
|
# gem "activesupport", ">= 2.3.5"
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
|
10
|
-
if RUBY_VERSION.to_f < 2.1
|
11
|
-
gem 'nokogiri', '< 1.7'
|
12
|
-
end
|
13
|
-
|
14
|
-
if RUBY_VERSION.to_f > 1.8
|
15
|
-
gem "moneta"
|
16
|
-
gem "highline"
|
17
|
-
else
|
18
|
-
gem "moneta", "~> 0.7.20"
|
19
|
-
gem "highline", "~> 1.6.2"
|
20
|
-
gem 'rake', '< 11'
|
21
|
-
gem 'git', '< 1.3'
|
22
|
-
end
|
6
|
+
gem "moneta", "~> 1.4.0"
|
7
|
+
gem "highline", "~> 2.0.0"
|
23
8
|
|
24
9
|
if defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'jruby')
|
25
10
|
gem 'jruby-openssl'
|
26
11
|
end
|
27
12
|
gem "bcrypt"
|
13
|
+
gem "sshkey"
|
28
14
|
|
29
15
|
# Add dependencies to develop your gem here.
|
30
16
|
# Include everything needed to run rake, tests, features, etc.
|
31
17
|
group :development do
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
gem 'jeweler', '< 2.2'
|
37
|
-
else
|
38
|
-
gem "jeweler"
|
39
|
-
end
|
40
|
-
if RUBY_VERSION.to_f < 2.0
|
41
|
-
gem 'public_suffix', '~> 1.4.6'
|
42
|
-
end
|
43
|
-
else
|
44
|
-
gem "rspec", "~> 2.4"
|
45
|
-
gem "rdoc", "~> 3.8"
|
46
|
-
gem "jeweler", "~> 1.6"
|
47
|
-
gem "addressable", "~> 2.3.8"
|
48
|
-
end
|
18
|
+
gem "rspec"
|
19
|
+
gem "rdoc"
|
20
|
+
gem "jeweler"
|
21
|
+
gem "addressable"
|
49
22
|
gem 'rspec-pending_for'
|
50
23
|
end
|
data/README.md
CHANGED
@@ -24,7 +24,7 @@ retrieve (by deleting) the plain password and send it to the user. Puppet
|
|
24
24
|
will still simply retrieve the hashed password that is stored in trocla,
|
25
25
|
while the plain password is not anymore stored on the server.
|
26
26
|
|
27
|
-
|
27
|
+
By default trocla uses moneta to store the passwords and can use any kind of
|
28
28
|
key/value based storage supported by moneta for trocla. By default it uses a
|
29
29
|
simple yaml file.
|
30
30
|
However, since version 0.2.0 trocla also supports a pluggable storage backend
|
@@ -212,8 +212,25 @@ Additional options are:
|
|
212
212
|
|
213
213
|
Output render options are:
|
214
214
|
|
215
|
-
certonly
|
216
|
-
keyonly
|
215
|
+
certonly If set to true the x509 format will return only the certificate
|
216
|
+
keyonly If set to true the x509 format will return only the private key
|
217
|
+
publickeyonly If set to true the x509 format will return only the public key
|
218
|
+
|
219
|
+
### sshkey
|
220
|
+
|
221
|
+
This format generate a ssh keypair
|
222
|
+
|
223
|
+
Additional options are:
|
224
|
+
|
225
|
+
type The ssh key type (rsa, dsa). Default: rsa
|
226
|
+
bits Specifies the number of bits in the key to create. Default: 2048
|
227
|
+
comment Specifies a comment.
|
228
|
+
passphrase Specifies a passphrase.
|
229
|
+
|
230
|
+
Output render options are:
|
231
|
+
|
232
|
+
pubonly If set to true the sshkey format will return only the ssh public key
|
233
|
+
privonly If set to true the sshkey format will return only the ssh private key
|
217
234
|
|
218
235
|
## Installation
|
219
236
|
|
@@ -256,6 +273,7 @@ Such a store is a simple class that implements Trocla::Store and at the moment t
|
|
256
273
|
|
257
274
|
* Moneta - the default store using [moneta](https://rubygems.org/gems/moneta) to delegate storing the values
|
258
275
|
* Memory - simple inmemory backend. Mainly used for testing.
|
276
|
+
* Vault - modern secrets storage by HashiCorp, require the ruby gem [vault](https://github.com/hashicorp/vault-ruby)
|
259
277
|
|
260
278
|
The backend is chosen based on the `store` configuration option. If it is a symbol, we expect it to be a store that we ship with trocla. Otherwise, we assume it to be a fully qualified ruby class name, that inherits from Trocla::Store. If trocla should load an additional library to be able to find your custom store class, you can set `store_require` to whatever should be passed to a ruby require statement.
|
261
279
|
|
@@ -298,6 +316,31 @@ store_options:
|
|
298
316
|
|
299
317
|
These examples are by no way complete, moneta has much more to offer. Please have a look at [moneta's documentation](https://github.com/minad/moneta/blob/master/README.md) for further information.
|
300
318
|
|
319
|
+
#### Vault backend
|
320
|
+
|
321
|
+
[Vault](https://www.vaultproject.io/) is a modern secret storage supported by HashiCorp, which works with a REST API. You can create multiple storage engine.
|
322
|
+
|
323
|
+
To use vault with trocla you need to create a kv (key/value) storage engine on the vault side. Trocla can use [v1](https://www.vaultproject.io/docs/secrets/kv/kv-v1) and [v2](https://www.vaultproject.io/docs/secrets/kv/kv-v2) API endpoints, but it's recommended to use the v2 (native hash object, history, acl...).
|
324
|
+
|
325
|
+
You need to install the `vault` gem to be able to use the vault backend, which is not included in the default dependencies for trocla.
|
326
|
+
|
327
|
+
With vault storage, the terminology changes:
|
328
|
+
* `mount`, this is the name of your kv engine
|
329
|
+
* `key`, this is the biggest change. As usual with trocla, the key is a simple string. With the vault kv engine, the key map to a path, so you can have a key like `my/path/key` for structured your data
|
330
|
+
* `secret`, is the data content of your key. This is a simple hash with key (format) and value (the secret content of your format)
|
331
|
+
|
332
|
+
The trocla mapping works the same way as with a moneta or file backend.
|
333
|
+
|
334
|
+
The `store_options` are a dynamic argument for initializer [Vault::Client](https://github.com/hashicorp/vault-ruby/blob/master/lib/vault/client.rb) class (except `:mount`, used to defined the kv name). You can define only one kv mount.
|
335
|
+
|
336
|
+
```YAML
|
337
|
+
store: :vault
|
338
|
+
store_options:
|
339
|
+
:mount: kv
|
340
|
+
:token: s.Tok3n
|
341
|
+
:address: https://vault.local
|
342
|
+
```
|
343
|
+
|
301
344
|
### Backend encryption
|
302
345
|
|
303
346
|
By default trocla does not encrypt anything it stores. You might want to let Trocla encrypt all your passwords, at the moment the only supported way is SSL.
|
data/bin/trocla
CHANGED
@@ -99,14 +99,31 @@ def reset(options)
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def delete(options)
|
102
|
-
|
102
|
+
res = Trocla.new(options.delete(:config_file)).delete_password(
|
103
103
|
options.delete(:trocla_key),
|
104
104
|
options.delete(:trocla_format)
|
105
|
-
)
|
105
|
+
)
|
106
|
+
[ res, res.nil? ? 1 : 0 ]
|
106
107
|
end
|
107
108
|
|
108
109
|
def formats(options)
|
109
|
-
|
110
|
+
key = (options.delete(:trocla_key) || '' )
|
111
|
+
if key.empty?
|
112
|
+
"Available formats: #{Trocla::Formats.all.join(', ')}"
|
113
|
+
else
|
114
|
+
res = Trocla.new(options.delete(:config_file)).available_format(
|
115
|
+
key,
|
116
|
+
options.merge(YAML.load(options.delete(:other_options).shift.to_s)||{})
|
117
|
+
)
|
118
|
+
[ res.nil? ? res : res.join(', '), res.nil? ? 1 : 0 ]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def search(options)
|
123
|
+
res = Trocla.new(options.delete(:config_file)).search_key(
|
124
|
+
options.delete(:trocla_key)
|
125
|
+
)
|
126
|
+
[ res.nil? ? res : res.join("\n"), res.nil? ? 1 : 0 ]
|
110
127
|
end
|
111
128
|
|
112
129
|
def check_format(format_name)
|
@@ -119,13 +136,13 @@ def check_format(format_name)
|
|
119
136
|
end
|
120
137
|
end
|
121
138
|
|
122
|
-
actions=['create','get','set','reset','delete',
|
139
|
+
actions=['create','get','set','reset','delete','formats','search']
|
123
140
|
|
124
141
|
if (action=ARGV.shift) && actions.include?(action)
|
125
142
|
options[:trocla_key] = ARGV.shift
|
126
143
|
options[:trocla_format] = ARGV.shift
|
127
144
|
options[:other_options] = ARGV
|
128
|
-
check_format(options[:trocla_format]) unless ['delete','formats'].include?(action)
|
145
|
+
check_format(options[:trocla_format]) unless ['delete','formats','search'].include?(action)
|
129
146
|
begin
|
130
147
|
result, excode = send(action,options)
|
131
148
|
if result
|
data/lib/VERSION
CHANGED
data/lib/trocla.rb
CHANGED
@@ -62,7 +62,7 @@ class Trocla
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def reset_password(key,format,options={})
|
65
|
-
|
65
|
+
delete_password(key,format)
|
66
66
|
password(key,format,options)
|
67
67
|
end
|
68
68
|
|
@@ -82,6 +82,14 @@ class Trocla
|
|
82
82
|
render(format,password,options)
|
83
83
|
end
|
84
84
|
|
85
|
+
def available_format(key, options={})
|
86
|
+
render(false,store.formats(key),options)
|
87
|
+
end
|
88
|
+
|
89
|
+
def search_key(key, options={})
|
90
|
+
render(false,store.search(key),options)
|
91
|
+
end
|
92
|
+
|
85
93
|
def formats(format)
|
86
94
|
(@format_cache||={})[format] ||= Trocla::Formats[format].new(self)
|
87
95
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'sshkey'
|
2
|
+
|
3
|
+
class Trocla::Formats::Sshkey < Trocla::Formats::Base
|
4
|
+
|
5
|
+
expensive true
|
6
|
+
|
7
|
+
def format(plain_password,options={})
|
8
|
+
|
9
|
+
if plain_password.match(/-----BEGIN RSA PRIVATE KEY-----.*-----END RSA PRIVATE KEY/m)
|
10
|
+
# Import, validate ssh key
|
11
|
+
begin
|
12
|
+
sshkey = ::SSHKey.new(plain_password)
|
13
|
+
rescue Exception => e
|
14
|
+
raise "SSH key import failed: #{e.message}"
|
15
|
+
end
|
16
|
+
return sshkey.private_key + sshkey.ssh_public_key
|
17
|
+
end
|
18
|
+
|
19
|
+
type = options['type'] || 'rsa'
|
20
|
+
bits = options['bits'] || 2048
|
21
|
+
|
22
|
+
begin
|
23
|
+
sshkey = ::SSHKey.generate(
|
24
|
+
type: type,
|
25
|
+
bits: bits,
|
26
|
+
comment: options['comment'],
|
27
|
+
passphrase: options['passphrase']
|
28
|
+
)
|
29
|
+
rescue Exception => e
|
30
|
+
raise "SSH key creation failed: #{e.message}"
|
31
|
+
end
|
32
|
+
|
33
|
+
sshkey.private_key + sshkey.ssh_public_key
|
34
|
+
end
|
35
|
+
|
36
|
+
def render(output,render_options={})
|
37
|
+
if render_options['privonly']
|
38
|
+
::SSHKey.new(output).private_key
|
39
|
+
elsif render_options['pubonly']
|
40
|
+
::SSHKey.new(output).ssh_public_key
|
41
|
+
else
|
42
|
+
super(output,render_options)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
data/lib/trocla/formats/x509.rb
CHANGED
@@ -97,6 +97,8 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
|
|
97
97
|
OpenSSL::PKey::RSA.new(output).to_pem
|
98
98
|
elsif render_options['certonly']
|
99
99
|
OpenSSL::X509::Certificate.new(output).to_pem
|
100
|
+
elsif render_options['publickeyonly']
|
101
|
+
OpenSSL::PKey::RSA.new(output).public_key.to_pem
|
100
102
|
else
|
101
103
|
super(output,render_options)
|
102
104
|
end
|
data/lib/trocla/store.rb
CHANGED
@@ -50,6 +50,16 @@ class Trocla::Store
|
|
50
50
|
format.nil? ? (delete_all(key)||{}) : delete_format(key,format)
|
51
51
|
end
|
52
52
|
|
53
|
+
# returns all formats for a key
|
54
|
+
def formats(key)
|
55
|
+
raise 'not implemented'
|
56
|
+
end
|
57
|
+
|
58
|
+
# def searches for a key
|
59
|
+
def search(key)
|
60
|
+
raise 'not implemented'
|
61
|
+
end
|
62
|
+
|
53
63
|
private
|
54
64
|
# sets a new plain value
|
55
65
|
# *must* invalidate all
|
data/lib/trocla/stores/memory.rb
CHANGED
@@ -19,6 +19,15 @@ class Trocla::Stores::Memory < Trocla::Store
|
|
19
19
|
set_expires(key,options['expires'])
|
20
20
|
end
|
21
21
|
|
22
|
+
def formats(key)
|
23
|
+
memory[key].empty? ? nil : memory[key].keys
|
24
|
+
end
|
25
|
+
|
26
|
+
def search(key)
|
27
|
+
r = memory.keys.grep(/#{key}/)
|
28
|
+
r.empty? ? nil : r
|
29
|
+
end
|
30
|
+
|
22
31
|
private
|
23
32
|
def set_plain(key,value,options)
|
24
33
|
memory[key] = { 'plain' => value }
|
data/lib/trocla/stores/moneta.rb
CHANGED
@@ -18,6 +18,17 @@ class Trocla::Stores::Moneta < Trocla::Store
|
|
18
18
|
moneta.fetch(key, {})[format]
|
19
19
|
end
|
20
20
|
|
21
|
+
def formats(key)
|
22
|
+
r = moneta.fetch(key)
|
23
|
+
r.nil? ? nil : r.keys
|
24
|
+
end
|
25
|
+
|
26
|
+
def search(key)
|
27
|
+
raise 'The search option is not available for any adapter other than Sequel or YAML' unless store_config['adapter'] == :Sequel || store_config['adapter'] == :YAML
|
28
|
+
r = search_keys(key)
|
29
|
+
r.empty? ? nil : r
|
30
|
+
end
|
31
|
+
|
21
32
|
private
|
22
33
|
def set_plain(key,value,options)
|
23
34
|
h = { 'plain' => value }
|
@@ -55,4 +66,19 @@ class Trocla::Stores::Moneta < Trocla::Store
|
|
55
66
|
end
|
56
67
|
res
|
57
68
|
end
|
69
|
+
def search_keys(key)
|
70
|
+
_moneta = Moneta.new(store_config['adapter'], (store_config['adapter_options']||{}).merge({ :expires => false }))
|
71
|
+
a = []
|
72
|
+
if store_config['adapter'] == :Sequel
|
73
|
+
keys = _moneta.adapter.backend[:trocla].select_order_map {from_base64(:k)}
|
74
|
+
elsif store_config['adapter'] == :YAML
|
75
|
+
keys = _moneta.adapter.backend.transaction(true) { _moneta.adapter.backend.roots }
|
76
|
+
end
|
77
|
+
_moneta.close
|
78
|
+
regexp = Regexp.new("#{key}")
|
79
|
+
keys.each do |k|
|
80
|
+
a << k if regexp.match(k)
|
81
|
+
end
|
82
|
+
a
|
83
|
+
end
|
58
84
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# the default vault based store
|
2
|
+
class Trocla::Stores::Vault < Trocla::Store
|
3
|
+
attr_reader :vault, :mount
|
4
|
+
def initialize(config,trocla)
|
5
|
+
super(config,trocla)
|
6
|
+
require 'vault'
|
7
|
+
@mount = (config.delete(:mount) || 'kv')
|
8
|
+
# load expire support by default
|
9
|
+
@vault = Vault::Client.new(config)
|
10
|
+
end
|
11
|
+
|
12
|
+
def close
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(key,format)
|
16
|
+
read(key)[format.to_sym]
|
17
|
+
end
|
18
|
+
|
19
|
+
def formats(key)
|
20
|
+
read(key).keys
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def read(key)
|
25
|
+
k = vault.kv(mount).read(key)
|
26
|
+
k.nil? ? {} : k.data
|
27
|
+
end
|
28
|
+
|
29
|
+
def write(key, value)
|
30
|
+
vault.kv(mount).write(key, value)
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_plain(key,value,options)
|
34
|
+
set_format(key,'plain',value,options)
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_format(key,format,value,options)
|
38
|
+
write(key, read(key).merge({format.to_sym => value}))
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete_all(key)
|
42
|
+
vault.kv(mount).delete(key)
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete_format(key,format)
|
46
|
+
old = read(key)
|
47
|
+
write(key, old.reject { |k,v| k == format.to_sym })
|
48
|
+
old[format.to_sym]
|
49
|
+
end
|
50
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
2
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'jruby' if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
|
3
4
|
require 'rspec'
|
4
5
|
require 'rspec/pending_for'
|
5
6
|
require 'yaml'
|
@@ -35,6 +36,11 @@ RSpec.shared_examples "encryption_basics" do
|
|
35
36
|
expect(@trocla.get_password('some_pass', 'plain')).to eql('super secret')
|
36
37
|
end
|
37
38
|
|
39
|
+
it "resets passwords" do
|
40
|
+
@trocla.set_password('some_pass', 'plain', 'super secret')
|
41
|
+
expect(@trocla.reset_password('some_pass', 'plain')).not_to eql('super secret')
|
42
|
+
end
|
43
|
+
|
38
44
|
end
|
39
45
|
describe 'deleting' do
|
40
46
|
it "plain" do
|
@@ -225,7 +231,13 @@ RSpec.shared_examples 'store_validation' do |store|
|
|
225
231
|
end
|
226
232
|
|
227
233
|
def default_config
|
228
|
-
@default_config ||=
|
234
|
+
@default_config ||= begin
|
235
|
+
config_path = [
|
236
|
+
File.expand_path(base_dir+'/lib/trocla/default_config.yaml'),
|
237
|
+
File.expand_path(File.dirname($LOADED_FEATURES.grep(/trocla.rb/)[0])+'/trocla/default_config.yaml'),
|
238
|
+
].find { |p| File.exists?(p) }
|
239
|
+
YAML.load(File.read(config_path))
|
240
|
+
end
|
229
241
|
end
|
230
242
|
|
231
243
|
def test_config
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe "Trocla::Format::Sshkey" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
expect_any_instance_of(Trocla).to receive(:read_config).and_return(test_config)
|
7
|
+
@trocla = Trocla.new
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:sshkey_options) do
|
11
|
+
{
|
12
|
+
'type' => 'rsa',
|
13
|
+
'bits' => 4096,
|
14
|
+
'comment' => 'My ssh key'
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "sshkey" do
|
19
|
+
it "is able to create an ssh keypair without options" do
|
20
|
+
sshkey = @trocla.password('my_ssh_keypair', 'sshkey', {})
|
21
|
+
expect(sshkey).to start_with('-----BEGIN RSA PRIVATE KEY-----')
|
22
|
+
expect(sshkey).to match(/ssh-/)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "is able to create an ssh keypair with options" do
|
26
|
+
sshkey = @trocla.password('my_ssh_keypair', 'sshkey', sshkey_options)
|
27
|
+
expect(sshkey).to start_with('-----BEGIN RSA PRIVATE KEY-----')
|
28
|
+
expect(sshkey).to match(/ssh-/)
|
29
|
+
expect(sshkey).to end_with('My ssh key')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'supports fetching only the priv key' do
|
33
|
+
sshkey = @trocla.password('my_ssh_keypair', 'sshkey', { 'render' => {'privonly' => true }})
|
34
|
+
expect(sshkey).to start_with('-----BEGIN RSA PRIVATE KEY-----')
|
35
|
+
expect(sshkey).not_to match(/ssh-/)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'supports fetching only the pub key' do
|
39
|
+
sshkey = @trocla.password('my_ssh_keypair', 'sshkey', { 'render' => {'pubonly' => true }})
|
40
|
+
expect(sshkey).to start_with('ssh-rsa')
|
41
|
+
expect(sshkey).not_to match(/-----BEGIN RSA PRIVATE KEY-----/)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "is able to create an ssh keypair with a passphrase" do
|
45
|
+
sshkey = @trocla.password('my_ssh_keypair', 'sshkey', { 'passphrase' => 'spec' })
|
46
|
+
expect(sshkey).to start_with('-----BEGIN RSA PRIVATE KEY-----')
|
47
|
+
expect(sshkey).to match(/ssh-/)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -44,7 +44,9 @@ describe "Trocla::Format::X509" do
|
|
44
44
|
expect(cert.public_key.n.num_bytes * 8).to eq(4096)
|
45
45
|
expect((Date.parse(cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
|
46
46
|
# it's a self signed cert and NOT a CA
|
47
|
-
|
47
|
+
# Change of behavior on openssl side: https://github.com/openssl/openssl/issues/15146
|
48
|
+
validates_self_even_if_no_ca = Gem::Version.new(%x{openssl version}.split(' ')[1]) > Gem::Version.new('1.1.1g')
|
49
|
+
expect(verify(cert,cert)).to be validates_self_even_if_no_ca
|
48
50
|
|
49
51
|
v = cert.extensions.find{|e| e.oid == 'basicConstraints' }.value
|
50
52
|
expect(v).to eq('CA:FALSE')
|
@@ -136,6 +138,11 @@ describe "Trocla::Format::X509" do
|
|
136
138
|
expect(cert_str).not_to match(/-----BEGIN CERTIFICATE-----/)
|
137
139
|
expect(cert_str).to match(/-----BEGIN RSA PRIVATE KEY-----/)
|
138
140
|
end
|
141
|
+
it 'supports fetching only the publickey' do
|
142
|
+
pkey_str = @trocla.password('mycert', 'x509', cert_options.merge('render' => {'publickeyonly' => true }))
|
143
|
+
expect(pkey_str).not_to match(/-----BEGIN CERTIFICATE-----/)
|
144
|
+
expect(pkey_str).to match(/-----BEGIN PUBLIC KEY-----/)
|
145
|
+
end
|
139
146
|
it 'supports fetching only the cert' do
|
140
147
|
cert_str = @trocla.password('mycert', 'x509', cert_options.merge('render' => {'certonly' => true }))
|
141
148
|
expect(cert_str).to match(/-----BEGIN CERTIFICATE-----/)
|
data/spec/trocla_spec.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -- encoding : utf-8 --
|
1
2
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
3
|
|
3
4
|
describe "Trocla" do
|
@@ -99,6 +100,11 @@ describe "Trocla" do
|
|
99
100
|
expect(@trocla.get_password('set_test2','md5crypt')).to eq(md5crypt)
|
100
101
|
expect(@trocla.get_password('set_test2','plain')).to eq(plain)
|
101
102
|
end
|
103
|
+
|
104
|
+
it 'is able to set password with umlauts and other UTF-8 charcters' do
|
105
|
+
expect(myumlaut = @trocla.set_password('set_test_umlaut','plain','Tütü')).to eql('Tütü')
|
106
|
+
expect(@trocla.get_password('set_test_umlaut','plain','Tütü')).to eql('Tütü')
|
107
|
+
end
|
102
108
|
end
|
103
109
|
|
104
110
|
describe "reset_password" do
|
@@ -120,6 +126,40 @@ describe "Trocla" do
|
|
120
126
|
end
|
121
127
|
end
|
122
128
|
|
129
|
+
describe "search_key" do
|
130
|
+
it "search a specific key" do
|
131
|
+
keys = ['search_key','search_key1','key_search','key_search2']
|
132
|
+
keys.each do |k|
|
133
|
+
@trocla.password(k,'plain')
|
134
|
+
end
|
135
|
+
expect(@trocla.search_key('search_key1').length).to eq(1)
|
136
|
+
end
|
137
|
+
it "ensure search regex is ok" do
|
138
|
+
keys = ['search_key2','search_key3','key_search2','key_search4']
|
139
|
+
keys.each do |k|
|
140
|
+
@trocla.password(k,'plain')
|
141
|
+
end
|
142
|
+
expect(@trocla.search_key('key').length).to eq(4)
|
143
|
+
expect(@trocla.search_key('^search').length).to eq(2)
|
144
|
+
expect(@trocla.search_key('ch.*3').length).to eq(1)
|
145
|
+
expect(@trocla.search_key('ch.*[3-4]$').length).to eq(2)
|
146
|
+
expect(@trocla.search_key('ch.*1')).to be_nil
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "list_format" do
|
151
|
+
it "list available formats for key" do
|
152
|
+
formats = ['plain','mysql']
|
153
|
+
formats.each do |f|
|
154
|
+
@trocla.password('list_key',f)
|
155
|
+
end
|
156
|
+
expect(@trocla.available_format('list_key')).to eq(formats)
|
157
|
+
end
|
158
|
+
it "no return if key doesn't exist" do
|
159
|
+
expect(@trocla.available_format('list_key1')).to be_nil
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
123
163
|
describe "delete_password" do
|
124
164
|
it "deletes all passwords if no format is given" do
|
125
165
|
expect(@trocla.password('delete_test1','mysql')).not_to be_nil
|
data/trocla.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: trocla 0.
|
5
|
+
# stub: trocla 0.4.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "trocla".freeze
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "0.4.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["mh".freeze]
|
14
|
-
s.date = "
|
14
|
+
s.date = "2021-05-11"
|
15
15
|
s.description = "Trocla helps you to generate random passwords and to store them in various formats (plain, MD5, bcrypt) for later retrival.".freeze
|
16
16
|
s.email = "mh+trocla@immerda.ch".freeze
|
17
17
|
s.executables = ["trocla".freeze]
|
@@ -46,17 +46,20 @@ Gem::Specification.new do |s|
|
|
46
46
|
"lib/trocla/formats/sha256crypt.rb",
|
47
47
|
"lib/trocla/formats/sha512crypt.rb",
|
48
48
|
"lib/trocla/formats/ssha.rb",
|
49
|
+
"lib/trocla/formats/sshkey.rb",
|
49
50
|
"lib/trocla/formats/x509.rb",
|
50
51
|
"lib/trocla/store.rb",
|
51
52
|
"lib/trocla/stores.rb",
|
52
53
|
"lib/trocla/stores/memory.rb",
|
53
54
|
"lib/trocla/stores/moneta.rb",
|
55
|
+
"lib/trocla/stores/vault.rb",
|
54
56
|
"lib/trocla/util.rb",
|
55
57
|
"lib/trocla/version.rb",
|
56
58
|
"spec/data/.keep",
|
57
59
|
"spec/spec_helper.rb",
|
58
60
|
"spec/trocla/encryptions/none_spec.rb",
|
59
61
|
"spec/trocla/encryptions/ssl_spec.rb",
|
62
|
+
"spec/trocla/formats/sshkey_spec.rb",
|
60
63
|
"spec/trocla/formats/x509_spec.rb",
|
61
64
|
"spec/trocla/store/memory_spec.rb",
|
62
65
|
"spec/trocla/store/moneta_spec.rb",
|
@@ -66,36 +69,32 @@ Gem::Specification.new do |s|
|
|
66
69
|
]
|
67
70
|
s.homepage = "https://tech.immerda.ch/2011/12/trocla-get-hashed-passwords-out-of-puppet-manifests/".freeze
|
68
71
|
s.licenses = ["GPLv3".freeze]
|
69
|
-
s.rubygems_version = "
|
72
|
+
s.rubygems_version = "3.1.2".freeze
|
70
73
|
s.summary = "Trocla a simple password generator and storage".freeze
|
71
74
|
|
72
75
|
if s.respond_to? :specification_version then
|
73
76
|
s.specification_version = 4
|
77
|
+
end
|
74
78
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
s.add_dependency(%q<highline>.freeze, [">= 0"])
|
86
|
-
s.add_dependency(%q<bcrypt>.freeze, [">= 0"])
|
87
|
-
s.add_dependency(%q<rspec>.freeze, [">= 0"])
|
88
|
-
s.add_dependency(%q<rdoc>.freeze, [">= 0"])
|
89
|
-
s.add_dependency(%q<jeweler>.freeze, [">= 0"])
|
90
|
-
s.add_dependency(%q<rspec-pending_for>.freeze, [">= 0"])
|
91
|
-
end
|
79
|
+
if s.respond_to? :add_runtime_dependency then
|
80
|
+
s.add_runtime_dependency(%q<moneta>.freeze, ["~> 1.4.0"])
|
81
|
+
s.add_runtime_dependency(%q<highline>.freeze, ["~> 2.0.0"])
|
82
|
+
s.add_runtime_dependency(%q<bcrypt>.freeze, [">= 0"])
|
83
|
+
s.add_runtime_dependency(%q<sshkey>.freeze, [">= 0"])
|
84
|
+
s.add_development_dependency(%q<rspec>.freeze, [">= 0"])
|
85
|
+
s.add_development_dependency(%q<rdoc>.freeze, [">= 0"])
|
86
|
+
s.add_development_dependency(%q<jeweler>.freeze, [">= 0"])
|
87
|
+
s.add_development_dependency(%q<addressable>.freeze, [">= 0"])
|
88
|
+
s.add_development_dependency(%q<rspec-pending_for>.freeze, [">= 0"])
|
92
89
|
else
|
93
|
-
s.add_dependency(%q<moneta>.freeze, ["
|
94
|
-
s.add_dependency(%q<highline>.freeze, ["
|
90
|
+
s.add_dependency(%q<moneta>.freeze, ["~> 1.4.0"])
|
91
|
+
s.add_dependency(%q<highline>.freeze, ["~> 2.0.0"])
|
95
92
|
s.add_dependency(%q<bcrypt>.freeze, [">= 0"])
|
93
|
+
s.add_dependency(%q<sshkey>.freeze, [">= 0"])
|
96
94
|
s.add_dependency(%q<rspec>.freeze, [">= 0"])
|
97
95
|
s.add_dependency(%q<rdoc>.freeze, [">= 0"])
|
98
96
|
s.add_dependency(%q<jeweler>.freeze, [">= 0"])
|
97
|
+
s.add_dependency(%q<addressable>.freeze, [">= 0"])
|
99
98
|
s.add_dependency(%q<rspec-pending_for>.freeze, [">= 0"])
|
100
99
|
end
|
101
100
|
end
|
metadata
CHANGED
@@ -1,31 +1,45 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trocla
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mh
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: moneta
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.4.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 1.4.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: highline
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.0.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bcrypt
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - ">="
|
@@ -39,7 +53,7 @@ dependencies:
|
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
56
|
+
name: sshkey
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - ">="
|
@@ -94,6 +108,20 @@ dependencies:
|
|
94
108
|
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: addressable
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
126
|
name: rspec-pending_for
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -144,17 +172,20 @@ files:
|
|
144
172
|
- lib/trocla/formats/sha256crypt.rb
|
145
173
|
- lib/trocla/formats/sha512crypt.rb
|
146
174
|
- lib/trocla/formats/ssha.rb
|
175
|
+
- lib/trocla/formats/sshkey.rb
|
147
176
|
- lib/trocla/formats/x509.rb
|
148
177
|
- lib/trocla/store.rb
|
149
178
|
- lib/trocla/stores.rb
|
150
179
|
- lib/trocla/stores/memory.rb
|
151
180
|
- lib/trocla/stores/moneta.rb
|
181
|
+
- lib/trocla/stores/vault.rb
|
152
182
|
- lib/trocla/util.rb
|
153
183
|
- lib/trocla/version.rb
|
154
184
|
- spec/data/.keep
|
155
185
|
- spec/spec_helper.rb
|
156
186
|
- spec/trocla/encryptions/none_spec.rb
|
157
187
|
- spec/trocla/encryptions/ssl_spec.rb
|
188
|
+
- spec/trocla/formats/sshkey_spec.rb
|
158
189
|
- spec/trocla/formats/x509_spec.rb
|
159
190
|
- spec/trocla/store/memory_spec.rb
|
160
191
|
- spec/trocla/store/moneta_spec.rb
|
@@ -165,7 +196,7 @@ homepage: https://tech.immerda.ch/2011/12/trocla-get-hashed-passwords-out-of-pup
|
|
165
196
|
licenses:
|
166
197
|
- GPLv3
|
167
198
|
metadata: {}
|
168
|
-
post_install_message:
|
199
|
+
post_install_message:
|
169
200
|
rdoc_options: []
|
170
201
|
require_paths:
|
171
202
|
- lib
|
@@ -180,9 +211,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
180
211
|
- !ruby/object:Gem::Version
|
181
212
|
version: '0'
|
182
213
|
requirements: []
|
183
|
-
|
184
|
-
|
185
|
-
signing_key:
|
214
|
+
rubygems_version: 3.1.2
|
215
|
+
signing_key:
|
186
216
|
specification_version: 4
|
187
217
|
summary: Trocla a simple password generator and storage
|
188
218
|
test_files: []
|