File-KeePass-KDBX
view release on metacpan or search on metacpan
lib/File/KeePass/KDBX.pm view on Meta::CPAN
package File::KeePass::KDBX;
# ABSTRACT: Read and write KDBX files (using the File::KDBX backend)
use utf8;
use warnings;
use strict;
use Crypt::PRNG qw(irand);
use Crypt::Misc 0.029 qw(decode_b64 encode_b64);
use File::KDBX 0.900;
use File::KDBX::Constants qw(:header :magic :version);
use File::KDBX::Loader::KDB;
use File::KDBX::Util qw(clone_nomagic generate_uuid load_optional);
use Hash::Util::FieldHash qw(fieldhashes);
use Module::Load;
use Scalar::Util qw(blessed looks_like_number weaken);
use boolean;
use namespace::clean;
our $VERSION = '0.902'; # VERSION
fieldhashes \my (%KDBX, %TIED);
BEGIN {
our @ISA;
@ISA = qw(File::KeePass) if $INC{'File/KeePass.pm'};
}
sub new {
my $class = shift;
# copy constructor
return $_[0]->clone if @_ == 1 && (blessed $_[0] // '') eq __PACKAGE__;
if (@_ == 1 && blessed $_[0] && $_[0]->isa('File::KeePass')) {
return $class->from_fkp(@_);
}
if (@_ == 1 && blessed $_[0] && $_[0]->isa('File::KDBX')) {
my $self = bless {}, $class;
$self->kdbx($_[0]);
return $self;
}
my $args = ref $_[0] ? {%{$_[0]}} : {@_};
my $self = bless $args, $class;
exists $args->{kdbx} and $self->kdbx(delete $args->{kdbx});
return $self;
}
sub DESTROY { $_[0]->clear }
sub clone {
my $self = shift;
require Storable;
return Storable::dclone($self);
}
sub STORABLE_freeze {
my $self = shift;
my $copy = {%$self};
delete @$self{qw(header groups)};
return '', $copy, $KDBX{$self};
}
sub STORABLE_thaw {
my $self = shift;
my $cloning = shift;
shift; # empty
my $copy = shift;
my $kdbx = shift;
@$self{keys %$copy} = values %$copy;
$self->kdbx($kdbx) if $kdbx;
lib/File/KeePass/KDBX.pm view on Meta::CPAN
return $uniq->{$id} ||= do {
if (length($id) != 16) {
$id = substr($self->encode_base64($id), 0, 16) if $id !~ /^\d+$/ || $id > 2**32-1;
$id = sprintf '%016s', $id if $id ne '0';
}
$id = $self->gen_uuid while $uniq->{$id}++;
$id;
};
}
##############################################################################
sub auto_lock {
my $self = shift;
$self->{auto_lock} = shift if @_;
$self->{auto_lock} //= 1;
}
sub is_locked { $_[0]->kdbx->is_locked }
sub lock { $_[0]->kdbx->lock }
sub unlock { $_[0]->kdbx->unlock }
sub locked_entry_password {
my $self = shift;
my $entry = shift;
$self->is_locked or die "Passwords are not locked\n";
$entry = $self->find_entry({id => $entry}) if !ref $entry;
return if !$entry;
my $entry_obj = $entry->{__object} or return;
return $entry_obj->string_peek('Password');
}
##############################################################################
sub _tie {
my $self = shift;
my $ref = shift // \my %h;
my $class = shift;
my $obj = shift;
my $cache = $TIED{$self} //= {};
$class = __PACKAGE__."::Tie::$class" if $class !~ s/^\+//;
my $key = "$class:" . Hash::Util::FieldHash::id($obj);
my $hit = $cache->{$key};
return $hit if defined $hit;
load $class;
tie((ref $ref eq 'ARRAY' ? @$ref : %$ref), $class, $obj, @_, $self);
$hit = $cache->{$key} = $ref;
weaken $cache->{$key};
return $hit;
}
### convert datetime from KDBX to KeePass format
sub _decode_datetime {
local $_ = shift or return;
return $_->strftime('%Y-%m-%d %H:%M:%S');
}
### convert datetime from KeePass to KDBX format
sub _encode_datetime {
local $_ = shift or return;
return Time::Piece->strptime($_, '%Y-%m-%d %H:%M:%S');
}
### convert UUID from KeePass to KDBX format
sub _encode_uuid {
local $_ = shift // return;
# Group IDs in KDB files are 32-bit integers
return sprintf('%016x', $_) if length($_) != 16 && looks_like_number($_);
return $_;
}
### convert tristate from KDBX to KeePass format
sub _decode_tristate {
local $_ = shift // return;
return $_ ? 1 : 0;
}
### convert tristate from KeePass to KDBX format
sub _encode_tristate {
local $_ = shift // return;
return boolean($_);
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
File::KeePass::KDBX - Read and write KDBX files (using the File::KDBX backend)
=head1 VERSION
version 0.902
=head1 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;
( run in 0.751 second using v1.01-cache-2.11-cpan-bbc515a03b3 )