trocla 0.4.0 → 0.5.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.
@@ -1,8 +1,9 @@
1
1
  require 'openssl'
2
+
3
+ # Trocla::Formats::X509
2
4
  class Trocla::Formats::X509 < Trocla::Formats::Base
3
5
  expensive true
4
6
  def format(plain_password,options={})
5
-
6
7
  if plain_password.match(/-----BEGIN RSA PRIVATE KEY-----.*-----END RSA PRIVATE KEY-----.*-----BEGIN CERTIFICATE-----.*-----END CERTIFICATE-----/m)
7
8
  # just an import, don't generate any new keys
8
9
  return plain_password
@@ -11,17 +12,17 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
11
12
  cn = nil
12
13
  if options['subject']
13
14
  subject = options['subject']
14
- if cna = OpenSSL::X509::Name.parse(subject).to_a.find{|e| e[0] == 'CN' }
15
+ if cna = OpenSSL::X509::Name.parse(subject).to_a.find { |e| e[0] == 'CN' }
15
16
  cn = cna[1]
16
17
  end
17
18
  elsif options['CN']
18
19
  subject = ''
19
20
  cn = options['CN']
20
- ['C','ST','L','O','OU','CN','emailAddress'].each do |field|
21
+ ['C', 'ST', 'L', 'O', 'OU', 'CN', 'emailAddress'].each do |field|
21
22
  subject << "/#{field}=#{options[field]}" if options[field]
22
23
  end
23
24
  else
24
- raise "You need to pass \"subject\" or \"CN\" as an option to use this format"
25
+ raise 'You need to pass "subject" or "CN" as an option to use this format'
25
26
  end
26
27
  hash = options['hash'] || 'sha2'
27
28
  sign_with = options['ca']
@@ -33,17 +34,17 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
33
34
  key_usages = Array(key_usages) if key_usages
34
35
 
35
36
  altnames = if become_ca || (an = options['altnames']) && Array(an).empty?
36
- []
37
- else
38
- # ensure that we have the CN with us, but only if it
39
- # it's like a hostname.
40
- # This might have to be improved.
41
- if cn.include?(' ')
42
- Array(an).collect { |v| "DNS:#{v}" }.join(', ')
43
- else
44
- (["DNS:#{cn}"] + Array(an).collect { |v| "DNS:#{v}" }).uniq.join(', ')
45
- end
46
- end
37
+ []
38
+ else
39
+ # ensure that we have the CN with us, but only if it
40
+ # it's like a hostname.
41
+ # This might have to be improved.
42
+ if cn.include?(' ')
43
+ Array(an).collect { |v| "DNS:#{v}" }.join(', ')
44
+ else
45
+ (["DNS:#{cn}"] + Array(an).collect { |v| "DNS:#{v}" }).uniq.join(', ')
46
+ end
47
+ end
47
48
 
48
49
  begin
49
50
  key = mkkey(keysize)
@@ -55,7 +56,7 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
55
56
  cert = nil
56
57
  if sign_with # certificate signed with CA
57
58
  begin
58
- ca_str = trocla.get_password(sign_with,'x509')
59
+ ca_str = trocla.get_password(sign_with, 'x509')
59
60
  ca = OpenSSL::X509::Certificate.new(ca_str)
60
61
  cakey = OpenSSL::PKey::RSA.new(ca_str)
61
62
  caserial = getserial(sign_with)
@@ -72,8 +73,10 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
72
73
  end
73
74
 
74
75
  begin
75
- cert = mkcert(caserial, request.subject, ca, request.public_key, days,
76
- altnames, key_usages, name_constraints, become_ca)
76
+ cert = mkcert(
77
+ caserial, request.subject, ca, request.public_key, days,
78
+ altnames, key_usages, name_constraints, become_ca
79
+ )
77
80
  cert.sign(cakey, signature(hash))
78
81
  addserial(sign_with, caserial)
79
82
  rescue Exception => e
