Download:
rpass.rb
#!/usr/bin/ruby
#title:rpass
#date: 2008-05-19
#author:Aaron Radke
# TODO: add an optional encrypted file to use
require 'rubygems'
require 'crypt/rijndael'
require 'base64'
require 'stringio'
require 'crypt/blowfish'
#require 'highline/import'
require 'highline'
class RPass
def initialize(opts={})
@highline = HighLine.new
@opts = opts
@opts[:file] = File.dirname(__FILE__) + "/stored.aes" unless @opts.key?(:file)
@key = @highline.ask("key for #{@opts[:file]}? ") { |q| q.echo = false}
@rijndael = Crypt::Rijndael.new("%-32.32s" % @key)
self.decrypt
end
def decrypt
if File.exists?(@opts[:file])
puts "Decrypting ..."
#---decrypt
encryptedString = ""
File.open(@opts[:file], "r").each{|line|
encryptedString << line
}
# TODO? Need to add the proper logic if the string did not decrypt
f = File.open(@opts[:file], "r")
begin
@decryptedString = @rijndael.decrypt_string(encryptedString)
rescue RuntimeError
puts "Error: Could not decrypt: " + $!
exit
end
if decryptedString.class != String
puts "Error: could not decrypt unkown type"
exit
end
#some other key will cause the header to be scrambled
if decryptedString =~ /^title:rpass/
@decryptedLines = decryptedString.split(/\n/)[1..-1]
else
puts "Error: could not decrypt"
exit
end
else
key2 = @highline.ask("new file: renter key ? ") { |q| q.echo = false}
if key2 != @key
puts "Error: Setting up new key failed"
exit
else
@decryptedLines = []
end
end
end
def encrypt
puts "Saving encrypted version..."
plainString = @decryptedLines.join("\n")
plainString = "title:rpass\n" + plainString
f = File.open(@opts[:file],"w")
print @rijndael.encrypt_stream(plainString)
f.close
end
def insert(text, index = -1)
@decryptedLines.insert(index, text)
end
def replace(text, index = -1)
@decryptedLines[index] = text
end
def delete(index = -1)
@decryptedLines.delete_at(index)
end
def grep(pattern)
@decryptedLines.each_with_index{|line,i|
if line =~ /#{pattern}/i
puts "#{i}: #{line}"
end
}
end
def ask
command = @highline.ask("rpass> ", String)
command.sub!(/^\s+/,'')
command.sub!(/\s+$/,'')
if command =~ /^h(elp)?$/
puts "Available commands:"
puts %{---------
(h)elp
(l)ist
exit
(s)ave
reload
(g)rep pattern
(d)elete index
(i)nsert index text
(a)dd text
newkey key
(r)eplace index text
}.gsub(/\t+/,'')
elsif command =~ /^(exit|quit)$/
encrypt
return false
elsif command =~ /^s(ave)?$/
encrypt
elsif command =~ /^reload$/
decrypt
elsif command =~ /^l(ist)?$/
grep(".?")
elsif command =~ /^g(rep)?\s+(.*)$/
grep($2)
elsif command =~ /^d(elete)?\s+(-?\d+)$/
delete($2.to_i)
elsif command =~ /^i(nsert)?\s+(-?\d+)\s+(.*)$/
insert($3,$2.to_i)
elsif command =~ /^a(dd)?\s+(.*)$/
insert($2,-1)
grep($2)
elsif command =~ /^r(eplace)?\s+(-?\d+)\s+(.*)$/
replace($3,$2.to_i)
elsif command =~ /^newkey$/
key1 = @highline.ask("Enter a new key? ") { |q| q.echo = false}
key2 = @highline.ask("Renter new key? ") { |q| q.echo = false}
if key1 == key2
puts "Setting up new key..."
@key = key1
@rijndael = Crypt::Rijndael.new(@key)
else
puts "Error, key not duplicated. New key not set."
end
replace($2,$1.to_i)
else
grep(command)
end
return true
end
end
if ARGV.size == 1
rpass = RPass.new(:file => ARGV[0])
else
rpass = RPass.new
end
while rpass.ask
end