summaryrefslogtreecommitdiff
path: root/lib/trocla.rb
blob: 8d916b22aa7f58a5b0b3fda56d9ace72dc016f9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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'].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,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?
      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)
    if (format == 'plain')
      h = (cache[key] = { 'plain' => password })
    else
      h = (cache[key] = cache.fetch(key,{}).merge({ format => password }))
    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
    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