@@ -82,8 +85,10 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
82
85
  else # self-signed certificate
83
86
  begin
84
87
  subj = OpenSSL::X509::Name.parse(subject)
85
- cert = mkcert(getserial(subj), subj, nil, key.public_key, days,
86
- altnames, key_usages, name_constraints, become_ca)
88
+ cert = mkcert(
89
+ getserial(subj), subj, nil, key.public_key, days,
90
+ altnames, key_usages, name_constraints, become_ca
91
+ )
87
92
  cert.sign(key, signature(hash))
88
93
  rescue Exception => e
89
94
  raise "Self-signed certificate #{subject} creation failed: #{e.message}"
@@ -92,7 +97,7 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
92
97
  key.to_pem + cert.to_pem
93
98
  end
94
99
 
95
- def render(output,render_options={})
100
+ def render(output, render_options = {})
96
101
  if render_options['keyonly']
97
102
  OpenSSL::PKey::RSA.new(output).to_pem
98
103
  elsif render_options['certonly']
@@ -100,26 +105,26 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
100
105
  elsif render_options['publickeyonly']
101
106
  OpenSSL::PKey::RSA.new(output).public_key.to_pem
102
107
  else
103
- super(output,render_options)
108
+ super(output, render_options)
104
109
  end
105
110
  end
106
111
 
107
112
  private
108
- # nice help: https://gist.github.com/mitfik/1922961
109
113
 
114
+ # nice help: https://gist.github.com/mitfik/1922961
110
115
  def signature(hash = 'sha2')
111
116
  if hash == 'sha1'
112
- OpenSSL::Digest::SHA1.new
117
+ OpenSSL::Digest::SHA1.new
113
118
  elsif hash == 'sha224'
114
- OpenSSL::Digest::SHA224.new
119
+ OpenSSL::Digest::SHA224.new
115
120
  elsif hash == 'sha2' || hash == 'sha256'
116
- OpenSSL::Digest::SHA256.new
121
+ OpenSSL::Digest::SHA256.new
117
122
  elsif hash == 'sha384'
118
- OpenSSL::Digest::SHA384.new
123
+ OpenSSL::Digest::SHA384.new
119
124
  elsif hash == 'sha512'
120
- OpenSSL::Digest::SHA512.new
125
+ OpenSSL::Digest::SHA512.new
121
126
  else
122
- raise "Unrecognized hash: #{hash}"
127
+ raise "Unrecognized hash: #{hash}"
123
128
  end
124
129
  end
125
130
 
@@ -127,7 +132,7 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
127
132
  OpenSSL::PKey::RSA.generate(len)
128
133
  end
129
134
 
130
- def mkreq(subject,public_key)
135
+ def mkreq(subject, public_key)
131
136
  request = OpenSSL::X509::Request.new
132
137
  request.subject = subject
133
138
  request.public_key = public_key
@@ -135,9 +140,9 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
135
140
  request
136
141
  end
137
142
 
138
- def mkcert(serial,subject,issuer,public_key,days,altnames, key_usages = nil, name_constraints = [], become_ca = false)
143
+ def mkcert(serial, subject, issuer, public_key, days, altnames, key_usages = nil, name_constraints = [], become_ca = false)
139
144
  cert = OpenSSL::X509::Certificate.new
140
- issuer = cert if issuer == nil
145
+ issuer = cert if issuer.nil?
141
146
  cert.subject = subject
142
147
  cert.issuer = issuer.subject
143
148
  cert.not_before = Time.now
@@ -149,36 +154,36 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
149
154
  ef = OpenSSL::X509::ExtensionFactory.new
150
155
  ef.subject_certificate = cert
151
156
  ef.issuer_certificate = issuer
152
- cert.extensions = [ ef.create_extension("subjectKeyIdentifier", "hash") ]
157
+ cert.extensions = [ef.create_extension('subjectKeyIdentifier', 'hash')]
153
158
 
154
159
  if become_ca
