class TheFox::OSP::Database
Attributes
has_changed[RW]
Public Class Methods
new(file_path, osp)
click to toggle source
# File lib/osp/database.rb, line 12 def initialize(file_path, osp) @file_path = file_path @osp = osp @load_callback_method = nil @write_callback_method = nil @has_changed = false @data = { 'meta' => { 'version' => 1, 'created_at' => DateTime.now.to_s, 'updated_at' => DateTime.now.to_s, }, 'hosts' => Hash.new, } end
Public Instance Methods
add_host(host)
click to toggle source
# File lib/osp/database.rb, line 170 def add_host(host) @data['hosts'][host.name] = host update @has_changed = true end
csv()
click to toggle source
Return all hosts and passwords as CSV string.
# File lib/osp/database.rb, line 189 def csv "HOST,PASSWORD\r\n" @data['hosts'] .map{ |id, host| "#{host.name},#{host.password}" } .join("\r\n") end
hosts()
click to toggle source
# File lib/osp/database.rb, line 166 def hosts @data['hosts'] end
load()
click to toggle source
# File lib/osp/database.rb, line 39 def load load_callback(1000, 'Check for existing database file.') if @file_path.exist? load_callback(1050, "Use database file: #{@file_path}") load_callback(1100, "Read file '#{@file_path}'.") db_meta = File.binread(@file_path) load_callback(1200, 'Process database metadata.') db_meta = Base64.strict_decode64(db_meta) db_meta = MessagePack.unpack(db_meta) db_e = Base64.strict_decode64(db_meta['db']) mac = OpenSSL::Digest::SHA256.digest(db_e) if db_meta['mac'] == mac load_callback(1300, 'Setup database decryption.') dk_sha256 = OpenSSL::Digest::SHA256.digest(@osp.dk) iv = Base64.strict_decode64(db_meta['iv']) aes = OpenSSL::Cipher::AES.new(256, 'CBC') aes.decrypt aes.key = dk_sha256 aes.iv = iv begin load_callback(1350, 'Decrypt database.') db_b64 = aes.update(db_e) db_b64 << aes.final rescue Exception #=> e raise 'Incorrect email and password combination.' end load_callback(1400, 'Build database.') @data = MessagePack.unpack(Base64.strict_decode64(db_b64)) @data['hosts'] = @data['hosts'].map{ |name, host| host_o = TheFox::OSP::Host.from_h(host) host_o.osp = @osp [name, host_o] }.to_h load_callback(9000, 'Database startup done.') else raise 'Database integrity check failed.' end else load_callback(9500, 'Database startup done.') end end
load_callback(*o)
click to toggle source
# File lib/osp/database.rb, line 33 def load_callback(*o) if !@load_callback_method.nil? @load_callback_method.call(*o) end end
load_callback_method=(m)
click to toggle source
# File lib/osp/database.rb, line 29 def load_callback_method=(m) @load_callback_method = m end
remove_host(host)
click to toggle source
# File lib/osp/database.rb, line 176 def remove_host(host) if @data['hosts'].has_key?(host.name) @data['hosts'].delete(host.name) update @has_changed = true true else false end end
update()
click to toggle source
# File lib/osp/database.rb, line 162 def update @data['meta']['updated_at'] = DateTime.now.to_s end
write()
click to toggle source
# File lib/osp/database.rb, line 100 def write write_callback(1000, 'Check database for changes.') if @has_changed tmp = Pathname.new("#{@file_path}~").expand_path # http://stackoverflow.com/questions/9049789/aes-encryption-key-versus-iv # http://keepass.info/help/base/security.html # https://gist.github.com/byu/99651 write_callback(1100, 'Make temp database.') db_c = @data.clone db_c['hosts'] = db_c['hosts'].map{ |name, host| [name, host.clone.to_h] }.to_h write_callback(1200, 'Setup database encryption.') dk_sha256 = OpenSSL::Digest::SHA256.digest(@osp.dk) iv = OpenSSL::Cipher::AES.new(256, 'CBC').random_iv aes = OpenSSL::Cipher::AES.new(256, 'CBC') aes.encrypt aes.key = dk_sha256 aes.iv = iv write_callback(1250, 'Encrypt database.') db_e = aes.update(Base64.strict_encode64(db_c.to_msgpack)) db_e << aes.final mac = OpenSSL::Digest::SHA256.digest(db_e) db_out = { 'version' => 1, 'iv' => Base64.strict_encode64(iv), 'db' => Base64.strict_encode64(db_e), 'mac' => mac, } db_out = db_out.to_msgpack db_out = Base64.strict_encode64(db_out) write_callback(1300, "Write temp file to '#{tmp}'.") File.write(tmp, 'tmp') tmp.chmod(0600) File.binwrite(tmp, db_out) backup_dts = Time.now.strftime('%Y%m%d-%H%M%S') backup = Pathname.new("#{@file_path}~backup_#{backup_dts}_" << Digest::SHA256.file(tmp.to_s).hexdigest[0..7]) write_callback(1350, "Backup temp file to '#{backup}'.") File.write(backup, 'tmp') backup.chmod(0600) FileUtils.cp(tmp, backup) write_callback(1390, "Finally, move temp file to '#{@file_path}'.") File.write(@file_path, 'tmp') @file_path.chmod(0600) tmp.rename(@file_path) @has_changed = false else write_callback(9500, 'Nothing changed, nothing written.') end end
write_callback(*o)
click to toggle source
# File lib/osp/database.rb, line 94 def write_callback(*o) unless @write_callback_method.nil? @write_callback_method.call(*o) end end
write_callback_method=(m)
click to toggle source
# File lib/osp/database.rb, line 90 def write_callback_method=(m) @write_callback_method = m end