NAME

    File::KeePass::KDBX - Read and write KDBX files (using the File::KDBX
    backend)

VERSION

    version 0.900

SYNOPSIS

        use File::KeePass::KDBX;
    
        my $k = File::KeePass::KDBX->new($kdbx);
        # OR
        my $k = File::KeePass::KDBX->load_db($filepath, $password);
    
        print Dumper $k->header;
        print Dumper $k->groups; # passwords are locked
    
        $k->unlock;
        print Dumper $k->groups; # passwords are now visible

    See File::KeePass for a more complete synopsis.

DESCRIPTION

    This is a File::KeePass compatibility shim for File::KDBX. It presents
    the same interface as File::KeePass (mostly, see "Discrepancies") but
    uses File::KDBX for database storage, file parsing, etc. It is meant to
    be a drop-in replacement for File::KeePass. Documentation here might be
    somewhat thin, so just refer to the File::KeePass documentation since
    everything should look the same.

    Unlike File::KDBX itself, this module is EXPERIMENTAL. How it works
    might change in the future -- although by its nature it will aim to be
    as compatible as possible with the File::KeePass interface, so it's
    stable enough to start using without fear of interface changes. Just
    don't depend on any of its guts (which you shouldn't do even if it were
    completely "stable").

    File::KeePass::KDBX incorporates some of the code from File::KeePass
    but it is not a required dependency and need not be installed for basic
    functionality. If File::KeePass is installed, it will be used as a
    backend parser and generator for working with older KDB (KeePass 1)
    files since File::KDBX has no native KDB parser.

ATTRIBUTES

 kdbx

        $kdbx = $k->kdbx;
        $k->kdbx($kdbx);

    Get or set the File::KDBX instance. The File::KDBX is the object that
    actually contains the database data, so setting this will implicitly
    replace all of the data with data from the new database.

    Getting the File::KDBX associated with a File::KeePass::KDBX grants you
    access to new functionality that File::KeePass doesn't have any
    interface for, including:

      * KDBX4-exclusive data (e.g. KDF parameters and public custom data
      headers)

      * "Placeholders" in File::KDBX

      * One-time passwords

      * Search using "Simple Expressions"

      * and more

 default_exp

        $string = $k->default_exp;

    Get the default value to use as the expiry time.

 auto_lock

    Get and set whether the database will be locked initially after load.
    Regardless, the database can always be manually locked and unlocked at
    any time.

    See "auto_lock" in File::KeePass.

