lib/keepassx/group.rb in keepassx-0.1.0 vs lib/keepassx/group.rb in keepassx-1.0.0
- old
+ new
@@ -1,5 +1,7 @@
+# frozen_string_literal: true
+
# One group: [FIELDTYPE(FT)][FIELDSIZE(FS)][FIELDDATA(FD)]
# [FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)]...
#
# [ 2 bytes] FIELDTYPE
# [ 4 bytes] FIELDSIZE, size of FIELDDATA in bytes
@@ -18,39 +20,110 @@
# * 0006: Expiration time, FIELDSIZE = 5, FIELDDATA = packed date/time
# * 0007: Image ID, FIELDSIZE must be 4 bytes
# * 0008: Level, FIELDSIZE = 2
# * 0009: Flags, 32-bit value, FIELDSIZE = 4
# * FFFF: Group entry terminator, FIELDSIZE must be 0
+
module Keepassx
- class Group
- def self.extract_from_payload(header, payload_io)
- groups = []
- header.ngroups.times do
- group = Group.new(payload_io)
- groups << group
+ class Group < Fieldable
+
+ set_field_descriptor Keepassx::Field::Group
+
+ attr_accessor :entries
+ attr_reader :parent
+
+ def initialize(payload)
+ @parent = nil
+ @entries = []
+
+ super do
+ # Do some validation
+ raise ArgumentError, "'id' is required (type: integer)" unless valid_integer?(payload[:id])
+ raise ArgumentError, "'name' is required (type: string)" unless valid_string?(payload[:name])
+
+ # First set @parent and @level.
+ # Remove key from payload to not interfere with KeePassX fields format
+ self.parent = payload.delete(:parent)
+
+ # Build list of fields
+ @fields = build_payload(payload)
end
- groups
end
- def initialize(payload_io)
- fields = []
- begin
- field = GroupField.new(payload_io)
- fields << field
- end while not field.terminator?
- @fields = fields
+ class << self
+
+ def extract_from_payload(header, payload)
+ groups = []
+ header.groups_count.times { groups << Group.new(payload) }
+ groups
+ end
+
end
- def length
- @fields.map(&:length).reduce(&:+)
+
+ def parent=(value)
+ raise ArgumentError, "Expected Keepassx::Group or nil, got #{value.class}" unless valid_parent?(value)
+
+ if value.is_a?(Keepassx::Group)
+ self.level = value.level + 1
+ @parent = value
+
+ elsif value.nil?
+ # Assume, group is located at the top level, in case it has no parent
+ self.level = 0
+ @parent = nil
+ end
end
- def group_id
- @fields.detect { |field| field.name == 'groupid' }.data
+
+ # Redefine #level method to return 0 instead of nil
+ def level
+ value = get :level
+ value.nil? ? 0 : value
end
- def name
- @fields.detect { |field| field.name == 'group_name' }.data.chomp("\000")
+
+ def ==(other)
+ return false if other.nil?
+
+ parent == other.parent &&
+ name == other.name &&
+ id == other.id &&
+ level == other.level &&
+ icon == other.icon
end
+
+
+ private
+
+
+ # Redefine #level= to make it private :
+ # Setting group level only is a non-sense as it depends
+ # on parent group.
+ def level=(value)
+ set :level, value
+ end
+
+
+ def default_fields
+ @default_fields ||= {
+ id: :unknown,
+ name: :unknown,
+ creation_time: Time.now,
+ last_mod_time: Time.now,
+ last_acc_time: Time.now,
+ expiration_time: Time.local(2999, 12, 28, 23, 59, 59),
+ icon: 1,
+ level: 0,
+ flags: 0,
+ terminator: nil,
+ }
+ end
+
+
+ def valid_parent?(object)
+ object.is_a?(Keepassx::Group) || object.nil?
+ end
+
end
end