155
- cert.add_extension ef.create_extension("basicConstraints","CA:TRUE", true)
160
+ cert.add_extension ef.create_extension('basicConstraints', 'CA:TRUE', true)
156
161
  unless (ku = key_usages || ca_key_usages).empty?
157
- cert.add_extension ef.create_extension("keyUsage", ku.join(', '), true)
162
+ cert.add_extension ef.create_extension('keyUsage', ku.join(', '), true)
158
163
  end
159
164
  if name_constraints && !name_constraints.empty?
160
- cert.add_extension ef.create_extension("nameConstraints","permitted;DNS:#{name_constraints.join(',permitted;DNS:')}",true)
165
+ cert.add_extension ef.create_extension('nameConstraints', "permitted;DNS:#{name_constraints.join(',permitted;DNS:')}", true)
161
166
  end
162
167
  else
163
- cert.add_extension ef.create_extension("subjectAltName", altnames, true) unless altnames.empty?
164
- cert.add_extension ef.create_extension("basicConstraints","CA:FALSE", true)
168
+ cert.add_extension ef.create_extension('subjectAltName', altnames, true) unless altnames.empty?
169
+ cert.add_extension ef.create_extension('basicConstraints', 'CA:FALSE', true)
165
170
  unless (ku = key_usages || cert_key_usages).empty?
166
- cert.add_extension ef.create_extension("keyUsage", ku.join(', '), true)
171
+ cert.add_extension ef.create_extension('keyUsage', ku.join(', '), true)
167
172
  end
168
173
  end
169
- cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
174
+ cert.add_extension ef.create_extension('authorityKeyIdentifier', 'keyid:always,issuer:always')
170
175
 
171
176
  cert
172
177
  end
173
178
 
174
179
  def getserial(ca)
175
- newser = Trocla::Util.random_str(20,'hexadecimal').to_i(16)
180
+ newser = Trocla::Util.random_str(20, 'hexadecimal').to_i(16)
176
181
  all_serials(ca).include?(newser) ? getserial(ca) : newser
177
182
  end
178
183
 
179
184
  def all_serials(ca)
180
- if allser = trocla.get_password("#{ca}_all_serials",'plain')
181
- YAML.load(allser)
185
+ if allser = trocla.get_password("#{ca}_all_serials", 'plain')
186
+ YAML.safe_load(allser)
182
187
  else
183
188
  []
184
189
  end
@@ -186,14 +191,17 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
186
191
 
187
192
  def addserial(ca,serial)
188
193
  serials = all_serials(ca) << serial
189
- trocla.set_password("#{ca}_all_serials",'plain',YAML.dump(serials))
194
+ trocla.set_password("#{ca}_all_serials", 'plain', YAML.dump(serials))
190
195
  end
191
196
 
192
197
  def cert_key_usages
193
198
  ['nonRepudiation', 'digitalSignature', 'keyEncipherment']
194
199
  end
200
+
195
201
  def ca_key_usages
196
- ['keyCertSign', 'cRLSign', 'nonRepudiation',
197
- 'digitalSignature', 'keyEncipherment' ]
202
+ [
203
+ 'keyCertSign', 'cRLSign', 'nonRepudiation',
204
+ 'digitalSignature', 'keyEncipherment'
205
+ ]
198
206
  end
199
207
  end
@@ -1,13 +1,19 @@
1
- class Trocla::Formats
1
+ # frozen_string_literal: true
2
2
 
3
+ # Trocla::Formats
4
+ class Trocla::Formats
5
+ # Base
3
6
  class Base
4
7
  attr_reader :trocla
8
+
5
9
  def initialize(trocla)
6
10
  @trocla = trocla
7
11
  end
8
- def render(output,render_options={})
12
+
13
+ def render(output, render_options = {})
9
14
  output
10
15
  end
16
+
11
17
  def expensive?
12
18
  self.class.expensive?
13
19
  end
@@ -15,6 +21,7 @@ class Trocla::Formats
15
21
  def expensive(is_expensive)
