Revision history for File-KDBX.
+0.900 2022-05-01 12:55:59-0600
+
+ * Removed the min_version methods from dumper and loader because it was
+ unused and unnecessary.
+ * Now use the database maintenance_history_days value as the default
+ "max_age" value in prune_history method.
+ * Fixed distribution prereq issues.
+ * Clean up a lot of pod typos and other inaccuracies.
+
0.800 2022-04-30 21:14:30-0600
* Initial release
"IO::Handle" : "0",
"IPC::Cmd" : "0.52",
"Iterator::Simple" : "0",
- "Iterator::Simple::Iterator" : "0",
"List::Util" : "1.33",
"Module::Load" : "0",
"Module::Loaded" : "0",
"provides" : {
"File::KDBX" : {
"file" : "lib/File/KDBX.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Cipher" : {
"file" : "lib/File/KDBX/Cipher.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Cipher::CBC" : {
"file" : "lib/File/KDBX/Cipher/CBC.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Cipher::Stream" : {
"file" : "lib/File/KDBX/Cipher/Stream.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Constants" : {
"file" : "lib/File/KDBX/Constants.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Dumper" : {
"file" : "lib/File/KDBX/Dumper.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Dumper::KDB" : {
"file" : "lib/File/KDBX/Dumper/KDB.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Dumper::Raw" : {
"file" : "lib/File/KDBX/Dumper/Raw.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Dumper::V3" : {
"file" : "lib/File/KDBX/Dumper/V3.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Dumper::V4" : {
"file" : "lib/File/KDBX/Dumper/V4.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Dumper::XML" : {
"file" : "lib/File/KDBX/Dumper/XML.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Entry" : {
"file" : "lib/File/KDBX/Entry.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Error" : {
"file" : "lib/File/KDBX/Error.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Group" : {
"file" : "lib/File/KDBX/Group.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::IO" : {
"file" : "lib/File/KDBX/IO.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::IO::Crypt" : {
"file" : "lib/File/KDBX/IO/Crypt.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::IO::HashBlock" : {
"file" : "lib/File/KDBX/IO/HashBlock.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::IO::HmacBlock" : {
"file" : "lib/File/KDBX/IO/HmacBlock.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Iterator" : {
"file" : "lib/File/KDBX/Iterator.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::KDF" : {
"file" : "lib/File/KDBX/KDF.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::KDF::AES" : {
"file" : "lib/File/KDBX/KDF/AES.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::KDF::Argon2" : {
"file" : "lib/File/KDBX/KDF/Argon2.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Key" : {
"file" : "lib/File/KDBX/Key.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Key::ChallengeResponse" : {
"file" : "lib/File/KDBX/Key/ChallengeResponse.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Key::Composite" : {
"file" : "lib/File/KDBX/Key/Composite.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Key::File" : {
"file" : "lib/File/KDBX/Key/File.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Key::Password" : {
"file" : "lib/File/KDBX/Key/Password.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Key::YubiKey" : {
"file" : "lib/File/KDBX/Key/YubiKey.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Loader" : {
"file" : "lib/File/KDBX/Loader.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Loader::KDB" : {
"file" : "lib/File/KDBX/Loader/KDB.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Loader::Raw" : {
"file" : "lib/File/KDBX/Loader/Raw.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Loader::V3" : {
"file" : "lib/File/KDBX/Loader/V3.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Loader::V4" : {
"file" : "lib/File/KDBX/Loader/V4.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Loader::XML" : {
"file" : "lib/File/KDBX/Loader/XML.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Object" : {
"file" : "lib/File/KDBX/Object.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Safe" : {
"file" : "lib/File/KDBX/Safe.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Transaction" : {
"file" : "lib/File/KDBX/Transaction.pm",
- "version" : "0.800"
+ "version" : "0.900"
},
"File::KDBX::Util" : {
"file" : "lib/File/KDBX/Util.pm",
- "version" : "0.800"
+ "version" : "0.900"
}
},
"release_status" : "stable",
"web" : "https://github.com/chazmcgarvey/File-KDBX"
}
},
- "version" : "0.800",
+ "version" : "0.900",
"x_authority" : "cpan:CCM",
"x_generated_by_perl" : "v5.34.1",
"x_serialization_backend" : "Cpanel::JSON::XS version 4.27",
provides:
File::KDBX:
file: lib/File/KDBX.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Cipher:
file: lib/File/KDBX/Cipher.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Cipher::CBC:
file: lib/File/KDBX/Cipher/CBC.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Cipher::Stream:
file: lib/File/KDBX/Cipher/Stream.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Constants:
file: lib/File/KDBX/Constants.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Dumper:
file: lib/File/KDBX/Dumper.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Dumper::KDB:
file: lib/File/KDBX/Dumper/KDB.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Dumper::Raw:
file: lib/File/KDBX/Dumper/Raw.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Dumper::V3:
file: lib/File/KDBX/Dumper/V3.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Dumper::V4:
file: lib/File/KDBX/Dumper/V4.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Dumper::XML:
file: lib/File/KDBX/Dumper/XML.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Entry:
file: lib/File/KDBX/Entry.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Error:
file: lib/File/KDBX/Error.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Group:
file: lib/File/KDBX/Group.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::IO:
file: lib/File/KDBX/IO.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::IO::Crypt:
file: lib/File/KDBX/IO/Crypt.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::IO::HashBlock:
file: lib/File/KDBX/IO/HashBlock.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::IO::HmacBlock:
file: lib/File/KDBX/IO/HmacBlock.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Iterator:
file: lib/File/KDBX/Iterator.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::KDF:
file: lib/File/KDBX/KDF.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::KDF::AES:
file: lib/File/KDBX/KDF/AES.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::KDF::Argon2:
file: lib/File/KDBX/KDF/Argon2.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Key:
file: lib/File/KDBX/Key.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Key::ChallengeResponse:
file: lib/File/KDBX/Key/ChallengeResponse.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Key::Composite:
file: lib/File/KDBX/Key/Composite.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Key::File:
file: lib/File/KDBX/Key/File.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Key::Password:
file: lib/File/KDBX/Key/Password.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Key::YubiKey:
file: lib/File/KDBX/Key/YubiKey.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Loader:
file: lib/File/KDBX/Loader.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Loader::KDB:
file: lib/File/KDBX/Loader/KDB.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Loader::Raw:
file: lib/File/KDBX/Loader/Raw.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Loader::V3:
file: lib/File/KDBX/Loader/V3.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Loader::V4:
file: lib/File/KDBX/Loader/V4.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Loader::XML:
file: lib/File/KDBX/Loader/XML.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Object:
file: lib/File/KDBX/Object.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Safe:
file: lib/File/KDBX/Safe.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Transaction:
file: lib/File/KDBX/Transaction.pm
- version: '0.800'
+ version: '0.900'
File::KDBX::Util:
file: lib/File/KDBX/Util.pm
- version: '0.800'
+ version: '0.900'
recommends:
Compress::Raw::Zlib: '0'
File::KDBX::XS: '0'
IO::Handle: '0'
IPC::Cmd: '0.52'
Iterator::Simple: '0'
- Iterator::Simple::Iterator: '0'
List::Util: '1.33'
Module::Load: '0'
Module::Loaded: '0'
bugtracker: https://github.com/chazmcgarvey/File-KDBX/issues
homepage: https://github.com/chazmcgarvey/File-KDBX
repository: https://github.com/chazmcgarvey/File-KDBX.git
-version: '0.800'
+version: '0.900'
x_authority: cpan:CCM
x_generated_by_perl: v5.34.1
x_serialization_backend: 'YAML::Tiny version 1.73'
"IO::Handle" => 0,
"IPC::Cmd" => "0.52",
"Iterator::Simple" => 0,
- "Iterator::Simple::Iterator" => 0,
"List::Util" => "1.33",
"Module::Load" => 0,
"Module::Loaded" => 0,
"lib" => 0,
"utf8" => 0
},
- "VERSION" => "0.800",
+ "VERSION" => "0.900",
"test" => {
"TESTS" => "t/*.t"
}
"IPC::Cmd" => "0.52",
"IPC::Open3" => 0,
"Iterator::Simple" => 0,
- "Iterator::Simple::Iterator" => 0,
"List::Util" => "1.33",
"Module::Load" => 0,
"Module::Loaded" => 0,
VERSION
- version 0.800
+ version 0.900
SYNOPSIS
DESCRIPTION
- File::KDBX provides everything you need to work with a KDBX database. A
+ File::KDBX provides everything you need to work with KDBX databases. A
KDBX database is a hierarchical object database which is commonly used
to store secret information securely. It was developed for the KeePass
password safe. See "Introduction to KDBX" for more information about
KDBX.
- This module lets you query entries, create new entries, delete entries
- and modify entries. The distribution also includes various parsers and
- generators for serializing and persisting databases.
+ This module lets you query entries, create new entries, delete entries,
+ modify entries and more. The distribution also includes various parsers
+ and generators for serializing and persisting databases.
- This design of this software was influenced by the KeePassXC
+ The design of this software was influenced by the KeePassXC
<https://github.com/keepassxreboot/keepassxc> implementation of KeePass
as well as the File::KeePass module. File::KeePass is an alternative
module that works well in most cases but has a small backlog of bugs
Features
- This implementation of KDBX supports a lot of features:
-
* ☑ Read and write KDBX version 3 - version 4.1
* ☑ Read and write KDB files (requires File::KeePass)
groups are directories, entries are files, and strings and binaries
make up a file's contents.
- Databases are typically persisted as a encrypted, compressed files.
- They are usually accessed directly (i.e. not over a network). The
- primary focus of this type of database is data security. It is ideal
- for storing relatively small amounts of data (strings and binaries)
- that must remain secret except to such individuals as have the correct
+ Databases are typically persisted as encrypted, compressed files. They
+ are usually accessed directly (i.e. not over a network). The primary
+ focus of this type of database is data security. It is ideal for
+ storing relatively small amounts of data (strings and binaries) that
+ must remain secret except to such individuals as have the correct
master key. Even if the database file were to be "leaked" to the public
Internet, it should be virtually impossible to crack with a strong key.
The KDBX format is most often used by password managers to store
Timestamp indicating when the default username was last changed.
- maintenance_history_days
-
- TODO... not really sure what this is. 😀
-
color
A color associated with the database (in the form #ffffff where "f" is
recycle_bin_changed
- Timestamp indicating when the recycle bin was last changed.
+ Timestamp indicating when the recycle bin group was last changed.
entry_templates_group
history_max_items
- The maximum number of historical entries allowed to be saved for each
- entry.
+ The maximum number of historical entries that should be kept for each
+ entry. Default is 10.
history_max_size
The maximum total size (in bytes) that each individual entry's history
- is allowed to grow.
+ is allowed to grow. Default is 6 MiB.
+
+ maintenance_history_days
+
+ The maximum age (in days) historical entries should be kept. Default it
+ 365.
settings_changed
single implicit root group is created to contain the actual root
groups. When writing to such a format, if the root group looks like it
was implicitly created then it won't be written and the resulting file
- might have multiple root groups. This allows working with older files
- without changing their written internal structure while still adhering
- to modern semantics while the database is opened.
+ might have multiple root groups, as it was before loading. This allows
+ working with older files without changing their written internal
+ structure while still adhering to modern semantics while the database
+ is opened.
The root group of a KDBX database contains all of the database's
entries and other groups. If you replace the root group, you are
group and calling "add_group" in File::KDBX::Group on the parent group,
forwarding the arguments. Available options:
- * group (aka parent) - Group object or group UUID to add the group to
- (default: root group)
+ * group - Group object or group UUID to add the group to (default:
+ root group)
groups
group and calling "add_entry" in File::KDBX::Group on the parent group,
forwarding the arguments. Available options:
- * group (aka parent) - Group object or group UUID to add the entry to
- (default: root group)
+ * group - Group object or group UUID to add the entry to (default:
+ root group)
entries
$key = $kdbx->key($primitive);
Get or set a File::KDBX::Key. This is the master key (e.g. a password
- or a key file that can decrypt a database). See "new" in
- File::KDBX::Key for an explanation of what the primitive can be.
+ or a key file that can decrypt a database). You can also pass a
+ primitive that can be cast to a Key. See "new" in File::KDBX::Key for
+ an explanation of what the primitive can be.
You generally don't need to call this directly because you can provide
the key directly to the loader or dumper when loading or dumping a KDBX
$key = $kdbx->composite_key($key);
$key = $kdbx->composite_key($primitive);
- Construct a File::KDBX::Key::Composite from a primitive. See "new" in
- File::KDBX::Key for an explanation of what the primitive can be. If the
- primitive does not represent a composite key, it will be wrapped.
+ Construct a File::KDBX::Key::Composite from a Key or primitive. See
+ "new" in File::KDBX::Key for an explanation of what the primitive can
+ be. If the primitive does not represent a composite key, it will be
+ wrapped.
- You generally don't need to call this directly. The parser and writer
+ You generally don't need to call this directly. The loader and dumper
use it to transform a master key into a raw encryption key.
kdf
If not passed, the UUID comes from $kdbx->headers->{cipher_id} and the
encryption IV comes from $kdbx->headers->{encryption_iv}.
- You generally don't need to call this directly. The parser and writer
+ You generally don't need to call this directly. The loader and dumper
use it to decrypt and encrypt KDBX files.
random_stream
$kdbx->inner_headers->{inner_random_stream_id} (respectively) for KDBX4
files.
- You generally don't need to call this directly. The parser and writer
+ You generally don't need to call this directly. The loader and dumper
use it to scramble protected strings.
RECIPES
If you have an iterator, such as returned by "entries", "groups" or
even "objects" you can filter it using "where" in File::KDBX::Iterator.
- my $filtered_entries = $kdbx->entries->where($query);
+ my $filtered_entries = $kdbx->entries->where(\&query);
- A $query is just a subroutine that you can either write yourself or
+ A \&query is just a subroutine that you can either write yourself or
have generated for you from either a "Simple Expression" or
"Declarative Syntax". It's easier to have your query generated, so I'll
cover that first.
* < - Number less than
- * >> - Number greater than
+ * > - Number greater than
* <= - Number less than or equal
- Group3
- EntryC
- IDS order of groups is: Root, Group1, Group2, Group3 IDS order of
- entries is: EntryA, EntryB, EntryC IDS order of objects is: Root,
- Group1, EntryA, Group2, EntryB, Group3, EntryC
+ * IDS order of groups is: Root, Group1, Group2, Group3
+
+ * IDS order of entries is: EntryA, EntryB, EntryC
+
+ * IDS order of objects is: Root, Group1, EntryA, Group2, EntryB,
+ Group3, EntryC
+
+ * DFS order of groups is: Group2, Group1, Group3, Root
+
+ * DFS order of entries is: EntryB, EntryA, EntryC
+
+ * DFS order of objects is: Group2, EntryB, Group1, EntryA, Group3,
+ EntryC, Root
+
+ * BFS order of groups is: Root, Group1, Group3, Group2
- DFS order of groups is: Group2, Group1, Group3, Root DFS order of
- entries is: EntryB, EntryA, EntryC DFS order of objects is: Group2,
- EntryB, Group1, EntryA, Group3, EntryC, Root
+ * BFS order of entries is: EntryA, EntryC, EntryB
- BFS order of groups is: Root, Group1, Group3, Group2 BFS order of
- entries is: EntryA, EntryC, EntryB BFS order of objects is: Root,
- Group1, EntryA, Group3, EntryC, Group2, EntryB
+ * BFS order of objects is: Root, Group1, EntryA, Group3, EntryC,
+ Group2, EntryB
SYNCHRONIZING
use boolean;
use namespace::clean;
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
our $WARNINGS = 1;
fieldhashes \my (%SAFE, %KEYS);
has 'meta.database_description_changed' => sub { gmtime }, coerce => \&to_time;
has 'meta.default_username' => '', coerce => \&to_string;
has 'meta.default_username_changed' => sub { gmtime }, coerce => \&to_time;
-has 'meta.maintenance_history_days' => 0, coerce => \&to_number;
+has 'meta.maintenance_history_days' => HISTORY_DEFAULT_MAX_AGE, coerce => \&to_number;
has 'meta.color' => '', coerce => \&to_string;
has 'meta.master_key_changed' => sub { gmtime }, coerce => \&to_time;
has 'meta.master_key_change_rec' => -1, coerce => \&to_number;
my %args = @_;
# find the right group to add the group to
- my $parent = delete $args{group} // delete $args{parent} // $self->root;
+ my $parent = delete $args{group} // $self->root;
$parent = $self->groups->grep({uuid => $parent})->next if !ref $parent;
$parent or throw 'Invalid group';
my %args = @_;
# find the right group to add the entry to
- my $parent = delete $args{group} // delete $args{parent} // $self->root;
+ my $parent = delete $args{group} // $self->root;
$parent = $self->groups->grep({uuid => $parent})->next if !ref $parent;
$parent or throw 'Invalid group';
my $max_items = $args{max_items} // $self->history_max_items // HISTORY_DEFAULT_MAX_ITEMS;
my $max_size = $args{max_size} // $self->history_max_size // HISTORY_DEFAULT_MAX_SIZE;
- my $max_age = $args{max_age} // HISTORY_DEFAULT_MAX_AGE;
+ my $max_age = $args{max_age} // $self->maintenance_history_days // HISTORY_DEFAULT_MAX_AGE;
my @removed;
$self->entries->each(sub {
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
=head1 DESCRIPTION
-B<File::KDBX> provides everything you need to work with a KDBX database. A KDBX database is a hierarchical
+B<File::KDBX> provides everything you need to work with KDBX databases. A KDBX database is a hierarchical
object database which is commonly used to store secret information securely. It was developed for the KeePass
password safe. See L</"Introduction to KDBX"> for more information about KDBX.
-This module lets you query entries, create new entries, delete entries and modify entries. The distribution
-also includes various parsers and generators for serializing and persisting databases.
+This module lets you query entries, create new entries, delete entries, modify entries and more. The
+distribution also includes various parsers and generators for serializing and persisting databases.
-This design of this software was influenced by the L<KeePassXC|https://github.com/keepassxreboot/keepassxc>
+The design of this software was influenced by the L<KeePassXC|https://github.com/keepassxreboot/keepassxc>
implementation of KeePass as well as the L<File::KeePass> module. B<File::KeePass> is an alternative module
that works well in most cases but has a small backlog of bugs and security issues and also does not work with
newer KDBX version 4 files. If you're coming here from the B<File::KeePass> world, you might be interested in
=head2 Features
-This implementation of KDBX supports a lot of features:
-
=over 4
=item *
=item *
-☑ L<One-time passwords|File::KDBX::Entry/"One-time passwords">
+☑ L<One-time passwords|File::KDBX::Entry/"One-time Passwords">
=item *
You can think of a KDBX database kind of like a file system, where groups are directories, entries are files,
and strings and binaries make up a file's contents.
-Databases are typically persisted as a encrypted, compressed files. They are usually accessed directly (i.e.
+Databases are typically persisted as encrypted, compressed files. They are usually accessed directly (i.e.
not over a network). The primary focus of this type of database is data security. It is ideal for storing
relatively small amounts of data (strings and binaries) that must remain secret except to such individuals as
have the correct I<master key>. Even if the database file were to be "leaked" to the public Internet, it
Timestamp indicating when the default username was last changed.
-=head2 maintenance_history_days
-
-TODO... not really sure what this is. 😀
-
=head2 color
A color associated with the database (in the form C<#ffffff> where "f" is a hexidecimal digit). Some agents
=head2 recycle_bin_changed
-Timestamp indicating when the recycle bin was last changed.
+Timestamp indicating when the recycle bin group was last changed.
=head2 entry_templates_group
=head2 history_max_items
-The maximum number of historical entries allowed to be saved for each entry.
+The maximum number of historical entries that should be kept for each entry. Default is 10.
=head2 history_max_size
-The maximum total size (in bytes) that each individual entry's history is allowed to grow.
+The maximum total size (in bytes) that each individual entry's history is allowed to grow. Default is 6 MiB.
+
+=head2 maintenance_history_days
+
+The maximum age (in days) historical entries should be kept. Default it 365.
=head2 settings_changed
Every database has only a single root group at a time. Some old KDB files might have multiple root groups.
When reading such files, a single implicit root group is created to contain the actual root groups. When
writing to such a format, if the root group looks like it was implicitly created then it won't be written and
-the resulting file might have multiple root groups. This allows working with older files without changing
-their written internal structure while still adhering to modern semantics while the database is opened.
+the resulting file might have multiple root groups, as it was before loading. This allows working with older
+files without changing their written internal structure while still adhering to modern semantics while the
+database is opened.
The root group of a KDBX database contains all of the database's entries and other groups. If you replace the
root group, you are essentially replacing the entire database contents with something else.
=item *
-C<group> (aka C<parent>) - Group object or group UUID to add the group to (default: root group)
+C<group> - Group object or group UUID to add the group to (default: root group)
=back
=item *
-C<group> (aka C<parent>) - Group object or group UUID to add the entry to (default: root group)
+C<group> - Group object or group UUID to add the entry to (default: root group)
=back
$key = $kdbx->key($primitive);
Get or set a L<File::KDBX::Key>. This is the master key (e.g. a password or a key file that can decrypt
-a database). See L<File::KDBX::Key/new> for an explanation of what the primitive can be.
+a database). You can also pass a primitive that can be cast to a B<Key>. See L<File::KDBX::Key/new> for an
+explanation of what the primitive can be.
You generally don't need to call this directly because you can provide the key directly to the loader or
dumper when loading or dumping a KDBX file.
$key = $kdbx->composite_key($key);
$key = $kdbx->composite_key($primitive);
-Construct a L<File::KDBX::Key::Composite> from a primitive. See L<File::KDBX::Key/new> for an explanation of
-what the primitive can be. If the primitive does not represent a composite key, it will be wrapped.
+Construct a L<File::KDBX::Key::Composite> from a B<Key> or primitive. See L<File::KDBX::Key/new> for an
+explanation of what the primitive can be. If the primitive does not represent a composite key, it will be
+wrapped.
-You generally don't need to call this directly. The parser and writer use it to transform a master key into
+You generally don't need to call this directly. The loader and dumper use it to transform a master key into
a raw encryption key.
=head2 kdf
If not passed, the UUID comes from C<< $kdbx->headers->{cipher_id} >> and the encryption IV comes from
C<< $kdbx->headers->{encryption_iv} >>.
-You generally don't need to call this directly. The parser and writer use it to decrypt and encrypt KDBX
+You generally don't need to call this directly. The loader and dumper use it to decrypt and encrypt KDBX
files.
=head2 random_stream
C<< $kdbx->inner_headers->{inner_random_stream_key} >> and
C<< $kdbx->inner_headers->{inner_random_stream_id} >> (respectively) for KDBX4 files.
-You generally don't need to call this directly. The parser and writer use it to scramble protected strings.
+You generally don't need to call this directly. The loader and dumper use it to scramble protected strings.
=for Pod::Coverage STORABLE_freeze STORABLE_thaw TO_JSON
To find things in a KDBX database, you should use a filtered iterator. If you have an iterator, such as
returned by L</entries>, L</groups> or even L</objects> you can filter it using L<File::KDBX::Iterator/where>.
- my $filtered_entries = $kdbx->entries->where($query);
+ my $filtered_entries = $kdbx->entries->where(\&query);
-A C<$query> is just a subroutine that you can either write yourself or have generated for you from either
+A C<\&query> is just a subroutine that you can either write yourself or have generated for you from either
a L</"Simple Expression"> or L</"Declarative Syntax">. It's easier to have your query generated, so I'll cover
that first.
=item *
-C<< > >>> - Number greater than
+C<< > >> - Number greater than
=item *
- Group3
- EntryC
+=over 4
+
+=item *
+
IDS order of groups is: Root, Group1, Group2, Group3
+
+=item *
+
IDS order of entries is: EntryA, EntryB, EntryC
+
+=item *
+
IDS order of objects is: Root, Group1, EntryA, Group2, EntryB, Group3, EntryC
+=item *
+
DFS order of groups is: Group2, Group1, Group3, Root
+
+=item *
+
DFS order of entries is: EntryB, EntryA, EntryC
+
+=item *
+
DFS order of objects is: Group2, EntryB, Group1, EntryA, Group3, EntryC, Root
+=item *
+
BFS order of groups is: Root, Group1, Group3, Group2
+
+=item *
+
BFS order of entries is: EntryA, EntryC, EntryB
+
+=item *
+
BFS order of objects is: Root, Group1, EntryA, Group3, EntryC, Group2, EntryB
+=back
+
=head1 SYNCHRONIZING
B<TODO> - This is a planned feature, not yet implemented.
use Scalar::Util qw(looks_like_number);
use namespace::clean;
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
my %CIPHERS;
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
extends 'File::KDBX::Cipher';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
has key_size => 32;
sub iv_size { 16 }
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
extends 'File::KDBX::Cipher';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
has 'counter', is => 'ro', default => 0;
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
use Scalar::Util qw(dualvar);
use namespace::clean -except => 'import';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
BEGIN {
my %CONSTANTS = (
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
use Scalar::Util qw(looks_like_number openhandle);
use namespace::clean;
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub new {
has 'allow_upgrade', is => 'ro', default => 1;
has 'randomize_seeds', is => 'ro', default => 1;
-
-sub min_version { KDBX_VERSION_OLDEST }
-
sub _fh { $_[0]->{fh} or throw 'IO handle not set' }
sub _dump {
my $kdbx = $self->kdbx;
$kdbx->sig1 == KDBX_SIG1 or throw 'Invalid file signature', sig1 => $kdbx->sig1;
- $kdbx->version < $self->min_version || KDBX_VERSION_LATEST < $kdbx->version
+ $kdbx->version < KDBX_VERSION_OLDEST || KDBX_VERSION_LATEST < $kdbx->version
and throw 'Unsupported file version', version => $kdbx->version;
my @magic = ($kdbx->sig1, $kdbx->sig2, $kdbx->version);
=head1 VERSION
-version 0.800
+version 0.900
=head1 ATTRIBUTES
$dumper = $dumper->reset;
-Set a L<File::KDBX::Dumper> to a blank state, ready to dumper another KDBX file.
+Set a L<File::KDBX::Dumper> to a blank state, ready to dump another KDBX file.
=head2 dump
Dump a KDBX file.
-The C<$key> is either a L<File::KDBX::Key> or a primitive that can be converted to a Key object.
+The C<$key> is either a L<File::KDBX::Key> or a primitive that can be cast to a Key object.
=head2 dump_string
$dumper->dump_handle($fh, $key);
$dumper->dump_handle(*IO, $key);
-Dump a KDBX file to an input stream / file handle.
-
-=head2 min_version
-
- $min_version = File::KDBX::Dumper->min_version;
-
-Get the minimum KDBX file version supported, which is 3.0 or C<0x00030000> as
-it is encoded.
-
-To generate older KDBX files unsupported by this module, try L<File::KeePass>.
+Dump a KDBX file to an output stream / file handle.
=head1 BUGS
extends 'File::KDBX::Dumper';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub _write_magic_numbers { '' }
sub _write_headers { '' }
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
extends 'File::KDBX::Dumper';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub _dump {
my $self = shift;
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
extends 'File::KDBX::Dumper';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub _write_headers {
my $self = shift;
=head1 VERSION
-version 0.800
+version 0.900
=head1 BUGS
extends 'File::KDBX::Dumper';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
has _binaries_written => {}, is => 'ro';
=head1 VERSION
-version 0.800
+version 0.900
=head1 BUGS
extends 'File::KDBX::Dumper';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
has allow_protection => 1;
=head1 VERSION
-version 0.800
+version 0.900
=head1 ATTRIBUTES
format uses HMAC-SHA256 to detect tampering.
L<File::KDBX::Dumper::V3> automatically calculates the header hash an provides it to this module, and plain
-XML files which don't have a KDBX wrapper don't have headers and so should have a header hash. Therefore there
-is probably never any reason to set this manually.
+XML files which don't have a KDBX wrapper don't have headers and so should not have a header hash. Therefore
+there is probably never any reason to set this manually.
=head1 BUGS
extends 'File::KDBX::Object';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
my $PLACEHOLDER_MAX_DEPTH = 10;
my %PLACEHOLDERS;
my $max_items = $args{max_items} // eval { $self->kdbx->history_max_items } // HISTORY_DEFAULT_MAX_ITEMS;
my $max_size = $args{max_size} // eval { $self->kdbx->history_max_size } // HISTORY_DEFAULT_MAX_SIZE;
- my $max_age = $args{max_age} // HISTORY_DEFAULT_MAX_AGE;
+ my $max_age = $args{max_age} // eval { $self->kdbx->maintenance_history_days } // HISTORY_DEFAULT_MAX_AGE;
# history is ordered oldest to newest
my $history = $self->history;
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
=back
-If the current date and time is <2012-07-25 17:05:34>, the "simple" form would be C<20120725170534>.
+If the current date and time is C<2012-07-25 17:05:34>, the "simple" form would be C<20120725170534>.
=head3 Special Key Placeholders
If the placeholder is expanded in the context of an entry, C<$entry> is the B<File::KDBX::Entry> object in
context. Otherwise it is C<undef>. An entry is in context if, for example, the placeholder is in an entry's
-strings or auto-complete key sequences.
+strings or auto-type key sequences.
$File::KDBX::PLACEHOLDERS{'MY_PLACEHOLDER:'} = sub {
my ($entry, $arg) = @_; # ^ Notice the colon here
=head1 ATTRIBUTES
-=head2 uuid
-
-128-bit UUID identifying the entry within the database.
-
-=head2 icon_id
-
-Integer representing a default icon. See L<File::KDBX::Constants/":icon"> for valid values.
-
-=head2 custom_icon_uuid
-
-128-bit UUID identifying a custom icon within the database.
-
=head2 foreground_color
Text color represented as a string of the form C<#000000>.
TODO
-=head2 tags
-
-Text string with arbitrary tags which can be used to build a taxonomy.
-
=head2 auto_type_enabled
Whether or not the entry is eligible to be matched for auto-typing.
Keystroke sequences can have </Placeholders>, most commonly C<{USERNAME}> and C<{PASSWORD}>.
-=head2 previous_parent_group
-
-128-bit UUID identifying a group within the database.
-
=head2 quality_check
Boolean indicating whether the entry password should be tested for weakness and show up in reports.
There are methods available to provide more convenient access to binaries, including L</binary> and
L</binary_value>.
-=head2 custom_data
-
-A set of key-value pairs used to store arbitrary data, usually used by software to keep track of state rather
-than by end users (who typically work with the strings and binaries).
-
=head2 history
Array of historical entries. Historical entries are prior versions of the same entry so they all share the
same UUID with the current entry.
-=head2 last_modification_time
-
-Date and time when the entry was last modified.
-
-=head2 creation_time
-
-Date and time when the entry was created.
-
-=head2 last_access_time
-
-Date and time when the entry was last accessed.
-
-=head2 expiry_time
-
-Date and time when the entry expired or will expire.
-
-=head2 expires
-
-Boolean value indicating whether or not an entry is expired.
-
-=head2 usage_count
-
-The number of times an entry has been used, which typically means how many times the B<Password> string has
-been accessed.
-
-=head2 location_changed
-
-Date and time when the entry was last moved to a different parent group.
-
=head2 notes
Alias for the B<Notes> string value.
use Scalar::Util qw(blessed looks_like_number);
use namespace::clean -except => 'import';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
our @EXPORT = qw(alert error throw);
=head1 VERSION
-version 0.800
+version 0.900
=head1 ATTRIBUTES
extends 'File::KDBX::Object';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
# has uuid => sub { generate_uuid(printable => 1) };
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
=head1 ATTRIBUTES
-=head2 uuid
-
-128-bit UUID identifying the group within the database.
-
=head2 name
The human-readable name of the group.
Free form text string associated with the group.
-=head2 tags
-
-Text string with arbitrary tags which can be used to build a taxonomy.
-
-=head2 icon_id
-
-Integer representing a default icon. See L<File::KDBX::Constants/":icon"> for valid values.
-
-=head2 custom_icon_uuid
-
-128-bit UUID identifying a custom icon within the database.
-
=head2 is_expanded
Whether or not subgroups are visible when listed for user selection.
The UUID of the entry visible at the top of the list.
-=head2 custom_data
-
-A set of key-value pairs used to store arbitrary data, usually used by software to keep track of state rather
-than by end users (who typically work with the strings and binaries).
-
-=head2 previous_parent_group
-
-128-bit UUID identifying a group within the database.
-
=head2 entries
Array of entries contained within the group.
Array of subgroups contained within the group.
-=head2 last_modification_time
-
-Date and time when the entry was last modified.
-
-=head2 creation_time
-
-Date and time when the entry was created.
-
-=head2 last_access_time
-
-Date and time when the entry was last accessed.
-
-=head2 expiry_time
-
-Date and time when the entry expired or will expire.
-
-=head2 expires
-
-Boolean value indicating whether or not an entry is expired.
-
-=head2 usage_count
-
-TODO
-
-=head2 location_changed
-
-Date and time when the entry was last moved to a different parent group.
-
=head1 METHODS
=head2 entries
\@entries = $group->entries;
-Get an array of direct entries within a group.
+Get an array of direct child entries within a group.
=head2 entries_deeply
$bool = $group->is_entry_templates;
-Get whether or not a group is the group containing entry template of its connected database.
+Get whether or not a group is the group containing entry template in its connected database.
=head2 is_last_selected
extends 'IO::Handle';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub _croak { require Carp; goto &Carp::croak }
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
extends 'File::KDBX::IO';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
our $BUFFER_SIZE = 16384;
our $ERROR;
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
extends 'File::KDBX::IO';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
our $ALGORITHM = 'SHA256';
our $BLOCK_SIZE = 1048576; # 1MiB
our $ERROR;
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
extends 'File::KDBX::IO';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
our $BLOCK_SIZE = 1048576; # 1MiB
our $ERROR;
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
BEGIN { mark_as_loaded('Iterator::Simple::Iterator') }
extends 'Iterator::Simple::Iterator';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub new {
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
=head2 Buffer
This iterator is buffered, meaning it can drain from an iterator subroutine under the hood, storing items
-temporarily to be accessed later. This allows features like L</peek> and L</sort> which might be useful in the
-context of KDBX databases which are normally pretty small so draining an iterator isn't cost-prohibitive.
+temporarily to be accessed later. This allows features like L</peek> and L</order_by> which might be useful in
+the context of KDBX databases which are normally pretty small so draining an iterator completely isn't
+cost-prohibitive in terms of memory usage.
The way this works is that if you call an iterator without arguments, it acts like a normal iterator. If you
call it with arguments, however, the arguments are added to the buffer. When called without arguments, the
buffer is drained before the iterator function is. Using L</unget> is equivalent to calling the iterator with
-arguments, and as L</next> is equivalent to calling the iterator without arguments.
+arguments, and L</next> is equivalent to calling the iterator without arguments.
=head1 METHODS
\&iterator = File::KDBX::Iterator->new(\&iterator);
-Blesses an iterator to augment it with buffering plus some useful utility methods.
+Bless an iterator to augment it with buffering plus some useful utility methods.
=head2 next
$item = $iterator->();
$item = $iterator->next(\&query);
- $item = $iterator->next([\'simple expression', @fields]);
Get the next item or C<undef> if there are no more items. If a query is passed, get the next matching item,
discarding any unmatching items before the matching item. Example:
=head2 unget
+ # Replace buffer:
$iterator->unget(\@items);
- $iterator->unget(...);
# OR equivalently
$iterator->(\@items);
- $iterator->(...);
-Replace the buffer or unshift one or more items to the current buffer.
+ # Unshift onto buffer:
+ $iterator->unget(@items);
+ # OR equivalently
+ $iterator->(@items);
+
+Replace the buffer (first form) or unshift one or more items to the current buffer (second form).
See L</Buffer>.
$iterator->each($method_name, ...);
-Get or act on the rest of the items. There are three forms:
+Get or act on the rest of the items. This method has three forms:
=over 4
=item 2
-Pass a coderef to be called once per item, in order. Arguments to the coderef are the item itself (also C<$_>), its index number and then any extra arguments that were passed to C<each> after the coderef.
+Pass a coderef to be called once per item, in order. Arguments to the coderef are the item itself (also available as C<$_>), its index number and then any extra arguments that were passed to C<each> after the coderef.
=item 3
=head2 where
\&iterator = $iterator->grep(\&query);
- \&iterator = $iterator->grep([\'simple expression', @fields]);
Get a new iterator draining from an existing iterator but providing only items that pass a test or are matched
-by a query.
+by a query. In its basic form this method is very much like perl's built-in grep function, except for
+iterators.
+
+There are many examples of the various forms of this method at L<File::KDBX/QUERY>.
=head2 map
\&iterator = $iterator->map(\&code);
-Get a new iterator draining from an existing iterator but providing modified items.
+Get a new iterator draining from an existing iterator but providing modified items. In its basic form this
+method is very much like perl's built-in map function, except for iterators.
=head2 order_by
=back
-C<sort_by> and C<order_by> are aliases.
-
B<NOTE:> This method drains the iterator completely and places the sorted items onto the buffer. See
L</CAVEATS>.
=back
-C<nsort_by> and C<norder_by> are aliases.
-
B<NOTE:> This method drains the iterator completely and places the sorted items onto the buffer. See
L</CAVEATS>.
Get a new iterator draining from an existing iterator but providing only a limited number of items.
-C<limit> as an alias for L<Iterator::Simple/"$iterator->head($count)">.
+C<limit> as an alias for L<< Iterator::Simple/"$iterator->head($count)" >>.
=head2 to_array
use Scalar::Util qw(blessed);
use namespace::clean;
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
my %KDFS;
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
extends 'File::KDBX::KDF';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
# Rounds higher than this are eligible for forking:
my $FORK_OPTIMIZATION_THRESHOLD = 100_000;
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
extends 'File::KDBX::KDF';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub salt { $_[0]->{+KDF_PARAM_ARGON2_SALT} or throw 'Salt is not set' }
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
use Scalar::Util qw(blessed openhandle);
use namespace::clean;
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
fieldhashes \my %SAFE;
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
=item *
-L<File::KDBX::Key::File> - Possession of a file ("key file") with a secret.
+L<File::KDBX::Key::File> - Possession of a file ("key file") with a secret
=item *
B<COMPATIBILITY NOTE:> Most KeePass implementations are limited in the types and numbers of keys they support.
B<Password> keys are pretty much universally supported. B<File> keys are pretty well-supported. Many do not
support challenge-response keys. If you are concerned about compatibility, you should stick with one of these
-configurations:
+well-supported configurations:
=over 4
=item *
-One password and one key file
+Composite of one password and one key file
=back
$key = $key->hide;
-Put the raw key in L<File::KDBX/"Memory Protection">. Does nothing if the raw key is already in memory
-protection. Returns itself to allow method chaining.
+Put the raw key in L<memory protection|File::KDBX/"Memory Protection">. Does nothing if the raw key is already
+in memory protection. Returns itself to allow method chaining.
=head2 show
extends 'File::KDBX::Key';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub init {
my $self = shift;
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
A challenge-response key is kind of like multifactor authentication, except you don't really I<authenticate>
to a KDBX database because it's not a service. Specifically it would be the "what you have" component. It
-assumes there is some device that can store a key that is only known to the unlocker of a database.
-A challenge is made to the device and the response generated based on the key is used as the raw key.
+assumes there is some device that can store a key that is only known to the owner of a database. A challenge
+is made to the device and the response generated based on the key is used as the raw key.
Inherets methods and attributes from L<File::KDBX::Key>.
$raw_key = $key->raw_key($challenge);
Get the raw key which is the response to a challenge. The response will be saved so that subsequent calls
-(with or without the challenge) can provide the response without challenging the responder again. Only once
+(with or without the challenge) can provide the response without challenging the responder again. Only one
response is saved at a time; if you call this with a different challenge, the new response is saved over any
previous response.
extends 'File::KDBX::Key';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub init {
my $self = shift;
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
extends 'File::KDBX::Key';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
has 'type', is => 'ro';
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
$type = $key->type;
-Get the type of key file. Can be one of:
+Get the type of key file. Can be one of from L<File::KDBX::Constants/":key_file">:
=over 4
extends 'File::KDBX::Key';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub init {
my $self = shift;
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
extends 'File::KDBX::Key::ChallengeResponse';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
# It can take some time for the USB device to be ready again, so we can retry a few times.
our $RETRY_COUNT = 5;
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
use Scalar::Util qw(looks_like_number openhandle);
use namespace::clean;
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub new {
has inner_format => 'XML', is => 'ro';
-sub min_version { KDBX_VERSION_OLDEST }
-
-
sub read_magic_numbers {
my $self = shift;
my $fh = shift;
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
=item *
-C<Raw> - Read parsing and store the result in L<File::KDBX/raw>
+C<Raw> - Read and store the result in L<File::KDBX/raw> without parsing
=back
Load a KDBX file.
-The C<$key> is either a L<File::KDBX::Key> or a primitive that can be converted to a Key object.
+The C<$key> is either a L<File::KDBX::Key> or a primitive that can be cast to a Key object.
=head2 load_string
Read a KDBX file from an input stream / file handle.
-=head2 min_version
-
- $min_version = File::KDBX::Loader->min_version;
-
-Get the minimum KDBX file version supported, which is 3.0 or C<0x00030000> as
-it is encoded.
-
-To read older KDBX files unsupported by this module, try L<File::KeePass>.
-
=head2 read_magic_numbers
$magic = File::KDBX::Loader->read_magic_numbers($fh);
extends 'File::KDBX::Loader';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
my $DEFAULT_EXPIRATION = Time::Piece->new(32503677839); # 2999-12-31 23:59:59
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
extends 'File::KDBX::Loader';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub _read {
my $self = shift;
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
extends 'File::KDBX::Loader';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub _read_header {
my $self = shift;
=head1 VERSION
-version 0.800
+version 0.900
=head1 BUGS
extends 'File::KDBX::Loader';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub _read_header {
my $self = shift;
=head1 VERSION
-version 0.800
+version 0.900
=head1 BUGS
extends 'File::KDBX::Loader';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
has '_reader', is => 'ro';
has '_safe', is => 'ro', default => sub { File::KDBX::Safe->new(cipher => $_[0]->kdbx->random_stream) };
=head1 VERSION
-version 0.800
+version 0.900
=head1 BUGS
use Scalar::Util qw(blessed weaken);
use namespace::clean;
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
fieldhashes \my (%KDBX, %PARENT, %TXNS, %REFS, %SIGNALS);
=head1 VERSION
-version 0.800
+version 0.900
=head1 DESCRIPTION
$kdbx = $object->kdbx;
$object->kdbx($kdbx);
-Get or set the L<File::KDBX> instance connected with this object.
+Get or set the L<File::KDBX> instance connected with this object. Throws if the object is disconnected. Other
+object methods might only work if the object is connected to a database and so they might also throw if the
+object is disconnected. If you're not sure if an object is connected, try L</is_connected>.
+
+=head2 uuid
+
+128-bit UUID identifying the object within the connected database.
+
+=head2 icon_id
+
+Integer representing a default icon. See L<File::KDBX::Constants/":icon"> for valid values.
+
+=head2 custom_icon_uuid
+
+128-bit UUID identifying a custom icon within the connected database.
+
+=head2 tags
+
+Text string with arbitrary tags which can be used to build a taxonomy.
+
+=head2 previous_parent_group
+
+128-bit UUID identifying a group within the connected database the previously contained the object.
+
+=head2 last_modification_time
+
+Date and time when the entry was last modified.
+
+=head2 creation_time
+
+Date and time when the entry was created.
+
+=head2 last_access_time
+
+Date and time when the entry was last accessed.
+
+=head2 expiry_time
+
+Date and time when the entry expired or will expire.
+
+=head2 expires
+
+Boolean value indicating whether or not an entry is expired.
+
+=head2 usage_count
+
+The number of times an entry has been used, which typically means how many times the B<Password> string has
+been accessed.
+
+=head2 location_changed
+
+Date and time when the entry was last moved to a different parent group.
=head1 METHODS
$object = $object->remove(%options);
Remove an object from its parent. If the object is a group, all contained objects stay with the object and so
-are removed as well. Options:
+are removed as well, just like cutting off a branch takes the leafs as well. Options:
=over 4
$object->custom_data(%data);
$object->custom_data(key => $value, %data);
-Get and set custom data. Custom data is metadata associated with an object.
+Get and set custom data. Custom data is metadata associated with an object. It is a set of key-value pairs
+used to store arbitrary data, usually used by software like plug-ins to keep track of state rather than by end
+users.
Each data item can have a few attributes associated with it.
use Scalar::Util qw(refaddr);
use namespace::clean;
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub new {
=head1 VERSION
-version 0.800
+version 0.900
=head1 SYNOPSIS
use File::KDBX::Util qw(:class);
use namespace::clean;
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
sub new {
=head1 VERSION
-version 0.800
+version 0.900
=head1 ATTRIBUTES
use boolean;
use namespace::clean -except => 'import';
-our $VERSION = '0.800'; # VERSION
+our $VERSION = '0.900'; # VERSION
our %EXPORT_TAGS = (
assert => [qw(DEBUG assert assert_64bit)],
=head1 VERSION
-version 0.800
+version 0.900
=head1 FUNCTIONS
for this function, but this code is distinct, supporting an overlapping but not identical feature set and
having its own bugs.
-See L<File::KDBX/QUERY> for examples.
+See L<File::KDBX/"Declarative Syntax"> for examples.
=head2 query_any
'IO::Handle' => '0',
'IPC::Cmd' => '0.52',
'Iterator::Simple' => '0',
- 'Iterator::Simple::Iterator' => '0',
'List::Util' => '1.33',
'Module::Load' => '0',
'Module::Loaded' => '0',