Class: Passw3rd::PasswordService

Inherits:
Object
  • Object
show all
Defined in:
lib/passw3rd/password_service.rb

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.key_file_dirObject



18
19
20
# File 'lib/passw3rd/password_service.rb', line 18

def key_file_dir
  @key_file_dir || ENV['passw3rd-key_file_dir'] || Dir.getwd
end

.password_file_dirObject



13
14
15
# File 'lib/passw3rd/password_service.rb', line 13

def password_file_dir
  @password_file_dir || ENV['passw3rd-password_file_dir'] || Dir.getwd
end

Class Method Details

.cipher_nameObject



27
28
29
# File 'lib/passw3rd/password_service.rb', line 27

def cipher_name
  defined?(@cipher_name) ? @cipher_name : APPROVED_CIPHERS.first
end

.cipher_name=(cipher_name) ⇒ Object



22
23
24
25
# File 'lib/passw3rd/password_service.rb', line 22

def cipher_name= (cipher_name)
  raise "Hey man, you can only use #{APPROVED_CIPHERS}, you supplied #{cipher_name}" if cipher_name.nil? || !APPROVED_CIPHERS.include?(cipher_name)
  @cipher_name = ENV['passw3rd-cipher_name'] || cipher_name
end

.configure(&block) ⇒ Object



32
33
34
# File 'lib/passw3rd/password_service.rb', line 32

def self.configure(&block)
  instance_eval &block
end

.create_key_iv_file(path = nil) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/passw3rd/password_service.rb', line 105

def self.create_key_iv_file(path = nil)
  unless path
    path = ::Passw3rd::PasswordService.key_file_dir
  end    

  # d'oh!
  cipher = OpenSSL::Cipher::Cipher.new(::Passw3rd::PasswordService.cipher_name)
  iv = cipher.random_iv
  key = cipher.random_key

  begin
    File.open(self.key_path(path), 'w') {|f| f.write(key.unpack("H*").join) }
    File.open(self.iv_path(path), 'w') {|f| f.write(iv.unpack("H*").join) }
  rescue
    puts "Couldn't write key/IV to #{path}\n"
    raise $!
  end
  path
end

.decrypt(cipher_text, key_path = self.key_file_dir) ⇒ Object



65
66
67
68
69
70
71
72
73
74
# File 'lib/passw3rd/password_service.rb', line 65

def self.decrypt(cipher_text, key_path = self.key_file_dir)
  cipher = cipher_setup(:decrypt, key_path)
  begin
    d = cipher.update(cipher_text)
    d << cipher.final
  rescue OpenSSL::Cipher::CipherError => err
    puts "Couldn't decrypt password #{cipher_text}.  Are you using the right keys (#{key_path})?"
    raise err
  end
end

.encrypt(password, key_path = self.key_file_dir) ⇒ Object

Raises:

  • (ArgumentError)


52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/passw3rd/password_service.rb', line 52

def self.encrypt(password, key_path = self.key_file_dir)
  raise ArgumentError, "password cannot be blank" if password.to_s.empty?

  cipher = cipher_setup(:encrypt, key_path)
  begin
    e = cipher.update(password)
    e << cipher.final
  rescue OpenSSL::Cipher::CipherError => err
    puts "Couldn't encrypt password."
    raise err
  end
end

.get_password(password_file, options = {:key_path => self.key_file_dir, :force => true}) ⇒ Object



36
37
38
39
40
41
42
# File 'lib/passw3rd/password_service.rb', line 36

def self.get_password (password_file, options = {:key_path => self.key_file_dir, :force => true})
  uri = _parse_uri(password_file)
  encoded_password = read_file(uri)
  decrypt(encoded_password, options[:key_path])
rescue => e
  raise ArgumentError, "Could not decrypt passw3rd file #{password_file} - #{e}" if options[:force]
end

.iv_path(path = ::Passw3rd::PasswordService.key_file_dir) ⇒ Object



129
130
131
# File 'lib/passw3rd/password_service.rb', line 129

def self.iv_path(path = ::Passw3rd::PasswordService.key_file_dir)
  File.join(path || self.key_file_dir, IV_FILE)
end

.key_path(path = self.key_file_dir) ⇒ Object



125
126
127
# File 'lib/passw3rd/password_service.rb', line 125

def self.key_path(path= self.key_file_dir)
  File.join(path || self.key_file_dir, KEY_FILE)
end

.rotate_keys(args = {}) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/passw3rd/password_service.rb', line 76

def self.rotate_keys(args = {})
  unless args.empty?
    ::Passw3rd::PasswordService.configure do |c|
      c.password_file_dir = args[:password_file_dir]
      c.key_file_dir = args[:key_file_dir]
      c.cipher_name = args[:cipher]
    end
  end

  passwords = []

  Dir.foreach(::Passw3rd::PasswordService.password_file_dir) do |passw3rd_file|
    next if %w{. ..}.include?(passw3rd_file) || passw3rd_file =~ /\A\.passw3rd/
    puts "Rotating #{passw3rd_file}"
    passwords << {:clear_password => ::Passw3rd::PasswordService.get_password(passw3rd_file), :file => passw3rd_file}
  end

  ::Passw3rd::PasswordService.cipher_name = args[:new_cipher] if args[:new_cipher]

  path = self.create_key_iv_file
  puts "Wrote new keys to #{path}"

  passwords.each do |password|
    full_path = File.join(::Passw3rd::PasswordService.password_file_dir, password[:file])
    ::Passw3rd::PasswordService.write_password_file(password[:clear_password], password[:file])    
    puts "Wrote new password to #{full_path}"
  end
end

.write_password_file(password, output_path, key_path = self.key_file_dir) ⇒ Object



44
45
46
47
48
49
50
# File 'lib/passw3rd/password_service.rb', line 44

def self.write_password_file(password, output_path, key_path = self.key_file_dir)
  enc_password = encrypt(password, key_path)
  base64pw = Base64.encode64(enc_password) 
  path = File.join(password_file_dir, output_path)
  write_file(path, base64pw)
  path
end