16
22
  @expensive = is_expensive
17
23
  end
24
+
18
25
  def expensive?
19
26
  @expensive == true
20
27
  end
@@ -27,7 +34,9 @@ class Trocla::Formats
27
34
  end
28
35
 
29
36
  def all
30
- Dir[File.expand_path(File.join(File.dirname(__FILE__),'formats','*.rb'))].collect{|f| File.basename(f,'.rb').downcase }
37
+ Dir[File.expand_path(
38
+ File.join(File.dirname(__FILE__), 'formats', '*.rb')
39
+ )].collect { |f| File.basename(f, '.rb').downcase }
31
40
  end
32
41
 
33
42
  def available?(format)
@@ -35,10 +44,11 @@ class Trocla::Formats
35
44
  end
36
45
 
37
46
  private
47
+
38
48
  def formats
39
49
  @@formats ||= Hash.new do |hash, format|
40
50
  format = format.downcase
41
- if File.exists?(path(format))
51
+ if File.exist?(path(format))
42
52
  require "trocla/formats/#{format}"
43
53
  hash[format] = (eval "Trocla::Formats::#{format.capitalize}")
44
54
  else
@@ -48,7 +58,7 @@ class Trocla::Formats
48
58
  end
49
59
 
50
60
  def path(format)
51
- File.expand_path(File.join(File.dirname(__FILE__),'formats',"#{format}.rb"))
61
+ File.expand_path(File.join(File.dirname(__FILE__), 'formats', "#{format}.rb"))
52
62
  end
53
63
  end
54
64
  end
data/lib/trocla/store.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  # implements the default store behavior
2
2
  class Trocla::Store
3
3
  attr_reader :store_config, :trocla
4
- def initialize(config,trocla)
4
+
5
+ def initialize(config, trocla)
5
6
  @store_config = config
6
7
  @trocla = trocla
7
8
  end
@@ -9,14 +10,13 @@ class Trocla::Store
9
10
  # closes the store
10
11
  # when called do whatever "closes" your
11
12
  # store, e.g. close database connections.
12
- def close
13
- end
13
+ def close; end
14
14
 
15
15
  # should return value for key & format
16
16
  # returns nil if nothing or a nil value
17
17
  # was found.
18
18
  # If a key is expired it must return nil.
19
- def get(key,format)
19
+ def get(key, format)
20
20
  raise 'not implemented'
21
21
  end
22
22
 
@@ -33,11 +33,11 @@ class Trocla::Store
33
33
  # amount of seconds a key can live with.
34
34
  # This mechanism is expected to be
35
35
  # be implemented by the backend.
36
- def set(key,format,value,options={})
36
+ def set(key, format, value, options = {})
37
37
  if format == 'plain'
38
- set_plain(key,value,options)
38
+ set_plain(key, value, options)
39
39
  else
40
- set_format(key,format,value,options)
40
+ set_format(key, format, value, options)
41
41
  end
42
42
  end
43
43
 
@@ -46,30 +46,31 @@ class Trocla::Store
46
46
  # returns value of format or hash of
47
47
  # format => value # if everything is
48
48
  # deleted.
49
- def delete(key,format=nil)
50
- format.nil? ? (delete_all(key)||{}) : delete_format(key,format)
49
+ def delete(key, format = nil)
50
+ format.nil? ? (delete_all(key) || {}) : delete_format(key, format)
51
51
  end
52
52
 
53
53
  # returns all formats for a key
54
- def formats(key)
54
+ def formats(_)
55
55
  raise 'not implemented'
56
56
  end
57
57
 
58
58
  # def searches for a key
59
- def search(key)
59
+ def search(_)
60
60
  raise 'not implemented'
61
61
  end
62
62
 
63
63
  private
64
+
64
65
  # sets a new plain value
65
66
  # *must* invalidate all
66
67
  # other formats
67
- def set_plain(key,value,options)
68
+ def set_plain(key, value, options)
68
69
  raise 'not implemented'
