trocla 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,8 +2,8 @@
2
2
  require 'base64'
3
3
  require 'digest'
4
4
  class Trocla::Formats::Ssha < Trocla::Formats::Base
5
- def format(plain_password,options={})
6
- salt = options['salt'] || Trocla::Util.salt(16)
7
- "{SSHA}"+Base64.encode64("#{Digest::SHA1.digest("#{plain_password}#{salt}")}#{salt}").chomp
5
+ def format(plain_password, options = {})
6
+ salt = options['salt'] || Trocla::Util.salt(16)
7
+ '{SSHA}' + Base64.encode64("#{Digest::SHA1.digest("#{plain_password}#{salt}")}#{salt}").chomp
8
8
  end
9
9
  end
@@ -0,0 +1,42 @@
1
+ require 'sshkey'
2
+
3
+ class Trocla::Formats::Sshkey < Trocla::Formats::Base
4
+ expensive true
5
+
6
+ def format(plain_password,options={})
7
+ if plain_password.match(/-----BEGIN RSA PRIVATE KEY-----.*-----END RSA PRIVATE KEY/m)
8
+ # Import, validate ssh key
9
+ begin
10
+ sshkey = ::SSHKey.new(plain_password)
11
+ rescue Exception => e
12
+ raise "SSH key import failed: #{e.message}"
13
+ end
14
+ return sshkey.private_key + sshkey.ssh_public_key
15
+ end
16
+
17
+ type = options['type'] || 'rsa'
18
+ bits = options['bits'] || 2048
19
+
20
+ begin
21
+ sshkey = ::SSHKey.generate(
22
+ type: type, bits: bits,
23
+ comment: options['comment'],
24
+ passphrase: options['passphrase']
25
+ )
26
+ rescue Exception => e
27
+ raise "SSH key creation failed: #{e.message}"
28
+ end
29
+
30
+ sshkey.private_key + sshkey.ssh_public_key
31
+ end
32
+
33
+ def render(output, render_options = {})
34
+ if render_options['privonly']
35
+ ::SSHKey.new(output).private_key
36
+ elsif render_options['pubonly']
37
+ ::SSHKey.new(output).ssh_public_key
38
+ else
39
+ super(output, render_options)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,45 @@
1
+ require 'open3'
2
+ require 'yaml'
3
+
4
+ class Trocla::Formats::Wireguard < Trocla::Formats::Base
5
+ expensive true
6
+
7
+ def format(plain_password, options={})
8
+ return YAML.safe_load(plain_password) if plain_password.match(/---/)
9
+
10
+ wg_priv = nil
11
+ wg_pub = nil
12
+ begin
13
+ Open3.popen3('wg genkey') do |_stdin, stdout, _stderr, _waiter|
14
+ wg_priv = stdout.read.chomp
15
+ end
16
+ rescue SystemCallError => e
17
+ raise 'trocla wireguard: wg binary not found' if e.message =~ /No such file or directory/
18
+
19
+ raise "trocla wireguard: #{e.message}"
20
+ end
21
+
22
+ begin
23
+ Open3.popen3('wg pubkey') do |stdin, stdout, _stderr, _waiter|
24
+ stdin.write(wg_priv)
25
+ stdin.close
26
+
27
+ wg_pub = stdout.read.chomp
28
+ end
29
+ rescue SystemCallError => e
30
+ raise "trocla wireguard: #{e.message}"
31
+ end
32
+ YAML.dump({ 'wg_priv' => wg_priv, 'wg_pub' => wg_pub })
33
+ end
34
+
35
+ def render(output, render_options = {})
36
+ data = YAML.safe_load(output)
37
+ if render_options['privonly']
38
+ data['wg_priv']
39
+ elsif render_options['pubonly']
40
+ data['wg_pub']
41
+ else
42
+ 'pub: ' + data['wg_pub'] + "\npriv: " + data['wg_priv']
43
+ end
44
+ end
45
+ end
@@ -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,32 +97,34 @@ 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']
99
104
  OpenSSL::X509::Certificate.new(output).to_pem
105
+ elsif render_options['publickeyonly']
106
+ OpenSSL::PKey::RSA.new(output).public_key.to_pem
100
107
  else
101
- super(output,render_options)
108
+ super(output, render_options)
102
109
  end
103
110
  end
104
111
 
105
112
  private
106
- # nice help: https://gist.github.com/mitfik/1922961
107
113
 
114
+ # nice help: https://gist.github.com/mitfik/1922961
108
115
  def signature(hash = 'sha2')
109
116
  if hash == 'sha1'
110
- OpenSSL::Digest::SHA1.new
117
+ OpenSSL::Digest::SHA1.new
111
118
  elsif hash == 'sha224'
112
- OpenSSL::Digest::SHA224.new
119
+ OpenSSL::Digest::SHA224.new
113
120
  elsif hash == 'sha2' || hash == 'sha256'
114
- OpenSSL::Digest::SHA256.new
121
+ OpenSSL::Digest::SHA256.new
115
122
  elsif hash == 'sha384'
116
- OpenSSL::Digest::SHA384.new
123
+ OpenSSL::Digest::SHA384.new
117
124
  elsif hash == 'sha512'
118
- OpenSSL::Digest::SHA512.new
125
+ OpenSSL::Digest::SHA512.new
119
126
  else
120
- raise "Unrecognized hash: #{hash}"
127
+ raise "Unrecognized hash: #{hash}"
121
128
  end
122
129
  end
123
130
 
@@ -125,7 +132,7 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
125
132
  OpenSSL::PKey::RSA.generate(len)
126
133
  end
127
134
 
128
- def mkreq(subject,public_key)
135
+ def mkreq(subject, public_key)
129
136
  request = OpenSSL::X509::Request.new
130
137
  request.subject = subject
131
138
  request.public_key = public_key
@@ -133,9 +140,9 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
133
140
  request
134
141
  end
135
142
 
136
- 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)
137
144
  cert = OpenSSL::X509::Certificate.new
138
- issuer = cert if issuer == nil
145
+ issuer = cert if issuer.nil?
139
146
  cert.subject = subject
140
147
  cert.issuer = issuer.subject
141
148
  cert.not_before = Time.now
@@ -147,36 +154,36 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
147
154
  ef = OpenSSL::X509::ExtensionFactory.new
148
155
  ef.subject_certificate = cert
149
156
  ef.issuer_certificate = issuer
150
- cert.extensions = [ ef.create_extension("subjectKeyIdentifier", "hash") ]
157
+ cert.extensions = [ef.create_extension('subjectKeyIdentifier', 'hash')]
151
158
 
152
159
  if become_ca
153
- cert.add_extension ef.create_extension("basicConstraints","CA:TRUE", true)
160
+ cert.add_extension ef.create_extension('basicConstraints', 'CA:TRUE', true)
154
161
  unless (ku = key_usages || ca_key_usages).empty?
155
- cert.add_extension ef.create_extension("keyUsage", ku.join(', '), true)
162
+ cert.add_extension ef.create_extension('keyUsage', ku.join(', '), true)
156
163
  end
157
164
  if name_constraints && !name_constraints.empty?
158
- 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)
159
166
  end