METHODS

 new

        $k = File::KeePass::KDBX->new(%attributes);
        $k = File::KeePass::KDBX->new($kdbx);
        $k = File::KeePass::KDBX->new($keepass);

    Construct a new KeePass 2 database from a set of attributes, a
    File::KDBX instance or a File::KeePass instance.

 clone

        $k_copy = $k->clone;
        OR
        $k_copy = File::KeePass::KDBX->new($k);

    Make a copy.

 clear

        $k->clear;

    Reset the database to a freshly initialized state.

    See "clear" in File::KeePass.

 to_fkp

        $fkp = $k->to_fkp;

    Convert a File::KeePass::KDBX to a File::KeePass. The resulting object
    is a separate copy of the database; each can be modified independently.

 from_fkp

        $k = File::KeePass::KDBX->from_fkp($fkp);

    Convert a File::KeePass to a File::KeePass::KDBX. The resulting object
    is a separate copy of the database; each can be modified independently.

 load_db

        $k = $k->load_db($filepath, $key);
        $k = File::KeePass::KDBX->load_db($filepath, $key, \%args);

    Load a database from a file. $key is a master key, typically a password
    or passphrase and might also include a keyfile path (e.g. [$password,
    $keyfile]). %args are the same as for "new".

    See "load_db" in File::KeePass.

 parse_db

        $k = $k->parse_db($string, $key);
        $k = File::KeePass::KDBX->parse_db($string, $key, \%args);

    Load a database from a string. $key is a master key, typically a
    password or passphrase and might also include a keyfile path (e.g.
    [$password, $keyfile]). %args are the same as for "new".

    See "parse_db" in File::KeePass.

 parse_header

        \%head = $k->parse_header($string);

    Parse only the header.

    See "parse_header" in File::KeePass.

 save_db

        $k->save_db($filepath, $key);

    Save the database to a file. $key is a master key, typically a password
    or passphrase and might also include a keyfile path (e.g. [$password,
    $keyfile]).

    See "save_db" in File::KeePass.

 gen_db

        $db_string = $k->gen_db($key);

    Save the database to a string. $key is a master key, typically a
    password or passphrase and might also include a keyfile path (e.g.
    [$password, $keyfile]).

    See "gen_db" in File::KeePass.

 header

        \%header = $k->header;

    Get the database file headers and KDBX metadata.

    See "header" in File::KeePass.

 groups

        \@groups = $k->groups;

    Get the groups and entries stored in a database. This is the same data
    that "groups" in File::KDBX provides but in a shape compatible with
    "groups" in File::KeePass.

 dump_groups

        $string = $k->dump_groups;
        $string = $k->dump_groups(\%query);

    Get a string representation of the groups in the database.

    See "dump_groups" in File::KeePass.

 add_group

        $group = $k->add_group(\%group_info);

    Add a new group.

    See "add_group" in File::KeePass.

 find_groups

        @groups = $k->find_groups(\%query);

    Find groups.

    See "find_groups" in File::KeePass.

 find_group

        $group = $k->find_group(\%query);

    Find one group. If the query matches more than one group, an exception
    is thrown. If there is no matching group, undef is returned

    See "find_group" in File::KeePass.

 delete_group

        $group = $k->delete_group(\%query);

    Delete a group.

    See "delete_group" in File::KeePass.

 add_entry

        $entry = $k->add_entry(\%entry_info);

    Add a new entry.

    See "add_entry" in File::KeePass.

 find_entries

        @entries = $k->find_entries(\%query);

    Find entries.

    See "find_entries" in File::KeePass.

 find_entry

        $entry = $k->find_entry(\%query);

    Find one entry. If the query matches more than one entry, an exception
    is thrown. If there is no matching entry, undef is returned

    See "find_entry" in File::KeePass.

 delete_entry

        $entry = $k->delete_entry(\%query);

    Delete an entry.

    See "delete_entry" in File::KeePass.

 finder_tests

        @tests = $k->finder_tests(\%query);

    This is the query engine used to find groups and entries.

    See "finder_tests" in File::KeePass.

 now

        $string = $k->now;

    Get a timestamp representing the current date and time.

 is_locked

        $bool = $k->is_locked;

    Get whether or not a database is locked (i.e. memory-protected
    passwords).

    See "is_locked" in File::KeePass.

 lock

        $k->lock;

    Lock a database.

    See "lock" in File::KeePass.

 unlock

        $k->unlock;

    Unlock a database.

    See "unlock" in File::KeePass.

 locked_entry_password

        $password = $k->locked_entry_password($entry);

    Get a memory-protected password.

    See "locked_entry_password" in File::KeePass.

