trocla 0.3.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.
@@ -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