160
167
  else
161
- cert.add_extension ef.create_extension("subjectAltName", altnames, true) unless altnames.empty?
162
- 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)
163
170
  unless (ku = key_usages || cert_key_usages).empty?
164
- cert.add_extension ef.create_extension("keyUsage", ku.join(', '), true)
171
+ cert.add_extension ef.create_extension('keyUsage', ku.join(', '), true)
165
172
  end
166
173
  end
167
- cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
174
+ cert.add_extension ef.create_extension('authorityKeyIdentifier', 'keyid:always,issuer:always')
168
175
 
169
176
  cert
170
177
  end
171
178
 
172
179
  def getserial(ca)
173
- newser = Trocla::Util.random_str(20,'hexadecimal').to_i(16)
180
+ newser = Trocla::Util.random_str(20, 'hexadecimal').to_i(16)
174
181
  all_serials(ca).include?(newser) ? getserial(ca) : newser
175
182
  end
176
183
 
177
184
  def all_serials(ca)
178
- if allser = trocla.get_password("#{ca}_all_serials",'plain')
179
- YAML.load(allser)
185
+ if allser = trocla.get_password("#{ca}_all_serials", 'plain')
186
+ YAML.safe_load(allser)
180
187
  else
181
188
  []
182
189
  end
@@ -184,14 +191,17 @@ class Trocla::Formats::X509 < Trocla::Formats::Base
184
191
 
185
192
  def addserial(ca,serial)
186
193
  serials = all_serials(ca) << serial
187
- trocla.set_password("#{ca}_all_serials",'plain',YAML.dump(serials))
194
+ trocla.set_password("#{ca}_all_serials", 'plain', YAML.dump(serials))
188
195
  end
189
196
 
190
197
  def cert_key_usages
191
198
  ['nonRepudiation', 'digitalSignature', 'keyEncipherment']
192
199
  end
200
+
193
201
  def ca_key_usages
194
- ['keyCertSign', 'cRLSign', 'nonRepudiation',
195
- 'digitalSignature', 'keyEncipherment' ]
202
+ [
203
+ 'keyCertSign', 'cRLSign', 'nonRepudiation',
204
+ 'digitalSignature', 'keyEncipherment'
205
+ ]
196
206
  end
197
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,20 +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
+ end
52
+
53
+ # returns all formats for a key
54
+ def formats(_)
55
+ raise 'not implemented'
56
+ end
57
+
58
+ # def searches for a key
59
+ def search(_)
60
+ raise 'not implemented'
51
61
  end
52
62
 
53
63
  private
64
+
54
65
  # sets a new plain value
55
66
  # *must* invalidate all
56
67
  # other formats
57
- def set_plain(key,value,options)
68
+ def set_plain(key, value, options)
58
69
  raise 'not implemented'
59
70
  end
60
71
 