69
70
  end
70
71
 
71
72
  # sets a value of a format
72
- def set_format(key,format,value,options)
73
+ def set_format(key, format, value, options)
73
74
  raise 'not implemented'
74
75
  end
75
76
 
@@ -77,14 +78,14 @@ class Trocla::Store
77
78
  # and returns a hash with all
78
79
  # formats and values
79
80
  # or nil if nothing is found
80
- def delete_all(key)
81
+ def delete_all(_)
81
82
  raise 'not implemented'
82
83
  end
83
84
 
84
85
  # deletes the value of the passed
85
86
  # key & format and returns the
86
87
  # value.
87
- def delete_format(key,format)
88
+ def delete_format(key, format)
88
89
  raise 'not implemented'
89
90
  end
90
91
  end
@@ -1,12 +1,13 @@
1
1
  # a simple in memory store just as an example
2
2
  class Trocla::Stores::Memory < Trocla::Store
3
3
  attr_reader :memory
4
- def initialize(config,trocla)
5
- super(config,trocla)
4
+
5
+ def initialize(config, trocla)
6
+ super(config, trocla)
6
7
  @memory = Hash.new({})
7
8
  end
8
9
 
9
- def get(key,format)
10
+ def get(key, format)
10
11
  unless expired?(key)
11
12
  memory[key][format]
12
13
  else
@@ -14,9 +15,10 @@ class Trocla::Stores::Memory < Trocla::Store
14
15
  nil
15
16
  end
16
17
  end
17
- def set(key,format,value,options={})
18
- super(key,format,value,options)
19
- set_expires(key,options['expires'])
18
+
19
+ def set(key, format, value, options = {})
20
+ super(key, format, value, options)
21
+ set_expires(key, options['expires'])
20
22
  end
21
23
 
22
24
  def formats(key)
@@ -29,25 +31,29 @@ class Trocla::Stores::Memory < Trocla::Store
29
31
  end
30
32
 
31
33
  private
32
- def set_plain(key,value,options)
34
+
35
+ def set_plain(key, value, _)
33
36
  memory[key] = { 'plain' => value }
34
37
  end
35
38
 
36
- def set_format(key,format,value,options)
39
+ def set_format(key, format, value, _)
37
40
  memory[key].merge!({ format => value })
38
41
  end
39
42
 
40
43
  def delete_all(key)
41
44
  memory.delete(key)
42
45
  end
43
- def delete_format(key,format)
46
+
47
+ def delete_format(key, format)
44
48
  old_val = (h = memory[key]).delete(format)
45
49
  h.empty? ? memory.delete(key) : memory[key] = h
46
50
  set_expires(key,nil)
47
51
  old_val
48
52
  end
53
+
49
54
  private
50
- def set_expires(key,expires)
55
+
56
+ def set_expires(key, expires)
51
57
  expires = memory[key]['_expires'] if expires.nil?
52
58
  if expires && expires > 0
53
59
  memory[key]['_expires'] = expires
@@ -57,6 +63,7 @@ class Trocla::Stores::Memory < Trocla::Store
57
63
  memory[key].delete('_expires_at')
58
64
  end
59
65
  end
66
+
60
67
  def expired?(key)
61
68
  memory.key?(key) &&
62
69
  (a = memory[key]['_expires_at']).is_a?(Time) && \
@@ -1,20 +1,22 @@
1
1
  # the default moneta based store
2
2
  class Trocla::Stores::Moneta < Trocla::Store
3
3
  attr_reader :moneta
4
- def initialize(config,trocla)
5
- super(config,trocla)
4
+
5
+ def initialize(config, trocla)
6
+ super(config, trocla)
6
7
  require 'moneta'
7
8
  # load expire support by default
8
- adapter_options = { :expires => true }.merge(
9
- store_config['adapter_options']||{})
10
- @moneta = Moneta.new(store_config['adapter'],adapter_options)
9
+ adapter_options = {
10
+ :expires => true
11
+ }.merge(store_config['adapter_options'] || {})
12
+ @moneta = Moneta.new(store_config['adapter'], adapter_options)
11
13
  end
