X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=lib%2FFile%2FKDBX%2FDumper%2FV4.pm;h=8765e0211a9b4a8b105c57ef3e216cb337509d98;hb=16c035abaa2ff6c53076f4ff6ae3215130acb56f;hp=b96e568d46be09c4df5e3be8c9d93d93f813a951;hpb=f63182fc62b25269b1c38588dca2b3535ed1a1a2;p=chaz%2Fp5-File-KDBX diff --git a/lib/File/KDBX/Dumper/V4.pm b/lib/File/KDBX/Dumper/V4.pm index b96e568..8765e02 100644 --- a/lib/File/KDBX/Dumper/V4.pm +++ b/lib/File/KDBX/Dumper/V4.pm @@ -9,19 +9,19 @@ use Crypt::Mac::HMAC qw(hmac); use Encode qw(encode is_utf8); use File::KDBX::Constants qw(:header :inner_header :compression :kdf :variant_map); use File::KDBX::Error; -use File::KDBX::Util qw(:empty assert_64bit erase_scoped); +use File::KDBX::IO::Crypt; +use File::KDBX::IO::HmacBlock; +use File::KDBX::Util qw(:class :empty :int :load erase_scoped); use IO::Handle; -use PerlIO::via::File::KDBX::Crypt; -use PerlIO::via::File::KDBX::HmacBlock; use Scalar::Util qw(looks_like_number); use boolean qw(:all); use namespace::clean; -use parent 'File::KDBX::Dumper'; +extends 'File::KDBX::Dumper'; our $VERSION = '999.999'; # VERSION -sub _binaries_written { $_[0]->{_binaries_written} //= {} } +has _binaries_written => {}, is => 'ro'; sub _write_headers { my $self = shift; @@ -61,7 +61,7 @@ sub _write_header { my $type = shift; my $val = shift // ''; - $type = KDBX_HEADER($type); + $type = to_header_constant($type); if ($type == HEADER_END) { # nothing } @@ -129,9 +129,8 @@ sub _intuit_variant_type { return VMAP_TYPE_BOOL; } elsif (looks_like_number($variant) && ($variant + 0) =~ /^\d+$/) { - assert_64bit; my $neg = $variant < 0; - my @b = unpack('L>2', pack('Q>', $variant)); + my @b = unpack('L>2', scalar reverse pack_Ql($variant)); return VMAP_TYPE_INT64 if $b[0] && $neg; return VMAP_TYPE_UINT64 if $b[0]; return VMAP_TYPE_INT32 if $neg; @@ -162,8 +161,7 @@ sub _write_variant_dictionary { $val = pack('L<', $val); } elsif ($type == VMAP_TYPE_UINT64) { - assert_64bit; - $val = pack('Q<', $val); + $val = pack_Ql($val); } elsif ($type == VMAP_TYPE_BOOL) { $val = pack('C', $val); @@ -172,8 +170,7 @@ sub _write_variant_dictionary { $val = pack('l', $val); } elsif ($type == VMAP_TYPE_INT64) { - assert_64bit; - $val = pack('q<', $val); + $val = pack_ql($val); } elsif ($type == VMAP_TYPE_STRING) { $val = encode('UTF-8', $val); @@ -233,18 +230,22 @@ sub _write_body { $kdbx->key($key); # HMAC-block the rest of the stream - PerlIO::via::File::KDBX::HmacBlock->push($fh, $hmac_key); + $fh = File::KDBX::IO::HmacBlock->new($fh, key => $hmac_key); my $final_key = digest_data('SHA256', $kdbx->headers->{master_seed}, $transformed_key); push @cleanup, erase_scoped $final_key; my $cipher = $kdbx->cipher(key => $final_key); - PerlIO::via::File::KDBX::Crypt->push($fh, $cipher); + $fh = File::KDBX::IO::Crypt->new($fh, cipher => $cipher); my $compress = $kdbx->headers->{+HEADER_COMPRESSION_FLAGS}; if ($compress == COMPRESSION_GZIP) { - require PerlIO::via::File::KDBX::Compression; - PerlIO::via::File::KDBX::Compression->push($fh); + load_optional('IO::Compress::Gzip'); + $fh = IO::Compress::Gzip->new($fh, + -Level => IO::Compress::Gzip::Z_BEST_COMPRESSION(), + -TextFlag => 1, + ) or throw "Failed to initialize compression library: $IO::Compress::Gzip::GzipError", + error => $IO::Compress::Gzip::GzipError; } elsif ($compress != COMPRESSION_NONE) { throw "Unsupported compression ($compress)\n", compression_flags => $compress; @@ -254,9 +255,6 @@ sub _write_body { local $self->{compress_datetimes} = 1; $self->_write_inner_body($fh, $header_hash); - - binmode($fh, ':pop') if $compress; - binmode($fh, ':pop:pop'); } sub _write_inner_headers { @@ -288,8 +286,7 @@ sub _write_inner_header { my $buf = pack('C', $type); $fh->print($buf) or throw 'Failed to write inner header type'; - $type = KDBX_INNER_HEADER($type); - + $type = to_inner_header_constant($type); if ($type == INNER_HEADER_END) { # nothing } @@ -317,8 +314,8 @@ sub _write_binaries { my $new_ref = 0; my $written = $self->_binaries_written; - my $entries = $kdbx->all_entries(history => true); - for my $entry (@$entries) { + my $entries = $kdbx->entries(history => 1); + while (my $entry = $entries->next) { for my $key (keys %{$entry->binaries}) { my $binary = $entry->binaries->{$key}; if (defined $binary->{ref} && defined $kdbx->binaries->{$binary->{ref}}) {