61
72
  # sets a value of a format
62
- def set_format(key,format,value,options)
73
+ def set_format(key, format, value, options)
63
74
  raise 'not implemented'
64
75
  end
65
76
 
@@ -67,14 +78,14 @@ class Trocla::Store
67
78
  # and returns a hash with all
68
79
  # formats and values
69
80
  # or nil if nothing is found
70
- def delete_all(key)
81
+ def delete_all(_)
71
82
  raise 'not implemented'
72
83
  end
73
84
 
74
85
  # deletes the value of the passed
75
86
  # key & format and returns the
76
87
  # value.
77
- def delete_format(key,format)
88
+ def delete_format(key, format)
78
89
  raise 'not implemented'
79
90
  end
80
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,31 +15,45 @@ 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'])
22
+ end
23
+
24
+ def formats(key)
25
+ memory[key].empty? ? nil : memory[key].keys
26
+ end
27
+
28
+ def search(key)
29
+ r = memory.keys.grep(/#{key}/)
30
+ r.empty? ? nil : r
20
31
  end
21
32
 
22
33
  private
23
- def set_plain(key,value,options)
34
+
35
+ def set_plain(key, value, _)
24
36
  memory[key] = { 'plain' => value }
25
37
  end
26
38
 
27
- def set_format(key,format,value,options)
39
+ def set_format(key, format, value, _)
28
40
  memory[key].merge!({ format => value })
29
41
  end
30
42
 
31
43
  def delete_all(key)
32
44
  memory.delete(key)
33
45
  end
34
- def delete_format(key,format)
46
+
47
+ def delete_format(key, format)
35
48
  old_val = (h = memory[key]).delete(format)
36
49
  h.empty? ? memory.delete(key) : memory[key] = h
37
50
  set_expires(key,nil)
38
51
  old_val
39
52
  end
53
+
40
54
  private
41
- def set_expires(key,expires)
55
+
56
+ def set_expires(key, expires)
42
57
  expires = memory[key]['_expires'] if expires.nil?
43
58
  if expires && expires > 0
44
59
  memory[key]['_expires'] = expires
@@ -48,6 +63,7 @@ class Trocla::Stores::Memory < Trocla::Store
48
63
  memory[key].delete('_expires_at')
49
64
  end
50
65
  end
66
+
51
67
  def expired?(key)
52
68
  memory.key?(key) &&
53
69
  (a = memory[key]['_expires_at']).is_a?(Time) && \
@@ -1,27 +1,42 @@
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
 
23
+ def formats(key)
24
+ r = moneta.fetch(key)
25
+ r.nil? ? nil : r.keys
26
+ end
27
+
28
+ def search(key)
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
+
31
+ r = search_keys(key)
32
+ r.empty? ? nil : r
33
+ end
34
+
21
35
  private
22
- def set_plain(key,value,options)
36
+
37
+ def set_plain(key, value, options)
23
38
  h = { 'plain' => value }
24
- mo = moneta_options(key,options)
39
+ mo = moneta_options(key, options)
25
40
  if options['expires'] && options['expires'] > 0
26
41
  h['_expires'] = options['expires']
27
42
  else
@@ -29,24 +44,28 @@ class Trocla::Stores::Moneta < Trocla::Store
29
44
  # expires if nothing is set.
30
45
  mo[:expires] = false
31
46
  end
32
- moneta.store(key,h,mo)
47
+ moneta.store(key, h, mo)
33
48
  end
34
49
 
35
- def set_format(key,format,value,options)
36
- moneta.store(key,
37
- moneta.fetch(key,{}).merge({ format => value }),
38
- 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
+ )
39
56
  end
40
57
 
41
58
  def delete_all(key)
42
59
  moneta.delete(key)
43
60
  end
44
- def delete_format(key,format)
45
- old_val = (h = moneta.fetch(key,{})).delete(format)
46
- 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, {}))
47
65
  old_val
48
66
  end
49
- def moneta_options(key,options)
67
+
68
+ def moneta_options(key, options)
50
69
  res = {}
51
70
  if options.key?('expires')
52
71
  res[:expires] = options['expires']
@@ -55,4 +74,21 @@ class Trocla::Stores::Moneta < Trocla::Store
55
74
  end
56
75
  res
57
76
  end
77
+
78
+ def search_keys(key)
79
+ _moneta = Moneta.new(store_config['adapter'], (store_config['adapter_options'] || {}).merge({ :expires => false }))
80
+ a = []
81
+
82
+ if store_config['adapter'] == :Sequel
83
+ keys = _moneta.adapter.backend[:trocla].select_order_map { from_base64(:k) }
84
+ elsif store_config['adapter'] == :YAML
85
+ keys = _moneta.adapter.backend.transaction(true) { _moneta.adapter.backend.roots }
86
+ end
87
+ _moneta.close
88
+ regexp = Regexp.new("#{key}")
89
+ keys.each do |k|
90
+ a << k if regexp.match(k)
91
+ end
92
+ a
93
+ end
58
94
  end