File-KDBX
view release on metacpan or search on metacpan
lib/File/KDBX/Loader/KDB.pm view on Meta::CPAN
package File::KDBX::Loader::KDB;
# ABSTRACT: Read KDB files
use warnings;
use strict;
use Encode qw(encode);
use File::KDBX::Constants qw(:header :cipher :random_stream :icon);
use File::KDBX::Error;
use File::KDBX::Util qw(:class :empty :io :uuid load_optional);
use File::KDBX;
use Ref::Util qw(is_arrayref is_hashref);
use Scalar::Util qw(looks_like_number);
use Time::Piece 1.33;
use boolean;
use namespace::clean;
extends 'File::KDBX::Loader';
our $VERSION = '0.906'; # VERSION
my $DEFAULT_EXPIRATION = Time::Piece->strptime('2999-12-31 23:59:59', '%Y-%m-%d %H:%M:%S');
sub _read_headers { '' }
sub _read_body {
my $self = shift;
my $fh = shift;
my $key = shift;
my $buf = shift;
load_optional('File::KeePass');
$buf .= do { local $/; <$fh> };
$key = $self->kdbx->composite_key($key, keep_primitive => 1);
my $k = eval { File::KeePass->new->parse_db(\$buf, _convert_kdbx_to_keepass_master_key($key)) };
if (my $err = $@) {
throw 'Failed to parse KDB file', error => $err;
}
$k->unlock;
$self->kdbx->key($key);
return convert_keepass_to_kdbx($k, $self->kdbx);
}
# This is also used by File::KDBX::Dumper::KDB.
sub _convert_kdbx_to_keepass_master_key {
my $key = shift;
my @keys = @{$key->keys};
if (@keys == 1 && !$keys[0]->can('filepath')) {
return [encode('CP-1252', $keys[0]->{primitive})]; # just a password
}
elsif (@keys == 1) {
return [undef, \$keys[0]->raw_key]; # just a keyfile
}
elsif (@keys == 2 && !$keys[0]->can('filepath') && $keys[1]->can('filepath')) {
return [encode('CP-1252', $keys[0]->{primitive}), \$keys[1]->raw_key];
}
throw 'Cannot use this key to load a KDB file', key => $key;
}
sub convert_keepass_to_kdbx {
my $k = shift;
my $kdbx = shift // File::KDBX->new;
$kdbx->{headers} //= {};
_convert_keepass_to_kdbx_headers($k->{header}, $kdbx);
( run in 1.287 second using v1.01-cache-2.11-cpan-39bf76dae61 )