Class: SafeFile
- Inherits:
-
Object
- Object
- SafeFile
- Defined in:
- lib/safefile.rb
Overview
SafeFile The file containing the safe entries
Instance Attribute Summary collapse
-
#entries ⇒ Object
Returns the value of attribute entries.
-
#filename ⇒ Object
Returns the value of attribute filename.
-
#password ⇒ Object
Returns the value of attribute password.
Instance Method Summary collapse
-
#add(name) ⇒ Object
Adds an entry.
-
#authorized? ⇒ Boolean
Returns whether the password is authorized.
-
#can_insert?(name) ⇒ Boolean
Determines whether we can insert this entry–if it exists, we prompt for the OK.
-
#change_password ⇒ Object
Changes the file’s password.
-
#count ⇒ Object
Returns the count of entries in the file.
-
#create_element(name, text) ⇒ Object
Helper method to create an XML element with a name and text.
-
#create_file(file) ⇒ Object
Creates a new file.
-
#decrypt_file(file) ⇒ Object
Decrypts the file.
-
#delete(name) ⇒ Object
Deletes an entry.
- #generate_salt_and_hash ⇒ Object
-
#initialize(password, dir, filename = '.safe.xml') ⇒ SafeFile
constructor
A new instance of SafeFile.
-
#insert(name, id, pw) ⇒ Object
Inserts an entry.
-
#list(name) ⇒ Object
Lists the desired entries.
-
#load ⇒ Object
Loads the file.
-
#save ⇒ Object
Saves the file.
Constructor Details
#initialize(password, dir, filename = '.safe.xml') ⇒ SafeFile
Returns a new instance of SafeFile.
52 53 54 55 56 57 58 |
# File 'lib/safefile.rb', line 52 def initialize(password, dir, filename = '.safe.xml') raise "Password must not be blank" unless password self.entries = Hash.new self.filename = "#{dir}/#{filename}" self.password = password load end |
Instance Attribute Details
#entries ⇒ Object
Returns the value of attribute entries.
50 51 52 |
# File 'lib/safefile.rb', line 50 def entries @entries end |
#filename ⇒ Object
Returns the value of attribute filename.
50 51 52 |
# File 'lib/safefile.rb', line 50 def filename @filename end |
#password ⇒ Object
Returns the value of attribute password.
50 51 52 |
# File 'lib/safefile.rb', line 50 def password @password end |
Instance Method Details
#add(name) ⇒ Object
Adds an entry
124 125 126 127 128 129 130 131 132 |
# File 'lib/safefile.rb', line 124 def add(name) if can_insert? name print "#{name} User ID: " id = gets.chomp! pw = SafeUtils::get_password("#{name} Password: ") insert(name, id, pw) save end end |
#authorized? ⇒ Boolean
Returns whether the password is authorized
198 199 200 |
# File 'lib/safefile.rb', line 198 def @hash == Digest::SHA256.hexdigest(self.password + @salt) end |
#can_insert?(name) ⇒ Boolean
Determines whether we can insert this entry–if it exists, we prompt for the OK
141 142 143 144 145 146 147 148 |
# File 'lib/safefile.rb', line 141 def can_insert?(name) proceed = true if @entries.has_key?(name) print "Overwrite existing #{name} (y/N)? " proceed = (gets.chomp == 'y') end proceed end |
#change_password ⇒ Object
Changes the file’s password
180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/safefile.rb', line 180 def change_password new_password = SafeUtils::get_password('Enter new password: ') rpt_password = SafeUtils::get_password('Confirm password: ') if new_password == rpt_password self.password = new_password generate_salt_and_hash save else puts 'Passwords do not match' end end |
#count ⇒ Object
Returns the count of entries in the file
175 176 177 |
# File 'lib/safefile.rb', line 175 def count() @entries.length end |
#create_element(name, text) ⇒ Object
Helper method to create an XML element with a name and text
203 204 205 206 207 |
# File 'lib/safefile.rb', line 203 def create_element(name, text) e = Element.new name e.text = text e end |
#create_file(file) ⇒ Object
Creates a new file
95 96 97 98 99 |
# File 'lib/safefile.rb', line 95 def create_file(file) puts 'Creating new file . . .' generate_salt_and_hash save end |
#decrypt_file(file) ⇒ Object
Decrypts the file
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/safefile.rb', line 74 def decrypt_file(file) begin root = Document.new(file).root @salt = root.attributes["salt"] @hash = root.attributes["hash"] if crypt_key = Crypt::Blowfish.new(self.password) e_entries = root.elements["entries"] e_entries.elements.each("entry") do |entry| fields = crypt_key.decrypt_string(Base64::decode64(entry.cdatas[0].to_s)).split("\t") fields.length == 3 ? insert(fields[0], fields[1], fields[2]) : puts("Cannot parse #{fields}, discarding.") end else raise 'The password you entered is not valid' end rescue ParseException puts "Cannot parse #{file.path}" end end |
#delete(name) ⇒ Object
Deletes an entry
151 152 153 154 155 156 157 158 |
# File 'lib/safefile.rb', line 151 def delete(name) if @entries.has_key?(name) @entries.delete(name) save else puts "Entry #{name} not found" end end |
#generate_salt_and_hash ⇒ Object
192 193 194 195 |
# File 'lib/safefile.rb', line 192 def generate_salt_and_hash @salt = [Array.new(20){rand(256).chr}.join].pack('m').chomp @hash = Digest::SHA256.hexdigest(self.password + @salt) end |
#insert(name, id, pw) ⇒ Object
Inserts an entry
135 136 137 138 |
# File 'lib/safefile.rb', line 135 def insert(name, id, pw) @entries.delete(name) @entries[name] = SafeEntry.new(name, id, pw) end |
#list(name) ⇒ Object
Lists the desired entries
161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/safefile.rb', line 161 def list(name) output = Array.new @entries.each_value do |entry| # TODO Inconsistent case handling if name == nil || entry.name.upcase =~ /^#{name.upcase}/ output << entry end end output.sort.each do |entry| puts entry end end |
#load ⇒ Object
Loads the file
61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/safefile.rb', line 61 def load f = File.open(@filename, File::CREAT) begin f.lstat.size == 0 ? create_file(f) : decrypt_file(f) rescue # TODO Determine whether error is can't create file, and print appropriate error raise $! ensure f.close unless f.nil? end end |
#save ⇒ Object
Saves the file
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/safefile.rb', line 102 def save doc = Document.new root = Element.new "safe" root.attributes["salt"] = @salt root.attributes["hash"] = @hash doc.add_element root crypt_key = Crypt::Blowfish.new(self.password) e_entries = Element.new "entries" @entries.each_value do |entry| e = Element.new "entry" CData.new Base64.encode64(crypt_key.encrypt_string(entry.to_s)), true, e e_entries.add_element e end root.add_element e_entries f = File.new(@filename, 'w') doc.write f, 2 f.close end |