12
14
 
13
15
  def close
14
16
  moneta.close
15
17
  end
16
18
 
17
- def get(key,format)
19
+ def get(key, format)
18
20
  moneta.fetch(key, {})[format]
19
21
  end
20
22
 
@@ -25,14 +27,16 @@ class Trocla::Stores::Moneta < Trocla::Store
25
27
 
26
28
  def search(key)
27
29
  raise 'The search option is not available for any adapter other than Sequel or YAML' unless store_config['adapter'] == :Sequel || store_config['adapter'] == :YAML
30
+
28
31
  r = search_keys(key)
29
32
  r.empty? ? nil : r
30
33
  end
31
34
 
32
35
  private
33
- def set_plain(key,value,options)
36
+
37
+ def set_plain(key, value, options)
34
38
  h = { 'plain' => value }
35
- mo = moneta_options(key,options)
39
+ mo = moneta_options(key, options)
36
40
  if options['expires'] && options['expires'] > 0
37
41
  h['_expires'] = options['expires']
38
42
  else
@@ -40,24 +44,28 @@ class Trocla::Stores::Moneta < Trocla::Store
40
44
  # expires if nothing is set.
41
45
  mo[:expires] = false
42
46
  end
43
- moneta.store(key,h,mo)
47
+ moneta.store(key, h, mo)
44
48
  end
45
49
 
46
- def set_format(key,format,value,options)
47
- moneta.store(key,
48
- moneta.fetch(key,{}).merge({ format => value }),
49
- moneta_options(key,options))
50
+ def set_format(key, format, value, options)
51
+ moneta.store(
52
+ key,
53
+ moneta.fetch(key, {}).merge({ format => value }),
54
+ moneta_options(key, options)
55
+ )
50
56
  end
51
57
 
52
58
  def delete_all(key)
53
59
  moneta.delete(key)
54
60
  end
55
- def delete_format(key,format)
56
- old_val = (h = moneta.fetch(key,{})).delete(format)
57
- h.empty? ? moneta.delete(key) : moneta.store(key,h,moneta_options(key,{}))
61
+
62
+ def delete_format(key, format)
63
+ old_val = (h = moneta.fetch(key, {})).delete(format)
64
+ h.empty? ? moneta.delete(key) : moneta.store(key, h, moneta_options(key, {}))
58
65
  old_val
59
66
  end
60
- def moneta_options(key,options)
67
+
68
+ def moneta_options(key, options)
61
69
  res = {}
62
70
  if options.key?('expires')
63
71
  res[:expires] = options['expires']
@@ -66,11 +74,13 @@ class Trocla::Stores::Moneta < Trocla::Store
66
74
  end
67
75
  res
68
76
  end
77
+
69
78
  def search_keys(key)
70
- _moneta = Moneta.new(store_config['adapter'], (store_config['adapter_options']||{}).merge({ :expires => false }))
79
+ _moneta = Moneta.new(store_config['adapter'], (store_config['adapter_options'] || {}).merge({ :expires => false }))
71
80
  a = []
81
+
72
82
  if store_config['adapter'] == :Sequel
73
- keys = _moneta.adapter.backend[:trocla].select_order_map {from_base64(:k)}
83
+ keys = _moneta.adapter.backend[:trocla].select_order_map { from_base64(:k) }
74
84
  elsif store_config['adapter'] == :YAML
75
85
  keys = _moneta.adapter.backend.transaction(true) { _moneta.adapter.backend.roots }
76
86
  end
@@ -1,18 +1,19 @@
1
1
  # the default vault based store
2
2
  class Trocla::Stores::Vault < Trocla::Store
3
- attr_reader :vault, :mount
4
- def initialize(config,trocla)
5
- super(config,trocla)
3
+ attr_reader :vault, :mount, :destroy
4
+
5
+ def initialize(config, trocla)
6
+ super(config, trocla)
6
7
  require 'vault'
