summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormh <mh@immerda.ch>2014-06-27 19:23:20 +0200
committermh <mh@immerda.ch>2014-06-27 19:23:20 +0200
commitecb2a2c7c6ec3576bc49747a484fa0f8e93a50fa (patch)
tree05ccf120e136b3d6d77a8d91f9930f0139b8e54b
parent20de208ee827cb451e60705180909ce81eae0127 (diff)
parent08ac533d2156b666ae6ca68e797992629051315f (diff)
Merge branch 'tilya-charset_option'
-rwxr-xr-xbin/trocla5
-rw-r--r--lib/trocla.rb38
-rw-r--r--lib/trocla/default_config.yaml1
-rw-r--r--lib/trocla/formats.rb20
-rw-r--r--lib/trocla/formats/bcrypt.rb2
-rw-r--r--lib/trocla/formats/md5crypt.rb2
-rw-r--r--lib/trocla/formats/mysql.rb4
-rw-r--r--lib/trocla/formats/pgsql.rb2
-rw-r--r--lib/trocla/formats/plain.rb4
-rw-r--r--lib/trocla/formats/sha1.rb7
-rw-r--r--lib/trocla/formats/sha256crypt.rb2
-rw-r--r--lib/trocla/formats/sha512crypt.rb2
-rw-r--r--lib/trocla/formats/ssha.rb2
-rw-r--r--lib/trocla/formats/x509.rb118
-rw-r--r--lib/trocla/util.rb32
15 files changed, 133 insertions, 108 deletions
diff --git a/bin/trocla b/bin/trocla
index dd32f84..6949318 100755
--- a/bin/trocla
+++ b/bin/trocla
@@ -65,10 +65,11 @@ def set(options)
password = options.delete(:password) || STDIN.read.chomp
end
format = options.delete(:trocla_format)
- Trocla.new(options.delete(:config_file)).set_password(
+ trocla = Trocla.new(options.delete(:config_file))
+ trocla.set_password(
options.delete(:trocla_key),
format,
- Trocla::Formats[format].format(password, options.delete(:other_options).shift.to_s)
+ trocla.formats(format).format(password, options.delete(:other_options).shift.to_s)
)
""
end
diff --git a/lib/trocla.rb b/lib/trocla.rb
index 74825aa..8d916b2 100644
--- a/lib/trocla.rb
+++ b/lib/trocla.rb
@@ -3,11 +3,11 @@ require 'trocla/util'
require 'trocla/formats'
class Trocla
-
+
def initialize(config_file=nil)
if config_file
@config_file = File.expand_path(config_file)
- elsif File.exists?(def_config_file=File.expand_path('~/.troclarc.yaml')) || File.exists?(def_config_file=File.expand_path('/etc/troclarc.yaml'))
+ elsif File.exists?(def_config_file=File.expand_path('~/.troclarc.yaml')) || File.exists?(def_config_file=File.expand_path('/etc/troclarc.yaml'))
@config_file = def_config_file
end
end
@@ -20,27 +20,27 @@ class Trocla
return password
end
- plain_pwd = get_password(key,'plain')
+ plain_pwd = get_password(key,'plain')
if options['random'] && plain_pwd.nil?
- plain_pwd = Trocla::Util.random_str(options['length'].to_i,options['shellsafe'])
- set_password(key,'plain',plain_pwd) unless format == 'plain'
+ plain_pwd = Trocla::Util.random_str(options['length'].to_i,options['charset'])
+ set_password(key,'plain',plain_pwd) unless format == 'plain'
elsif !options['random'] && plain_pwd.nil?
raise "Password must be present as plaintext if you don't want a random password"
end
- set_password(key,format,Trocla::Formats[format].format(plain_pwd,options))
+ set_password(key,format,self.formats(format).format(plain_pwd,options))
end
-
+
def get_password(key,format)
cache.fetch(key,{})[format]
end
-
+
def reset_password(key,format,options={})
set_password(key,format,nil)
password(key,format,options)
end
-
+
def delete_password(key,format=nil)
- if format.nil?
+ if format.nil?
cache.delete(key)
else
old_val = (h = cache.fetch(key,{})).delete(format)
@@ -48,7 +48,7 @@ class Trocla
old_val
end
end
-
+
def set_password(key,format,password)
if (format == 'plain')
h = (cache[key] = { 'plain' => password })
@@ -57,22 +57,26 @@ class Trocla
end
h[format]
end
-
+
+ def formats(format)
+ (@format_cache||={})[format] ||= Trocla::Formats[format].new(self)
+ end
+
private
def cache
@cache ||= build_cache
end
-
+
def build_cache
require 'moneta'
lconfig = config
Moneta.new(lconfig['adapter'], lconfig['adapter_options']||{})
end
-
+
def config
@config ||= read_config
end
-
+
def read_config
if @config_file.nil?
default_config
@@ -81,10 +85,10 @@ class Trocla
default_config.merge(YAML.load(File.read(@config_file)))
end
end
-
+
def default_config
require 'yaml'
YAML.load(File.read(File.expand_path(File.join(File.dirname(__FILE__),'trocla','default_config.yaml'))))
end
-
+
end
diff --git a/lib/trocla/default_config.yaml b/lib/trocla/default_config.yaml
index f46568f..d4037fd 100644
--- a/lib/trocla/default_config.yaml
+++ b/lib/trocla/default_config.yaml
@@ -2,6 +2,7 @@
options:
random: true
length: 12
+ charset: default
adapter: :YAML
adapter_options:
:file: '/tmp/trocla.yaml'
diff --git a/lib/trocla/formats.rb b/lib/trocla/formats.rb
index 3cf31bd..0103c4e 100644
--- a/lib/trocla/formats.rb
+++ b/lib/trocla/formats.rb
@@ -1,32 +1,40 @@
class Trocla::Formats
+
+ class Base
+ attr_reader :trocla
+ def initialize(trocla)
+ @trocla = trocla
+ end
+ end
+
class << self
def [](format)
formats[format.downcase]
end
-
+
def all
Dir[File.expand_path(File.join(File.dirname(__FILE__),'formats','*.rb'))].collect{|f| File.basename(f,'.rb').downcase }
end
-
+
def available?(format)
all.include?(format.downcase)
end
-
+
private
def formats
@@formats ||= Hash.new do |hash, format|
format = format.downcase
if File.exists?(path(format))
require "trocla/formats/#{format}"
- hash[format] = (eval "Trocla::Formats::#{format.capitalize}").new
+ hash[format] = (eval "Trocla::Formats::#{format.capitalize}")
else
raise "Format #{format} is not supported!"
end
end
end
-
+
def path(format)
File.expand_path(File.join(File.dirname(__FILE__),'formats',"#{format}.rb"))
end
end
-end \ No newline at end of file
+end
diff --git a/lib/trocla/formats/bcrypt.rb b/lib/trocla/formats/bcrypt.rb
index 7196e54..4b6fb33 100644
--- a/lib/trocla/formats/bcrypt.rb
+++ b/lib/trocla/formats/bcrypt.rb
@@ -1,4 +1,4 @@
-class Trocla::Formats::Bcrypt
+class Trocla::Formats::Bcrypt < Trocla::Formats::Base
require 'bcrypt'
def format(plain_password,options={})
BCrypt::Password.create(plain_password).to_s
diff --git a/lib/trocla/formats/md5crypt.rb b/lib/trocla/formats/md5crypt.rb
index 36e3a3c..80d2f09 100644
--- a/lib/trocla/formats/md5crypt.rb
+++ b/lib/trocla/formats/md5crypt.rb
@@ -1,5 +1,5 @@
# salted crypt
-class Trocla::Formats::Md5crypt
+class Trocla::Formats::Md5crypt < Trocla::Formats::Base
def format(plain_password,options={})
plain_password.crypt('$1$' << Trocla::Util.salt << '$')
end
diff --git a/lib/trocla/formats/mysql.rb b/lib/trocla/formats/mysql.rb
index 7fbc3a7..a097f95 100644
--- a/lib/trocla/formats/mysql.rb
+++ b/lib/trocla/formats/mysql.rb
@@ -1,6 +1,6 @@
-class Trocla::Formats::Mysql
+class Trocla::Formats::Mysql < Trocla::Formats::Base
require 'digest/sha1'
def format(plain_password,options={})
"*" + Digest::SHA1.hexdigest(Digest::SHA1.digest(plain_password)).upcase
end
-end \ No newline at end of file
+end
diff --git a/lib/trocla/formats/pgsql.rb b/lib/trocla/formats/pgsql.rb
index de233c7..ef4fed3 100644
--- a/lib/trocla/formats/pgsql.rb
+++ b/lib/trocla/formats/pgsql.rb
@@ -1,4 +1,4 @@
-class Trocla::Formats::Pgsql
+class Trocla::Formats::Pgsql < Trocla::Formats::Base
require 'digest/md5'
def format(plain_password,options={})
raise "You need pass the username as an option to use this format" unless options['username']
diff --git a/lib/trocla/formats/plain.rb b/lib/trocla/formats/plain.rb
index 98797d2..79502e0 100644
--- a/lib/trocla/formats/plain.rb
+++ b/lib/trocla/formats/plain.rb
@@ -1,7 +1,7 @@
-class Trocla::Formats::Plain
+class Trocla::Formats::Plain < Trocla::Formats::Base
def format(plain_password,options={})
plain_password
end
-end \ No newline at end of file
+end
diff --git a/lib/trocla/formats/sha1.rb b/lib/trocla/formats/sha1.rb
new file mode 100644
index 0000000..1321b35
--- /dev/null
+++ b/lib/trocla/formats/sha1.rb
@@ -0,0 +1,7 @@
+class Trocla::Formats::Sha1 < Trocla::Formats::Base
+ require 'digest/sha1'
+ require 'base64'
+ def format(plain_password,options={})
+ '{SHA}' + Base64.encode64(Digest::SHA1.digest(plain_password))
+ end
+end
diff --git a/lib/trocla/formats/sha256crypt.rb b/lib/trocla/formats/sha256crypt.rb
index 6bd1b72..e34c149 100644
--- a/lib/trocla/formats/sha256crypt.rb
+++ b/lib/trocla/formats/sha256crypt.rb
@@ -1,5 +1,5 @@
# salted crypt
-class Trocla::Formats::Sha256crypt
+class Trocla::Formats::Sha256crypt < Trocla::Formats::Base
def format(plain_password,options={})
plain_password.crypt('$5$' << Trocla::Util.salt << '$')
end
diff --git a/lib/trocla/formats/sha512crypt.rb b/lib/trocla/formats/sha512crypt.rb
index d2725c1..47eb11e 100644
--- a/lib/trocla/formats/sha512crypt.rb
+++ b/lib/trocla/formats/sha512crypt.rb
@@ -1,5 +1,5 @@
# salted crypt
-class Trocla::Formats::Sha512crypt
+class Trocla::Formats::Sha512crypt < Trocla::Formats::Base
def format(plain_password,options={})
plain_password.crypt('$6$' << Trocla::Util.salt << '$')
end
diff --git a/lib/trocla/formats/ssha.rb b/lib/trocla/formats/ssha.rb
index eaac6bb..a2e0d02 100644
--- a/lib/trocla/formats/ssha.rb
+++ b/lib/trocla/formats/ssha.rb
@@ -1,7 +1,7 @@
# salted crypt
require 'base64'
require 'digest'
-class Trocla::Formats::Ssha
+class Trocla::Formats::Ssha < Trocla::Formats::Base
def format(plain_password,options={})
salt = options['salt'] || Trocla::Util.salt(16)
"{SSHA}"+Base64.encode64("#{Digest::SHA1.digest("#{plain_password}#{salt}")}#{salt}").chomp
diff --git a/lib/trocla/formats/x509.rb b/lib/trocla/formats/x509.rb
index 5cb1fb2..219cd38 100644
--- a/lib/trocla/formats/x509.rb
+++ b/lib/trocla/formats/x509.rb
@@ -1,4 +1,4 @@
-class Trocla::Formats::X509
+class Trocla::Formats::X509 < Trocla::Formats::Base
require 'openssl'
def format(plain_password,options={})
@@ -24,65 +24,6 @@ class Trocla::Formats::X509
altnames = options['altnames'] || nil
altnames.collect { |v| "DNS:#{v}" }.join(', ') if altnames
- # nice help: https://gist.github.com/mitfik/1922961
-
- def mkkey(len)
- OpenSSL::PKey::RSA.generate(len)
- end
-
- def mkreq(subject,public_key)
- request = OpenSSL::X509::Request.new
- request.version = 0
- request.subject = subject
- request.public_key = public_key
-
- request
- end
-
- def mkcert(serial,subject,issuer,public_key,days,altnames)
- cert = OpenSSL::X509::Certificate.new
- issuer = cert if issuer == nil
- cert.subject = subject
- cert.issuer = issuer.subject
- cert.not_before = Time.now
- cert.not_after = Time.now + days * 24 * 60 * 60
- cert.public_key = public_key
- cert.serial = serial
- cert.version = 2
-
- ef = OpenSSL::X509::ExtensionFactory.new
- ef.subject_certificate = cert
- ef.issuer_certificate = issuer
- cert.extensions = [ ef.create_extension("subjectKeyIdentifier", "hash") ]
- cert.add_extension ef.create_extension("basicConstraints","CA:TRUE", true) if subject == issuer
- cert.add_extension ef.create_extension("basicConstraints","CA:FALSE", true) if subject != issuer
- cert.add_extension ef.create_extension("keyUsage", "nonRepudiation, digitalSignature, keyEncipherment", true)
- cert.add_extension ef.create_extension("subjectAltName", altnames, true) if altnames
- cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
-
- cert
- end
-
- def getca(ca)
- subreq = Trocla.new
- subreq.get_password(ca,'x509')
- end
-
- def getserial(ca,serial)
- subreq = Trocla.new
- newser = subreq.get_password("#{ca}_serial",'plain')
- if newser
- newser + 1
- else
- serial
- end
- end
-
- def setserial(ca,serial)
- subreq = Trocla.new
- subreq.set_password("#{ca}_serial",'plain',serial)
- end
-
begin
key = mkkey(keysize)
rescue Exception => e
@@ -127,4 +68,61 @@ class Trocla::Formats::X509
key.send("to_pem") + cert.send("to_pem")
end
end
+ private
+
+ # nice help: https://gist.github.com/mitfik/1922961
+
+ def mkkey(len)
+ OpenSSL::PKey::RSA.generate(len)
+ end
+
+ def mkreq(subject,public_key)
+ request = OpenSSL::X509::Request.new
+ request.version = 0
+ request.subject = subject
+ request.public_key = public_key
+
+ request
+ end
+
+ def mkcert(serial,subject,issuer,public_key,days,altnames)
+ cert = OpenSSL::X509::Certificate.new
+ issuer = cert if issuer == nil
+ cert.subject = subject
+ cert.issuer = issuer.subject
+ cert.not_before = Time.now
+ cert.not_after = Time.now + days * 24 * 60 * 60
+ cert.public_key = public_key
+ cert.serial = serial
+ cert.version = 2
+
+ ef = OpenSSL::X509::ExtensionFactory.new
+ ef.subject_certificate = cert
+ ef.issuer_certificate = issuer
+ cert.extensions = [ ef.create_extension("subjectKeyIdentifier", "hash") ]
+ cert.add_extension ef.create_extension("basicConstraints","CA:TRUE", true) if subject == issuer
+ cert.add_extension ef.create_extension("basicConstraints","CA:FALSE", true) if subject != issuer
+ cert.add_extension ef.create_extension("keyUsage", "nonRepudiation, digitalSignature, keyEncipherment", true)
+ cert.add_extension ef.create_extension("subjectAltName", altnames, true) if altnames
+ cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
+
+ cert
+ end
+
+ def getca(ca)
+ trocla.get_password(ca,'x509')
+ end
+
+ def getserial(ca,serial)
+ newser = trocla.get_password("#{ca}_serial",'plain')
+ if newser
+ newser + 1
+ else
+ serial
+ end
+ end
+
+ def setserial(ca,serial)
+ trocla.set_password("#{ca}_serial",'plain',serial)
+ end
end
diff --git a/lib/trocla/util.rb b/lib/trocla/util.rb
index ff7e3ce..78462f5 100644
--- a/lib/trocla/util.rb
+++ b/lib/trocla/util.rb
@@ -2,30 +2,36 @@ require 'securerandom'
class Trocla
class Util
class << self
- def random_str(length=12,shellsafe=:undef)
- if shellsafe
- (1..length).collect{|a| safechars[SecureRandom.random_number(safechars.size)] }.join.to_s
- else
- (1..length).collect{|a| chars[SecureRandom.random_number(chars.size)] }.join.to_s
- end
+ def random_str(length=12, charset='default')
+ _charsets = charsets[charset]
+ (1..length).collect{|a| _charsets[SecureRandom.random_number(_charsets.size)] }.join.to_s
end
def salt(length=8)
- (1..length).collect{|a| normal_chars[SecureRandom.random_number(normal_chars.size)] }.join.to_s
+ (1..length).collect{|a| alphanumeric[SecureRandom.random_number(alphanumeric.size)] }.join.to_s
end
private
+
+ def charsets
+ @charsets ||= {
+ 'default' => chars,
+ 'alphanumeric' => alphanumeric,
+ 'shellsafe' => shellsafe,
+ }
+ end
+
def chars
- @chars ||= normal_chars + special_chars
+ @chars ||= shellsafe + special_chars
end
- def safechars
- @chars ||= normal_chars + shellsafe_chars
+ def shellsafe
+ @chars ||= alphanumeric + shellsafe_chars
end
- def normal_chars
- @normal_chars ||= ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
+ def alphanumeric
+ @alphanumeric ||= ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
end
def special_chars
- @special_chars ||= "+*%/()@&=?![]{}-_.,;:".split(//)
+ @special_chars ||= "*()&![]{}-".split(//)
end
def shellsafe_chars
@shellsafe_chars ||= "+%/@=?_.,:".split(//)