summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authormh <mh@immerda.ch>2011-07-27 18:43:55 +0200
committermh <mh@immerda.ch>2011-07-27 18:43:55 +0200
commit9146a541ff96b92f4f14c6292307b68dc4673097 (patch)
tree3637ab49056565fad3566d78698634c2a6ab7265 /lib
initial release of trocla
Diffstat (limited to 'lib')
-rw-r--r--lib/VERSION4
-rw-r--r--lib/trocla.rb91
-rw-r--r--lib/trocla/default_config.yaml7
-rw-r--r--lib/trocla/formats.rb32
-rw-r--r--lib/trocla/formats/md5crypt.rb6
-rw-r--r--lib/trocla/formats/mysql.rb6
-rw-r--r--lib/trocla/formats/pgsql.rb7
-rw-r--r--lib/trocla/formats/plain.rb7
-rw-r--r--lib/trocla/util.rb14
-rw-r--r--lib/trocla/version.rb22
10 files changed, 196 insertions, 0 deletions
diff --git a/lib/VERSION b/lib/VERSION
new file mode 100644
index 0000000..a81c87a
--- /dev/null
+++ b/lib/VERSION
@@ -0,0 +1,4 @@
+major:0
+minor:0
+patch:1
+build: \ No newline at end of file
diff --git a/lib/trocla.rb b/lib/trocla.rb
new file mode 100644
index 0000000..fe7696c
--- /dev/null
+++ b/lib/trocla.rb
@@ -0,0 +1,91 @@
+require 'trocla/version'
+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'))
+ @config_file = def_config_file
+ end
+ end
+
+ def password(key,format,options={})
+ options = config['options'].merge(options)
+ raise "Format #{format} is not supported! Supported formats: #{Trocla::Formats.all.join(', ')}" unless Trocla::Formats::available?(format)
+
+ unless (password=get_password(key,format)).nil?
+ return password
+ end
+
+ plain_pwd = get_password(key,'plain')
+ if options['random'] && plain_pwd.nil?
+ plain_pwd = Trocla::Util.random_str(options['length'])
+ 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))
+ 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?
+ cache.delete(key)
+ else
+ old_val = (h = cache.fetch(key,{})).delete(format)
+ h.empty? ? cache.delete(key) : cache[key] = h
+ old_val
+ end
+ end
+
+ def set_password(key,format,password,delete_plain=false)
+ if ((format=format) == 'plain') && !delete_plain
+ h = (cache[key] = { 'plain' => password })
+ else
+ h = (cache[key] = cache.fetch(key,{}).merge({ format => password }))
+ end
+ h[format]
+ end
+
+ private
+ def cache
+ @cache ||= build_cache
+ end
+
+ def build_cache
+ require 'moneta'
+ require "moneta/adapters/#{config['adapter'].downcase}"
+ lconfig = config
+ Moneta::Builder.new { run eval( "Moneta::Adapters::#{lconfig['adapter']}"), lconfig['adapter_options'] }
+ end
+
+ def config
+ @config ||= read_config
+ end
+
+ def read_config
+ if @config_file.nil?
+ default_config
+ else
+ raise "Configfile #{@config_file} does not exist!" unless File.exists?(@config_file)
+ 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 \ No newline at end of file
diff --git a/lib/trocla/default_config.yaml b/lib/trocla/default_config.yaml
new file mode 100644
index 0000000..502e7f1
--- /dev/null
+++ b/lib/trocla/default_config.yaml
@@ -0,0 +1,7 @@
+---
+options:
+ random: true
+ length: 12
+adapter: YAML
+adapter_options:
+ :path: '/tmp/trocla.yaml'
diff --git a/lib/trocla/formats.rb b/lib/trocla/formats.rb
new file mode 100644
index 0000000..3cf31bd
--- /dev/null
+++ b/lib/trocla/formats.rb
@@ -0,0 +1,32 @@
+class Trocla::Formats
+ 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
+ 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
diff --git a/lib/trocla/formats/md5crypt.rb b/lib/trocla/formats/md5crypt.rb
new file mode 100644
index 0000000..f52e2a1
--- /dev/null
+++ b/lib/trocla/formats/md5crypt.rb
@@ -0,0 +1,6 @@
+# salted crypt
+class Trocla::Formats::Md5crypt
+ def format(plain_password,options={})
+ plain_password.crypt('$1$' << Trocla::Util.random_str(8) << '$')
+ end
+end \ No newline at end of file
diff --git a/lib/trocla/formats/mysql.rb b/lib/trocla/formats/mysql.rb
new file mode 100644
index 0000000..7fbc3a7
--- /dev/null
+++ b/lib/trocla/formats/mysql.rb
@@ -0,0 +1,6 @@
+class Trocla::Formats::Mysql
+ 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
diff --git a/lib/trocla/formats/pgsql.rb b/lib/trocla/formats/pgsql.rb
new file mode 100644
index 0000000..05c23ce
--- /dev/null
+++ b/lib/trocla/formats/pgsql.rb
@@ -0,0 +1,7 @@
+class Trocla::Formats::Pgsql
+ require 'digest/md5'
+ def format(plain_password,options={})
+ raise "You need pass the username in the options for this format" unless options['username']
+ "md5" + Digest::MD5.hexdigest(plain_password + options['username'])
+ end
+end \ No newline at end of file
diff --git a/lib/trocla/formats/plain.rb b/lib/trocla/formats/plain.rb
new file mode 100644
index 0000000..98797d2
--- /dev/null
+++ b/lib/trocla/formats/plain.rb
@@ -0,0 +1,7 @@
+class Trocla::Formats::Plain
+
+ def format(plain_password,options={})
+ plain_password
+ end
+
+end \ No newline at end of file
diff --git a/lib/trocla/util.rb b/lib/trocla/util.rb
new file mode 100644
index 0000000..468206d
--- /dev/null
+++ b/lib/trocla/util.rb
@@ -0,0 +1,14 @@
+class Trocla
+ class Util
+ class << self
+ def random_str(length=12)
+ (1..length).collect{|a| chars[rand(chars.size)] }.join.to_s
+ end
+
+ private
+ def chars
+ @chars ||= (('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a) + "+*%/()@&=?![]{}-_.,;:<>".split(//)
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/trocla/version.rb b/lib/trocla/version.rb
new file mode 100644
index 0000000..6d9476b
--- /dev/null
+++ b/lib/trocla/version.rb
@@ -0,0 +1,22 @@
+# encoding: utf-8
+class Trocla
+ class VERSION
+ version = {}
+ File.read(File.join(File.dirname(__FILE__), '../', 'VERSION')).each_line do |line|
+ type, value = line.chomp.split(":")
+ next if type =~ /^\s+$/ || value =~ /^\s+$/
+ version[type] = value
+ end
+
+ MAJOR = version['major']
+ MINOR = version['minor']
+ PATCH = version['patch']
+ BUILD = version['build']
+
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
+
+ def self.version
+ STRING
+ end
+ end
+end