Class: Keepassx::Database
- Inherits:
-
Object
- Object
- Keepassx::Database
- Includes:
- Utilities
- Defined in:
- lib/keepassx/database.rb
Instance Attribute Summary collapse
-
#header ⇒ Object
readonly
BACKUP_GROUP_OPTIONS = { :title => :Backup, :icon => 4, :id => 0 }.
-
#key_file ⇒ Object
Returns the value of attribute key_file.
-
#password ⇒ Object
Returns the value of attribute password.
-
#path ⇒ Object
Returns the value of attribute path.
Class Method Summary collapse
Instance Method Summary collapse
-
#add(item, opts = {}) ⇒ Keepassx::Group, Keepassx::Entry
Add new item to database.
-
#add_entry(opts) ⇒ Keepassx::Entry
Add new entry to database.
-
#add_group(opts) ⇒ Keepassx::Group
Add new group to database.
-
#checksum ⇒ String
Get actual payload checksum.
-
#delete(item, opts = {}) ⇒ Object
Delete item from database.
-
#dump(password = nil, key_file = nil) ⇒ String
Get raw encoded database.
-
#entries(opts = {}) ⇒ Array<Keepassx::Entry>
Get all matching entries.
-
#entry(opts = {}) ⇒ Keepassx::Entry
Get first matching entry.
-
#get(item_type, opts = {}) ⇒ Keepassx::Group, Keepassx::Entry
Search for items, using AND statement for the search conditions.
-
#group(opts = {}) ⇒ Keepassx::Group
Get first matching group.
-
#groups(opts = {}) ⇒ Array<Keepassx::Group>
Get all matching groups.
-
#index(v) ⇒ Fixnum
Get Group/Entry index in storage.
-
#initialize(opts) ⇒ Database
constructor
A new instance of Database.
-
#length ⇒ Fixnum
Get Enries and Groups total number.
-
#locked? ⇒ Boolean
Get lock state.
-
#next_group_id ⇒ Fixnum
Get next group ID number.
-
#save(password = nil, key_file = nil) ⇒ Fixnum
Save database to file storage.
-
#search(pattern) ⇒ Keepassx::Entry
Search entry by title.
-
#to_a ⇒ Array
Dump Array representation of database.
-
#to_xml ⇒ REXML::Document
Dump database in XML.
-
#unlock(password, key_file = nil) ⇒ Boolean
Unlock database.
-
#valid? ⇒ Boolean
Check database validity.
Constructor Details
#initialize(opts) ⇒ Database
Returns a new instance of Database.
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 |
# File 'lib/keepassx/database.rb', line 21 def initialize opts raw_db, @groups, @entries, @locked = '', [], [], true if opts.is_a? File self.path = opts.path raw_db = read opts initialize_database raw_db elsif opts.is_a? String self.path = opts raw_db = read opts if File.exist? opts initialize_database raw_db elsif opts.is_a? REXML::Document # TODO: Implement import method fail NotImplementedError elsif opts.is_a? Array initialize_database '' # Pass empty data to get header initialized # Avoid opts change by parse_data_array method opts.each { |item| parse_data_array item } # initialize_payload # Make sure payaload is available for checksum else fail TypeError, "Expected one of the File, String, " \ "REXML::Document or Hast, got #{opts.class}" end end |
Instance Attribute Details
#header ⇒ Object (readonly)
BACKUP_GROUP_OPTIONS = { :title => :Backup, :icon => 4, :id => 0 }
8 9 10 |
# File 'lib/keepassx/database.rb', line 8 def header @header end |
#key_file ⇒ Object
Returns the value of attribute key_file.
9 10 11 |
# File 'lib/keepassx/database.rb', line 9 def key_file @key_file end |
#password ⇒ Object
Returns the value of attribute password.
9 10 11 |
# File 'lib/keepassx/database.rb', line 9 def password @password end |
#path ⇒ Object
Returns the value of attribute path.
9 10 11 |
# File 'lib/keepassx/database.rb', line 9 def path @path end |
Class Method Details
.open(opts) {|db| ... } ⇒ Object
12 13 14 15 16 17 18 |
# File 'lib/keepassx/database.rb', line 12 def self.open opts path = opts.to_s fail "File #{path} does not exist." unless File.exist? path db = self.new path return db unless block_given? yield db end |
Instance Method Details
#add(item, opts = {}) ⇒ Keepassx::Group, Keepassx::Entry
Add new item to database.
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/keepassx/database.rb', line 204 def add item, opts = {} if item.is_a? Symbol if item.eql? :group return add_group opts elsif item.eql? :entry return add_entry opts else fail "Unknown item type '#{item.to_s}'" end elsif item.is_a? Keepassx::Group return add_group item elsif item.is_a? Keepassx::Entry return add_entry item else fail "Could not add '#{item.inspect}'" end end |
#add_entry(opts) ⇒ Keepassx::Entry
Add new entry to database.
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/keepassx/database.rb', line 270 def add_entry opts # FIXME: Add warnings and detailed description if opts.is_a? Hash opts = deep_copy opts # FIXME: Remove this feature as it has unpredictable behavior when groups with duplicate title are present if opts[:group].is_a? Symbol group = self.group opts[:group] fail "Group #{opts[:group].inspect} does not exist" if group.nil? opts[:group] = group end entry = Keepassx::Entry.new opts @entries << entry header.entry_number += 1 entry elsif opts.is_a? Keepassx::Entry @entries << opts header.entry_number += 1 opts else fail TypeError, "Expected Hash or Keepassx::Entry, got #{opts.class}" end end |
#add_group(opts) ⇒ Keepassx::Group
Add new group to database.
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/keepassx/database.rb', line 231 def add_group opts if opts.is_a? Hash opts = deep_copy opts opts[:id] = next_group_id unless opts.has_key? :id if opts[:parent].is_a? Symbol group = self.group opts[:parent] fail "Group #{opts[:parent].inspect} does not exist" if group.nil? opts[:parent] = group end group = Keepassx::Group.new(opts) if group.parent.nil? @groups << group else @groups.insert last_sibling_index(group.parent) + 1, group end header.group_number += 1 group elsif opts.is_a? Keepassx::Group # Assign parent group parent = opts.parent || nil @groups.insert last_sibling_index(parent) + 1, item header.group_number += 1 opts else fail TypeError, "Expected Hash or Keepassx::Group, got #{opts.class}" end end |
#checksum ⇒ String
Get actual payload checksum.
415 416 417 |
# File 'lib/keepassx/database.rb', line 415 def checksum Digest::SHA256.digest payload end |
#delete(item, opts = {}) ⇒ Object
Delete item from database.
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
# File 'lib/keepassx/database.rb', line 302 def delete item, opts = {} if item.is_a? Keepassx::Group delete_group item elsif item.is_a? Keepassx::Entry delete_entry item elsif item.is_a? Symbol if item.eql? :group delete_group group(opts) elsif item.eql? :entry delete_entry entry(opts) else fail "Unknown item type '#{item.to_s}'" end end end |
#dump(password = nil, key_file = nil) ⇒ String
Get raw encoded database.
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/keepassx/database.rb', line 58 def dump password = nil, key_file = nil # FIXME: Figure out what this is needed for # my $e = ($self->find_entries({title => 'Meta-Info', username => 'SYSTEM', comment => 'KPX_GROUP_TREE_STATE', url => '$'}))[0] || $self->add_entry({ # comment => 'KPX_GROUP_TREE_STATE', # title => 'Meta-Info', # username => 'SYSTEM', # url => '$', # id => '0000000000000000', # group => $g[0], # binary => {'bin-stream' => $bin}, # }); self.password = password unless password.nil? self.key_file = key_file unless key_file.nil? initialize_payload header.contents_hash = checksum encrypt header.encode << @encrypted_payload.to_s end |
#entries(opts = {}) ⇒ Array<Keepassx::Entry>
Get all matching entries.
172 173 174 |
# File 'lib/keepassx/database.rb', line 172 def entries opts = {} get :entry, opts end |
#entry(opts = {}) ⇒ Keepassx::Entry
Get first matching entry.
158 159 160 161 162 163 164 165 166 |
# File 'lib/keepassx/database.rb', line 158 def entry opts = {} entries = get :entry, opts if entries.empty? nil else entries.first end end |
#get(item_type, opts = {}) ⇒ Keepassx::Group, Keepassx::Entry
Search for items, using AND statement for the search conditions
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/keepassx/database.rb', line 106 def get item_type, opts = {} case item_type when :entry item_list = @entries when :group item_list = @groups else fail "Unknown item type '#{item_type}'" end if opts.empty? # Return all items if no selection condition was provided items = item_list else opts = {:title => opts.to_s} if opts.is_a? String or opts.is_a? Symbol match_number = opts.length items = [] opts.each do |k, v| items += Array(item_list.select { |e| e.send(k).eql?(v) }) end buffer = Hash.new 0 items.each do |e| buffer[e] += 1 end # Select only items which matches all conditions items = [] buffer.each do |k, v| items << k if v.eql? match_number end end if block_given? items.each do |i| yield i end else items end end |
#group(opts = {}) ⇒ Keepassx::Group
Get first matching group.
180 181 182 183 184 185 186 187 188 |
# File 'lib/keepassx/database.rb', line 180 def group opts = {} groups = get :group, opts if groups.empty? nil else groups.first end end |
#groups(opts = {}) ⇒ Array<Keepassx::Group>
Get all matching groups.
195 196 197 |
# File 'lib/keepassx/database.rb', line 195 def groups opts = {} get :group, opts end |
#index(v) ⇒ Fixnum
Get Group/Entry index in storage.
383 384 385 386 387 388 389 390 391 392 393 394 |
# File 'lib/keepassx/database.rb', line 383 def index v if v.is_a? Keepassx::Group groups.find_index v elsif v.is_a? Keepassx::Entry entries.find_index v else fail "Cannot get index for #{v.class}" end end |
#length ⇒ Fixnum
Get Enries and Groups total number.
400 401 402 403 404 405 406 407 408 409 |
# File 'lib/keepassx/database.rb', line 400 def length length = 0 [@groups, @entries].each do |items| items.each do |item| length += item.length end end length end |
#locked? ⇒ Boolean
Get lock state
375 376 377 |
# File 'lib/keepassx/database.rb', line 375 def locked? @locked end |
#next_group_id ⇒ Fixnum
Get next group ID number.
423 424 425 426 427 428 429 430 431 432 433 434 435 |
# File 'lib/keepassx/database.rb', line 423 def next_group_id if groups.empty? # Start each time from 1 to make sure groups get the same id's for the # same input data 1 else id = groups.last.id loop do id += 1 break id if groups.detect { |g| g.id.eql? id }.nil? end end end |
#save(password = nil, key_file = nil) ⇒ Fixnum
Save database to file storage
86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/keepassx/database.rb', line 86 def save password = nil, key_file = nil # TODO: Switch to rails style, i.e. save(:password => 'pass') fail TypeError, 'File path is not set' if path.nil? File.write path, dump(password, key_file) # FIXME: Implement exceptions rescue IOError => e warn ">>>> IOError in database.rb" fail rescue SystemCallError => e warn ">>>> SystemCallError in database.rb" fail end |
#search(pattern) ⇒ Keepassx::Entry
Search entry by title.
354 355 356 357 358 359 360 361 |
# File 'lib/keepassx/database.rb', line 354 def search pattern # FIXME: Seqrch by any atribute by pattern backup = group 'Backup' entries.select do |e| e.group != backup && e.title =~ /#{pattern}/i end end |
#to_a ⇒ Array
Dump Array representation of database.
461 462 463 464 465 |
# File 'lib/keepassx/database.rb', line 461 def to_a result = [] groups(:level => 0).each { |group| result << build_branch(group) } result end |
#to_xml ⇒ REXML::Document
Dump database in XML.
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
# File 'lib/keepassx/database.rb', line 441 def to_xml document = REXML::Document.new '<!DOCTYPE KEEPASSX_DATABASE><database/>' parent_element = document.root groups.each do |group| # xml = group.to_xml # parent_element = parent_element.add xml if group.parent.nil? section = parent_element.add group.to_xml entries(:group => group).each { |e| section.add e.to_xml } parent_element.add section end document end |
#unlock(password, key_file = nil) ⇒ Boolean
Unlock database.
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'lib/keepassx/database.rb', line 329 def unlock password, key_file = nil return true unless locked? self.password = password unless password.nil? self.key_file = key_file unless key_file.nil? decrypt payload_io = StringIO.new payload initialize_groups Group.extract_from_payload header, payload_io @entries = Entry.extract_from_payload header, groups, payload_io @locked = false true rescue OpenSSL::Cipher::CipherError false rescue Keepassx::MalformedDataError fail end |
#valid? ⇒ Boolean
Check database validity.
367 368 369 |
# File 'lib/keepassx/database.rb', line 367 def valid? header.valid? end |