trocla 0.3.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +24 -0
- data/.rspec +1 -1
- data/CHANGELOG.md +23 -0
- data/Gemfile +10 -36
- data/README.md +64 -5
- data/bin/trocla +57 -40
- data/lib/VERSION +1 -1
- data/lib/trocla/default_config.yaml +3 -4
- data/lib/trocla/encryptions/none.rb +0 -1
- data/lib/trocla/encryptions/ssl.rb +11 -11
- data/lib/trocla/encryptions.rb +12 -5
- data/lib/trocla/formats/bcrypt.rb +2 -2
- data/lib/trocla/formats/md5crypt.rb +2 -2
- data/lib/trocla/formats/mysql.rb +2 -2
- data/lib/trocla/formats/pgsql.rb +50 -3
- data/lib/trocla/formats/plain.rb +1 -3
- data/lib/trocla/formats/sha1.rb +1 -1
- data/lib/trocla/formats/sha256crypt.rb +2 -2
- data/lib/trocla/formats/sha512crypt.rb +2 -2
- data/lib/trocla/formats/ssha.rb +3 -3
- data/lib/trocla/formats/sshkey.rb +42 -0
- data/lib/trocla/formats/wireguard.rb +45 -0
- data/lib/trocla/formats/x509.rb +56 -46
- data/lib/trocla/formats.rb +15 -5
- data/lib/trocla/store.rb +24 -13
- data/lib/trocla/stores/memory.rb +26 -10
- data/lib/trocla/stores/moneta.rb +53 -17
- data/lib/trocla/stores/vault.rb +78 -0
- data/lib/trocla/stores.rb +3 -2
- data/lib/trocla/util.rb +28 -17
- data/lib/trocla/version.rb +7 -4
- data/lib/trocla.rb +51 -41
- data/spec/spec_helper.rb +13 -1
- data/spec/trocla/formats/pgsql_spec.rb +25 -0
- data/spec/trocla/formats/sshkey_spec.rb +52 -0
- data/spec/trocla/formats/x509_spec.rb +8 -1
- data/spec/trocla_spec.rb +43 -0
- data/trocla.gemspec +29 -26
- metadata +58 -12
- data/.travis.yml +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2d6d84b42cc62b4ab04eea0478d9e4801939c1d31accd0dba4a27e272f56dad2
|
4
|
+
data.tar.gz: 6a322a8ae343b6723476b53e9ff7158adaa8d1537bbb46fbc81ef5ebd5a6cff2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9bf44101c733c550f2ca6cd76e9a3788e8e2ac9f44576af255f6ea42271b0cb0cc6c004c6d66c9a4c49e5d74ab647e1cfc8f52bf1c0944176e5e529334effd11
|
7
|
+
data.tar.gz: d8e988c515297525975ca3b2339cfe81ba21444cf45c42637131d3f949871ab6a993f30b62ac2992d8388a2874bf8d4d43fcc9714383ac55fb22ad176f340dbc
|
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
name: Ruby
|
3
|
+
on: [push, pull_request]
|
4
|
+
jobs:
|
5
|
+
spec:
|
6
|
+
runs-on: ubuntu-latest
|
7
|
+
steps:
|
8
|
+
- name: check out repository
|
9
|
+
uses: actions/checkout@v3
|
10
|
+
- name: set up Ruby
|
11
|
+
uses: ruby/setup-ruby@v1
|
12
|
+
with:
|
13
|
+
bundler-cache: true
|
14
|
+
ruby-version: ${{ matrix.ruby }}
|
15
|
+
- name: install dependencies
|
16
|
+
run: bundle install
|
17
|
+
- name: install wireguard
|
18
|
+
run: sudo apt install -y wireguard
|
19
|
+
- name: run rspec
|
20
|
+
run: bundle exec rake spec
|
21
|
+
strategy:
|
22
|
+
fail-fast: false
|
23
|
+
matrix:
|
24
|
+
ruby: [2.5, 2.7, 3.0, 3.1]
|
data/.rspec
CHANGED
@@ -1 +1 @@
|
|
1
|
-
--color
|
1
|
+
--color --format documentation
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,28 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## to 0.5.0
|
4
|
+
|
5
|
+
* moved from travis ci to github actions (#73) - Thank you [Georg-g](https://github.com/geor-g)
|
6
|
+
* Support expire in vault (#71) - Thank you [Steffy Fort](https://github.com/fe80)
|
7
|
+
* Syntax improvements (#70) - Thank you [Steffy Fort](https://github.com/fe80)
|
8
|
+
* Add SCRAM-SHA-256 postgres support (#69) - Thank you [Steffy Fort](https://github.com/fe80)
|
9
|
+
* Support destroying and entry to properly clean up in vault (#68) - Thank you [Steffy Fort](https://github.com/fe80)
|
10
|
+
* Support search with vault backend (#67) - Thank you [Steffy Fort](https://github.com/fe80)
|
11
|
+
* Add wireguard format (#65) - Thank you [Jonas Genannt](https://github.com/hggh)
|
12
|
+
* Expand search path for sample config - Thank you [Anarcat](https://github.com/anarcat)
|
13
|
+
|
14
|
+
## to 0.4.0
|
15
|
+
|
16
|
+
* Add vault backend (#61) - Thank you [Steffy Fort](https://github.com/fe80)
|
17
|
+
* Add sshkey format similar to the OpenSSL - Thank you [Raphaël Rondeau](https://github.com/rrondeau)
|
18
|
+
* format/x509 allow to render 'publickeyonly' (#62) - Thank you [Thomas Weißschuh](https://github.com/t-8ch)
|
19
|
+
* Add a method to search for keys and list all formats of a key (#49) - Thank you - [Steffy Fort](https://github.com/fe80)
|
20
|
+
* Proper return code on cli (#57) - Thank you [Steffy Fort](https://github.com/fe80)
|
21
|
+
* expand search path for sample config file to fix autopkgtest (#64) - Thank you [anarcat](https://github.com/anarcat)
|
22
|
+
* drop support for ruby < 2.7 & update dependencies
|
23
|
+
* skip self-signed cert verification test on newer openssl version (#63)
|
24
|
+
* Fix reseting passwords when using SSL encryption (#52)
|
25
|
+
|
3
26
|
## to 0.3.0
|
4
27
|
|
5
28
|
* Add open method to be able to immediately close a trocla store after using it - thanks martinpfeiffer
|
data/Gemfile
CHANGED
@@ -1,50 +1,24 @@
|
|
1
|
-
source
|
1
|
+
source 'http://rubygems.org'
|
2
2
|
# Add dependencies required to use your gem here.
|
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 'highline', '~> 2.0.0'
|
7
|
+
gem 'moneta', '~> 1.4.0'
|
23
8
|
|
24
9
|
if defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'jruby')
|
25
10
|
gem 'jruby-openssl'
|
26
11
|
end
|
27
|
-
gem
|
12
|
+
gem 'bcrypt'
|
13
|
+
gem 'openssl'
|
14
|
+
gem 'sshkey'
|
28
15
|
|
29
16
|
# Add dependencies to develop your gem here.
|
30
17
|
# Include everything needed to run rake, tests, features, etc.
|
31
18
|
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
|
19
|
+
gem 'addressable'
|
20
|
+
gem 'jeweler'
|
21
|
+
gem 'rdoc'
|
22
|
+
gem 'rspec'
|
49
23
|
gem 'rspec-pending_for'
|
50
24
|
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
|
@@ -165,8 +165,9 @@ options to work properly. These are documented here:
|
|
165
165
|
|
166
166
|
### pgsql
|
167
167
|
|
168
|
-
Password hashes for PostgreSQL servers.
|
169
|
-
|
168
|
+
Password hashes for PostgreSQL servers. Since postgesql 10 you can use the sha256 hash, you have two options:
|
169
|
+
* Create a ssh256 hash password with option `encode: sha256` (default value)
|
170
|
+
* Create a md5 hash, the username is require for the salt key, with option `encode: md5` and `username: your_user`
|
170
171
|
|
171
172
|
### bcrypt
|
172
173
|
|
@@ -212,8 +213,36 @@ Additional options are:
|
|
212
213
|
|
213
214
|
Output render options are:
|
214
215
|
|
215
|
-
certonly
|
216
|
-
keyonly
|
216
|
+
certonly If set to true the x509 format will return only the certificate
|
217
|
+
keyonly If set to true the x509 format will return only the private key
|
218
|
+
publickeyonly If set to true the x509 format will return only the public key
|
219
|
+
|
220
|
+
### sshkey
|
221
|
+
|
222
|
+
This format generate a ssh keypair
|
223
|
+
|
224
|
+
Additional options are:
|
225
|
+
|
226
|
+
type The ssh key type (rsa, dsa). Default: rsa
|
227
|
+
bits Specifies the number of bits in the key to create. Default: 2048
|
228
|
+
comment Specifies a comment.
|
229
|
+
passphrase Specifies a passphrase.
|
230
|
+
|
231
|
+
Output render options are:
|
232
|
+
|
233
|
+
pubonly If set to true the sshkey format will return only the ssh public key
|
234
|
+
privonly If set to true the sshkey format will return only the ssh private key
|
235
|
+
|
236
|
+
### wireguard
|
237
|
+
|
238
|
+
This format generate a keypair for WireGuard.
|
239
|
+
|
240
|
+
The format requires the wg binary from WireGuard userland utilities.
|
241
|
+
|
242
|
+
Output render options are:
|
243
|
+
|
244
|
+
pubonly If set to true the wireguard format will return only the public key
|
245
|
+
privonly If set to true the wireguard format will return only the private key
|
217
246
|
|
218
247
|
## Installation
|
219
248
|
|
@@ -256,6 +285,7 @@ Such a store is a simple class that implements Trocla::Store and at the moment t
|
|
256
285
|
|
257
286
|
* Moneta - the default store using [moneta](https://rubygems.org/gems/moneta) to delegate storing the values
|
258
287
|
* Memory - simple inmemory backend. Mainly used for testing.
|
288
|
+
* Vault - modern secrets storage by HashiCorp, require the ruby gem [vault](https://github.com/hashicorp/vault-ruby)
|
259
289
|
|
260
290
|
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
291
|
|
@@ -272,6 +302,8 @@ We expect storage backends to implement support for the `expires` option, so tha
|
|
272
302
|
|
273
303
|
New backends should be tested using the provided shared example.
|
274
304
|
|
305
|
+
> **WARNING**: Vault backend use metadatas. It's set if an option is define. `expire` is automaticly change to `delete_version_after`, and you can use an interger or [format string](https://www.vaultproject.io/api-docs/secret/kv/kv-v2#parameters)
|
306
|
+
|
275
307
|
#### Moneta backends
|
276
308
|
|
277
309
|
Trocla uses moneta as its default storage backend and hence can store your passwords in any of moneta's supported backends. By default it uses the yaml backend, which is configured as followed:
|
@@ -298,6 +330,33 @@ store_options:
|
|
298
330
|
|
299
331
|
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
332
|
|
333
|
+
#### Vault backend
|
334
|
+
|
335
|
+
[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.
|
336
|
+
|
337
|
+
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...).
|
338
|
+
|
339
|
+
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.
|
340
|
+
|
341
|
+
With vault storage, the terminology changes:
|
342
|
+
* `mount`, this is the name of your kv engine
|
343
|
+
* `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
|
344
|
+
* `secret`, is the data content of your key. This is a simple hash with key (format) and value (the secret content of your format)
|
345
|
+
|
346
|
+
The trocla mapping works the same way as with a moneta or file backend.
|
347
|
+
|
348
|
+
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.
|
349
|
+
|
350
|
+
```YAML
|
351
|
+
store: :vault
|
352
|
+
store_options:
|
353
|
+
:mount: kv
|
354
|
+
:token: s.Tok3n
|
355
|
+
:address: https://vault.local
|
356
|
+
```
|
357
|
+
|
358
|
+
With Vault when you delete a key, you don't delete all key content. The metadatas, like history, are still here and the endpoint are not delete. If you prefere to destroy all key content you can add `:destroy: true` in the `store_options:` hash.
|
359
|
+
|
301
360
|
### Backend encryption
|
302
361
|
|
303
362
|
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
@@ -43,25 +43,25 @@ OptionParser.new do |opts|
|
|
43
43
|
options[:ask_password] = false
|
44
44
|
options[:password] = pass
|
45
45
|
end
|
46
|
-
|
47
46
|
end.parse!
|
48
47
|
|
49
48
|
def create(options)
|
50
|
-
[
|
49
|
+
[Trocla.new(options.delete(:config_file)).password(
|
51
50
|
options.delete(:trocla_key),
|
52
51
|
options.delete(:trocla_format),
|
53
|
-
options.merge(YAML.
|
54
|
-
)
|
52
|
+
options.merge(YAML.safe_load(options.delete(:other_options).shift.to_s) || {})
|
53
|
+
), 0]
|
55
54
|
end
|
56
55
|
|
57
56
|
def get(options)
|
58
57
|
res = Trocla.new(options.delete(:config_file)).get_password(
|
59
58
|
options.delete(:trocla_key),
|
60
59
|
options.delete(:trocla_format),
|
61
|
-
options.merge(YAML.
|
60
|
+
options.merge(YAML.safe_load(options.delete(:other_options).shift.to_s) || {})
|
62
61
|
)
|
63
|
-
[
|
62
|
+
[res, res.nil? ? 1 : 0]
|
64
63
|
end
|
64
|
+
|
65
65
|
def set(options)
|
66
66
|
if options.delete(:ask_password)
|
67
67
|
require 'highline/import'
|
@@ -69,7 +69,7 @@ def set(options)
|
|
69
69
|
pwd2 = ask('Repeat password: ') { |q| q.echo = 'x' }.to_s
|
70
70
|
unless password == pwd2
|
71
71
|
STDERR.puts 'Passwords did not match, exiting!'
|
72
|
-
return [
|
72
|
+
return [nil, 1]
|
73
73
|
end
|
74
74
|
else
|
75
75
|
password = options.delete(:password) || STDIN.read.chomp
|
@@ -78,35 +78,52 @@ def set(options)
|
|
78
78
|
no_format = options.delete('no_format')
|
79
79
|
trocla = Trocla.new(options.delete(:config_file))
|
80
80
|
value = if no_format
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
81
|
+
password
|
82
|
+
else
|
83
|
+
trocla.formats(format).format(password, (YAML.safe_load(options.delete(:other_options).shift.to_s) || {}))
|
84
|
+
end
|
85
85
|
trocla.set_password(
|
86
86
|
options.delete(:trocla_key),
|
87
87
|
format,
|
88
88
|
value
|
89
89
|
)
|
90
|
-
[
|
90
|
+
['', 0]
|
91
91
|
end
|
92
92
|
|
93
93
|
def reset(options)
|
94
|
-
[
|
94
|
+
[Trocla.new(options.delete(:config_file)).reset_password(
|
95
95
|
options.delete(:trocla_key),
|
96
96
|
options.delete(:trocla_format),
|
97
|
-
options.merge(YAML.
|
98
|
-
), 0
|
97
|
+
options.merge(YAML.safe_load(options.delete(:other_options).shift.to_s) || {})
|
98
|
+
), 0]
|
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.safe_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,30 +136,30 @@ def check_format(format_name)
|
|
119
136
|
end
|
120
137
|
end
|
121
138
|
|
122
|
-
actions=['create','get','set','reset','delete', 'formats' ]
|
139
|
+
actions = ['create', 'get', 'set', 'reset', 'delete', 'formats', 'search']
|
123
140
|
|
124
141
|
if (action=ARGV.shift) && actions.include?(action)
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
end
|
134
|
-
rescue Exception => e
|
135
|
-
unless e.message == 'exit'
|
136
|
-
STDERR.puts "Action failed with the following message: #{e.message}"
|
137
|
-
STDERR.puts '(See full trace by running task with --trace)'
|
138
|
-
end
|
139
|
-
raise e if options[:trace]
|
140
|
-
exit 1
|
142
|
+
options[:trocla_key] = ARGV.shift
|
143
|
+
options[:trocla_format] = ARGV.shift
|
144
|
+
options[:other_options] = ARGV
|
145
|
+
check_format(options[:trocla_format]) unless ['delete','formats','search'].include?(action)
|
146
|
+
begin
|
147
|
+
result, excode = send(action, options)
|
148
|
+
if result
|
149
|
+
puts result.is_a?(String) ? result : result.inspect
|
141
150
|
end
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
151
|
+
rescue Exception => e
|
152
|
+
unless e.message == 'exit'
|
153
|
+
STDERR.puts "Action failed with the following message: #{e.message}"
|
154
|
+
STDERR.puts '(See full trace by running task with --trace)'
|
155
|
+
end
|
156
|
+
raise e if options[:trace]
|
157
|
+
|
146
158
|
exit 1
|
159
|
+
end
|
160
|
+
exit excode.nil? ? 0 : excode
|
161
|
+
else
|
162
|
+
STDERR.puts "Please supply one of the following actions: #{actions.join(', ')}"
|
163
|
+
STDERR.puts "Use #{$0} --help to get a list of options for these actions"
|
164
|
+
exit 1
|
147
165
|
end
|
148
|
-
|
data/lib/VERSION
CHANGED
@@ -5,7 +5,7 @@ class Trocla::Encryptions::Ssl < Trocla::Encryptions::Base
|
|
5
5
|
def encrypt(value)
|
6
6
|
ciphertext = ''
|
7
7
|
value.scan(/.{0,#{chunksize}}/m).each do |chunk|
|
8
|
-
ciphertext += Base64.encode64(public_key.public_encrypt(chunk)).gsub("\n",'')+"\n" if chunk
|
8
|
+
ciphertext += Base64.encode64(public_key.public_encrypt(chunk)).gsub("\n", '') + "\n" if chunk
|
9
9
|
end
|
10
10
|
ciphertext
|
11
11
|
end
|
@@ -21,21 +21,21 @@ class Trocla::Encryptions::Ssl < Trocla::Encryptions::Base
|
|
21
21
|
private
|
22
22
|
|
23
23
|
def chunksize
|
24
|
-
|
24
|
+
public_key.n.num_bytes - 11
|
25
25
|
end
|
26
26
|
|
27
27
|
def private_key
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
@private_key ||= begin
|
29
|
+
file = require_option(:private_key)
|
30
|
+
OpenSSL::PKey::RSA.new(File.read(file), nil)
|
31
|
+
end
|
32
32
|
end
|
33
33
|
|
34
34
|
def public_key
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
@public_key ||= begin
|
36
|
+
file = require_option(:public_key)
|
37
|
+
OpenSSL::PKey::RSA.new(File.read(file), nil)
|
38
|
+
end
|
39
39
|
end
|
40
40
|
|
41
41
|
def option(key)
|
@@ -45,7 +45,7 @@ class Trocla::Encryptions::Ssl < Trocla::Encryptions::Base
|
|
45
45
|
def require_option(key)
|
46
46
|
val = option(key)
|
47
47
|
raise "Config error: 'ssl_options' => :#{key} is not defined" if val.nil?
|
48
|
+
|
48
49
|
val
|
49
50
|
end
|
50
51
|
end
|
51
|
-
|
data/lib/trocla/encryptions.rb
CHANGED
@@ -1,18 +1,24 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Trocla::Encryptions
|
4
|
+
class Trocla::Encryptions
|
5
|
+
# Base
|
3
6
|
class Base
|
4
7
|
attr_reader :trocla, :config
|
8
|
+
|
5
9
|
def initialize(config, trocla)
|
6
10
|
@trocla = trocla
|
7
11
|
@config = config
|
8
12
|
end
|
9
13
|
|
10
|
-
def encrypt(
|
14
|
+
def encrypt(_)
|
11
15
|
raise NoMethodError.new("#{self.class.name} needs to implement 'encrypt()'")
|
16
|
+
|
12
17
|
end
|
13
18
|
|
14
|
-
def decrypt(
|
19
|
+
def decrypt(_)
|
15
20
|
raise NoMethodError.new("#{self.class.name} needs to implement 'decrypt()'")
|
21
|
+
|
16
22
|
end
|
17
23
|
end
|
18
24
|
|
@@ -22,7 +28,7 @@ class Trocla::Encryptions
|
|
22
28
|
end
|
23
29
|
|
24
30
|
def all
|
25
|
-
Dir[
|
31
|
+
Dir[path '*'].collect do |enc|
|
26
32
|
File.basename(enc, '.rb').downcase
|
27
33
|
end
|
28
34
|
end
|
@@ -32,10 +38,11 @@ class Trocla::Encryptions
|
|
32
38
|
end
|
33
39
|
|
34
40
|
private
|
41
|
+
|
35
42
|
def encryptions
|
36
43
|
@@encryptions ||= Hash.new do |hash, encryption|
|
37
44
|
encryption = encryption.to_s.downcase
|
38
|
-
if File.
|
45
|
+
if File.exist?(path encryption)
|
39
46
|
require "trocla/encryptions/#{encryption}"
|
40
47
|
class_name = "Trocla::Encryptions::#{encryption.capitalize}"
|
41
48
|
hash[encryption] = (eval class_name)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class Trocla::Formats::Bcrypt < Trocla::Formats::Base
|
2
2
|
expensive true
|
3
3
|
require 'bcrypt'
|
4
|
-
def format(plain_password,options={})
|
5
|
-
BCrypt::Password.create(plain_password, :cost => options['cost']||BCrypt::Engine.cost).to_s
|
4
|
+
def format(plain_password, options = {})
|
5
|
+
BCrypt::Password.create(plain_password, :cost => options['cost'] || BCrypt::Engine.cost).to_s
|
6
6
|
end
|
7
7
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# salted crypt
|
2
2
|
class Trocla::Formats::Md5crypt < Trocla::Formats::Base
|
3
|
-
def format(plain_password,options={})
|
4
|
-
|
3
|
+
def format(plain_password, options = {})
|
4
|
+
plain_password.crypt('$1$' << Trocla::Util.salt << '$')
|
5
5
|
end
|
6
6
|
end
|
data/lib/trocla/formats/mysql.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Trocla::Formats::Mysql < Trocla::Formats::Base
|
2
2
|
require 'digest/sha1'
|
3
|
-
def format(plain_password,options={})
|
4
|
-
|
3
|
+
def format(plain_password, options = {})
|
4
|
+
'*' + Digest::SHA1.hexdigest(Digest::SHA1.digest(plain_password)).upcase
|
5
5
|
end
|
6
6
|
end
|
data/lib/trocla/formats/pgsql.rb
CHANGED
@@ -1,7 +1,54 @@
|
|
1
1
|
class Trocla::Formats::Pgsql < Trocla::Formats::Base
|
2
2
|
require 'digest/md5'
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
require 'openssl'
|
4
|
+
require 'base64'
|
5
|
+
def format(plain_password, options = {})
|
6
|
+
encode = (options['encode'] || 'sha256')
|
7
|
+
case encode
|
8
|
+
when 'md5'
|
9
|
+
raise 'You need pass the username as an option to use this format' unless options['username']
|
10
|
+
|
11
|
+
'md5' + Digest::MD5.hexdigest(plain_password + options['username'])
|
12
|
+
when 'sha256'
|
13
|
+
pg_sha256(plain_password)
|
14
|
+
else
|
15
|
+
raise 'Unkmow encode %s for pgsql password' % [encode]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def pg_sha256(password)
|
22
|
+
salt = OpenSSL::Random.random_bytes(16)
|
23
|
+
digest = digest_key(password, salt)
|
24
|
+
'SCRAM-SHA-256$%s:%s$%s:%s' % [
|
25
|
+
'4096',
|
26
|
+
Base64.strict_encode64(salt),
|
27
|
+
Base64.strict_encode64(client_key(digest)),
|
28
|
+
Base64.strict_encode64(server_key(digest))
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
def digest_key(password, salt)
|
33
|
+
OpenSSL::KDF.pbkdf2_hmac(
|
34
|
+
password,
|
35
|
+
salt: salt,
|
36
|
+
iterations: 4096,
|
37
|
+
length: 32,
|
38
|
+
hash: OpenSSL::Digest::SHA256.new
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def client_key(digest_key)
|
43
|
+
hmac = OpenSSL::HMAC.new(digest_key, OpenSSL::Digest::SHA256.new)
|
44
|
+
hmac << 'Client Key'
|
45
|
+
hmac.digest
|
46
|
+
OpenSSL::Digest.new('SHA256').digest hmac.digest
|
47
|
+
end
|
48
|
+
|
49
|
+
def server_key(digest_key)
|
50
|
+
hmac = OpenSSL::HMAC.new(digest_key, OpenSSL::Digest::SHA256.new)
|
51
|
+
hmac << 'Server Key'
|
52
|
+
hmac.digest
|
6
53
|
end
|
7
54
|
end
|
data/lib/trocla/formats/plain.rb
CHANGED
data/lib/trocla/formats/sha1.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# salted crypt
|
2
2
|
class Trocla::Formats::Sha256crypt < Trocla::Formats::Base
|
3
|
-
def format(plain_password,options={})
|
4
|
-
|
3
|
+
def format(plain_password, options = {})
|
4
|
+
plain_password.crypt('$5$' << Trocla::Util.salt << '$')
|
5
5
|
end
|
6
6
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# salted crypt
|
2
2
|
class Trocla::Formats::Sha512crypt < Trocla::Formats::Base
|
3
|
-
def format(plain_password,options={})
|
4
|
-
|
3
|
+
def format(plain_password, options = {})
|
4
|
+
plain_password.crypt('$6$' << Trocla::Util.salt << '$')
|
5
5
|
end
|
6
6
|
end
|