7
8
  @mount = (config.delete(:mount) || 'kv')
9
+ @destroy = (config.delete(:destroy) || false)
8
10
  # load expire support by default
9
11
  @vault = Vault::Client.new(config)
10
12
  end
11
13
 
12
- def close
13
- end
14
+ def close; end
14
15
 
15
- def get(key,format)
16
+ def get(key, format)
16
17
  read(key)[format.to_sym]
17
18
  end
18
19
 
@@ -20,31 +21,58 @@ class Trocla::Stores::Vault < Trocla::Store
20
21
  read(key).keys
21
22
  end
22
23
 
24
+ def search(key)
25
+ arr = key.split('/')
26
+ regexp = Regexp.new(arr.pop(1)[0].to_s)
27
+ path = arr.join('/')
28
+ list = vault.kv(mount).list(path)
29
+ list.map! do |l|
30
+ if regexp.match(l)
31
+ path.empty? ? l : [path, l].join('/')
32
+ end
33
+ end
34
+ list.compact
35
+ end
36
+
23
37
  private
38
+
24
39
  def read(key)
25
40
  k = vault.kv(mount).read(key)
26
41
  k.nil? ? {} : k.data
27
42
  end
28
43
 
29
- def write(key, value)
44
+ def write(key, value, options = {})
45
+ vault.kv(mount).write_metadata(key, convert_metadata(options)) unless options.empty?
30
46
  vault.kv(mount).write(key, value)
31
47
  end
32
48
 
33
- def set_plain(key,value,options)
34
- set_format(key,'plain',value,options)
49
+ def set_plain(key, value, options)
50
+ set_format(key, 'plain', value, options)
35
51
  end
36
52
 
37
- def set_format(key,format,value,options)
38
- write(key, read(key).merge({format.to_sym => value}))
53
+ def set_format(key, format, value, options)
54
+ write(
55
+ key,
56
+ read(key).merge({ format.to_sym => value }),
57
+ options
58
+ )
39
59
  end
40
60
 
41
61
  def delete_all(key)
42
- vault.kv(mount).delete(key)
62
+ destroy ? vault.kv(mount).destroy(key) : vault.kv(mount).delete(key)
43
63
  end
44
64
 
45
- def delete_format(key,format)
65
+ def delete_format(key, format)
46
66
  old = read(key)
47
- write(key, old.reject { |k,v| k == format.to_sym })
67
+ new = old.reject { |k, _| k == format.to_sym }
68
+ new.empty? ? delete_all(key) : write(key, new)
48
69
  old[format.to_sym]
49
70
  end
71
+
72
+ def convert_metadata(metadatas)
73
+ metadatas.transform_keys!(&:to_sym)
74
+ metadatas[:delete_version_after] = metadatas.delete(:expire) if metadatas[:expire]
75
+ %i[random profiles expires length].each { |k| metadatas.delete(k) }
76
+ metadatas
77
+ end
50
78
  end
data/lib/trocla/stores.rb CHANGED
@@ -7,7 +7,7 @@ class Trocla::Stores
7
7
  end
8
8
 
9
9
  def all
10
- @all ||= Dir[ path '*' ].collect do |store|
10
+ @all ||= Dir[path '*'].collect do |store|
11
11
  File.basename(store, '.rb').downcase
12
12
  end
13
13
  end
@@ -17,10 +17,11 @@ class Trocla::Stores
17
17
  end
18
18
 
19
19
  private
20
+
20
21
  def stores
21
22
  @@stores ||= Hash.new do |hash, store|
22
23
  store = store.to_s.downcase
23
- if File.exists?(path(store))
24
+ if File.exist?(path(store))
24
25
  require "trocla/stores/#{store}"
25
26
  class_name = "Trocla::Stores::#{store.capitalize}"
26
27
  hash[store] = (eval class_name)