CAVEATS

    This shim uses perltie magics. Some data structures look and act like
    regular hashes and arrays (mostly), but you might notice some
    unexpected magical things happen, like hash fields that populate
    themselves. The magic is only there to make matching the File::KeePass
    interface possible, since that interface assumes some amount of
    interaction with unblessed data structures. Some effort was made to at
    least hide the magic where reasonable; any magical behavior is
    incidental and not considered a feature.

    You should expect some considerable overhead which makes this module
    generally slower than using either File::KeePass or File::KDBX
    directly. In some cases this might be due to an inefficient
    implementation in the shim, but largely it is the cost of transparent
    compatibility.

    If performance is critical and you still don't want to rewrite your
    code to use File::KDBX directly but do want to take advantage of some
    of the new stuff, there is also the option to go part way. The strategy
    here is to use File::KeePass::KDBX to load a database and then
    immediately convert it to a File::KeePass object. Use that object
    without any runtime overhead, and then if and when you're ready to save
    the database or use any other File::KDBX feature, "upgrade" it back
    into a File::KeePass::KDBX object. This strategy would require modest
    code modifications to your application, to change:

        my $k = File::KeePass->new('database.kdbx', 'masterpw');

    to this:

        my $k = File::KeePass::KDBX->load_db('database.kdbx', 'masterpw')->to_fkp;
        # $k is a normal File::KeePass

    and change:

        $k->save_db('database.kdbx', 'masterpw');

    to this:

        File::KeePass::KDBX->from_fkp($k)->save_db('database.kdbx', 'masterpw');

    This works because File::KeePass::KDBX provides methods "to_fkp" and
    "from_fkp" for converting to and from File::KeePass. "new" also works
    instead of "from_fkp".

 Discrepancies

    This shim is supposed to be a drop-in replacement for File::KeePass. If
    you're sticking to the File::KeePass public interface you probably
    won't have to rewrite any code. If you do, it could be considered a
    File::KeePass::KDBX bug. But there are some differences that some code
    might notice and could even get tripped up on:

    File::KeePass::KDBX does not provide any of the "UTILITY METHODS" in
    File::KeePass or "OTHER METHODS" in File::KeePass unless incidentally,
    with two exceptions: "now" and "default_exp". I judge these other
    methods to not be useful for users of File::KeePass and so probably
    aren't used by anyone, but if I'm wrong you can get them by using
    File::KeePass:

        use File::KeePass;  # must use before File::KeePass::KDBX
        use File::KeePass::KDBX;

    Using both File::KeePass and File::KeePass::KDBX in this order will
    make the latter a proper subclass of the former, so all the utility
    methods will be available via inheritance. You might also need to do
    this if the answer to File::KeePass::KDBX->new->isa('File::KeePass') is
    important to your code.

    File::KeePass::KDBX does not take any pains to replicate File::KeePass
    bugs <https://rt.cpan.org/Public/Dist/Display.html?Name=File-KeePass>.
    If your code has any workarounds, you might need or want to undo those.
    The issues known to be fixed (or not applicable) by using
    File::KeePass::KDBX are: #85012
    <https://rt.cpan.org/Ticket/Display.html?id=85012>, #82582
    <https://rt.cpan.org/Ticket/Display.html?id=82582>, #124531
    <https://rt.cpan.org/Ticket/Display.html?id=124531>, #123330
    <https://rt.cpan.org/Ticket/Display.html?id=123330>, #120224
    <https://rt.cpan.org/Ticket/Display.html?id=120224>, #117836
    <https://rt.cpan.org/Ticket/Display.html?id=117836>, #97055
    <https://rt.cpan.org/Ticket/Display.html?id=97055>, #96049
    <https://rt.cpan.org/Ticket/Display.html?id=96049>, #94753
    <https://rt.cpan.org/Ticket/Display.html?id=94753> and #87109
    <https://rt.cpan.org/Ticket/Display.html?id=87109>.

    File::KeePass provides the header_size field in the "header", which is
    the size of the file header in number of bytes. File::KeePass::KDBX
    does not.

    File::KeePass supports a keep_xml option on "load_db" to retain a copy
    of the XML of a KDBX file from the parser as a string.
    File::KeePass::KDBX does not support this option. To do something
    similar with File::KDBX:

        my $kdbx = File::KDBX->load($filepath, $key, inner_format => 'Raw');
        my $xml = $kdbx->raw;

    There might be idiosyncrasies related to default values and when
    they're set. Fields within data structures might exist but be undefined
    in one where they just don't exist in the other. You might need to
    check for values using "defined" in perlfunc instead of "exists" in
    perlfunc.

    File::KeePass::KDBX might have slightly different error handling
    semantics. It might be stricter or fail earlier in some cases. For
    example, setting a date & time or UUID with an invalid format might
    fail immediately rather than later on in a query or at file generation.
    To achieve perfect consistency, you might need to validate your inputs
    and handle errors before passing them to File::KeePass::KDBX.

    Some methods have different performance profiles from their
    File::KeePass counterparts. Operations that are constant time in
    File::KeePass might be linear in File::KeePass::KDBX, for example. Or
    some things in File::KeePass::KDBX might be faster than File::KeePass.
    Of course you are not likely to detect any differences unless you work
    with very large databases, and I don't know of any application where
    large KDBX databases are common. I don't think any KDBX implementation
    is optimized for large databases.

BUGS

    Please report any bugs or feature requests on the bugtracker website
    https://github.com/chazmcgarvey/File-KeePass-KDBX/issues

    When submitting a bug or request, please include a test-file or a patch
    to an existing test-file that illustrates the bug or desired feature.

AUTHOR

    Charles McGarvey <ccm@cpan.org>

COPYRIGHT AND LICENSE

    This software is copyright (c) 2022 by Charles McGarvey.

    This is free software; you can redistribute it and/or modify it under
    the same terms as the Perl 5 programming language system itself.

