]> Dogcows Code - chaz/p5-File-KDBX/commitdiff
Version 0.902
authorCharles McGarvey <ccm@cpan.org>
Wed, 4 May 2022 01:18:47 +0000 (19:18 -0600)
committerCharles McGarvey <ccm@cpan.org>
Wed, 4 May 2022 01:18:47 +0000 (19:18 -0600)
52 files changed:
Changes
META.json
META.yml
Makefile.PL
README
lib/File/KDBX.pm
lib/File/KDBX/Cipher.pm
lib/File/KDBX/Cipher/CBC.pm
lib/File/KDBX/Cipher/Stream.pm
lib/File/KDBX/Constants.pm
lib/File/KDBX/Dumper.pm
lib/File/KDBX/Dumper/KDB.pm
lib/File/KDBX/Dumper/Raw.pm
lib/File/KDBX/Dumper/V3.pm
lib/File/KDBX/Dumper/V4.pm
lib/File/KDBX/Dumper/XML.pm
lib/File/KDBX/Entry.pm
lib/File/KDBX/Error.pm
lib/File/KDBX/Group.pm
lib/File/KDBX/IO.pm
lib/File/KDBX/IO/Crypt.pm
lib/File/KDBX/IO/HashBlock.pm
lib/File/KDBX/IO/HmacBlock.pm
lib/File/KDBX/Iterator.pm
lib/File/KDBX/KDF.pm
lib/File/KDBX/KDF/AES.pm
lib/File/KDBX/KDF/Argon2.pm
lib/File/KDBX/Key.pm
lib/File/KDBX/Key/ChallengeResponse.pm
lib/File/KDBX/Key/Composite.pm
lib/File/KDBX/Key/File.pm
lib/File/KDBX/Key/Password.pm
lib/File/KDBX/Key/YubiKey.pm
lib/File/KDBX/Loader.pm
lib/File/KDBX/Loader/KDB.pm
lib/File/KDBX/Loader/Raw.pm
lib/File/KDBX/Loader/V3.pm
lib/File/KDBX/Loader/V4.pm
lib/File/KDBX/Loader/XML.pm
lib/File/KDBX/Object.pm
lib/File/KDBX/Safe.pm
lib/File/KDBX/Transaction.pm
lib/File/KDBX/Util.pm
t/00-report-prereqs.dd
t/database.t
t/entry.t
t/error.t
t/kdbx2.t
t/kdbx3.t
t/kdbx4.t
t/lib/TestCommon.pm
t/util.t

diff --git a/Changes b/Changes
index c74d78a99023ca6dc9ae75126e8648e95c882a59..d9e489e3009f87c7eea8e17cad26c7da707f217a 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,18 +1,24 @@
 Revision history for File-KDBX.
 
+0.902     2022-05-03 19:18:06-0600
+
+  * Added support for 32-bit perls.
+  * API change: Rename iterator accessors on group to all_*.
+  * Declared perl 5.10.0 prerequisite. I have no intention of supporting 5.8 or earlier.
+  * Fixed more other broken tests -- thanks CPAN testers.
+
 0.901     2022-05-02 01:18:13-0600
 
-  * Fixed a bug where peeking at memory-protected strings and binaries does
-    not work without unlocking the database at least once.
+  * Fixed a bug where peeking at memory-protected strings and binaries does not work without unlocking the
+    database at least once.
   * Added an option for writing files non-atomically.
   * Fixed broken tests on Windows.
 
 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.
+  * 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.
   * Cleaned up a lot of pod typos and other inaccuracies.
 
index 7ee8a969689244bbdb30e6916ffa2d9cb4725061..e72d2592b65500b913744b8533bb0cd7540d7cf6 100644 (file)
--- a/META.json
+++ b/META.json
             "Crypt::Cipher" : "0",
             "Crypt::Digest" : "0",
             "Crypt::Mac::HMAC" : "0",
-            "Crypt::Misc" : "0.029",
+            "Crypt::Misc" : "0.049",
             "Crypt::Mode::CBC" : "0",
             "Crypt::PRNG" : "0",
             "Data::Dumper" : "0",
             "File::Temp" : "0",
             "Hash::Util::FieldHash" : "0",
             "IO::Handle" : "0",
-            "IPC::Cmd" : "0.52",
+            "IPC::Cmd" : "0.84",
             "Iterator::Simple" : "0",
             "List::Util" : "1.33",
+            "Math::BigInt" : "0",
             "Module::Load" : "0",
             "Module::Loaded" : "0",
             "POSIX" : "0",
             "boolean" : "0",
             "namespace::clean" : "0",
             "overload" : "0",
+            "perl" : "5.010",
             "strict" : "0",
             "warnings" : "0"
          }
             "Test::More" : "0",
             "Test::Warnings" : "0",
             "lib" : "0",
-            "perl" : "5.006",
             "utf8" : "0"
          },
          "suggests" : {
    "provides" : {
       "File::KDBX" : {
          "file" : "lib/File/KDBX.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Cipher" : {
          "file" : "lib/File/KDBX/Cipher.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Cipher::CBC" : {
          "file" : "lib/File/KDBX/Cipher/CBC.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Cipher::Stream" : {
          "file" : "lib/File/KDBX/Cipher/Stream.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Constants" : {
          "file" : "lib/File/KDBX/Constants.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Dumper" : {
          "file" : "lib/File/KDBX/Dumper.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Dumper::KDB" : {
          "file" : "lib/File/KDBX/Dumper/KDB.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Dumper::Raw" : {
          "file" : "lib/File/KDBX/Dumper/Raw.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Dumper::V3" : {
          "file" : "lib/File/KDBX/Dumper/V3.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Dumper::V4" : {
          "file" : "lib/File/KDBX/Dumper/V4.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Dumper::XML" : {
          "file" : "lib/File/KDBX/Dumper/XML.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Entry" : {
          "file" : "lib/File/KDBX/Entry.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Error" : {
          "file" : "lib/File/KDBX/Error.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Group" : {
          "file" : "lib/File/KDBX/Group.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::IO" : {
          "file" : "lib/File/KDBX/IO.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::IO::Crypt" : {
          "file" : "lib/File/KDBX/IO/Crypt.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::IO::HashBlock" : {
          "file" : "lib/File/KDBX/IO/HashBlock.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::IO::HmacBlock" : {
          "file" : "lib/File/KDBX/IO/HmacBlock.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Iterator" : {
          "file" : "lib/File/KDBX/Iterator.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::KDF" : {
          "file" : "lib/File/KDBX/KDF.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::KDF::AES" : {
          "file" : "lib/File/KDBX/KDF/AES.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::KDF::Argon2" : {
          "file" : "lib/File/KDBX/KDF/Argon2.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Key" : {
          "file" : "lib/File/KDBX/Key.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Key::ChallengeResponse" : {
          "file" : "lib/File/KDBX/Key/ChallengeResponse.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Key::Composite" : {
          "file" : "lib/File/KDBX/Key/Composite.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Key::File" : {
          "file" : "lib/File/KDBX/Key/File.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Key::Password" : {
          "file" : "lib/File/KDBX/Key/Password.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Key::YubiKey" : {
          "file" : "lib/File/KDBX/Key/YubiKey.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Loader" : {
          "file" : "lib/File/KDBX/Loader.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Loader::KDB" : {
          "file" : "lib/File/KDBX/Loader/KDB.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Loader::Raw" : {
          "file" : "lib/File/KDBX/Loader/Raw.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Loader::V3" : {
          "file" : "lib/File/KDBX/Loader/V3.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Loader::V4" : {
          "file" : "lib/File/KDBX/Loader/V4.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Loader::XML" : {
          "file" : "lib/File/KDBX/Loader/XML.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Object" : {
          "file" : "lib/File/KDBX/Object.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Safe" : {
          "file" : "lib/File/KDBX/Safe.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Transaction" : {
          "file" : "lib/File/KDBX/Transaction.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       },
       "File::KDBX::Util" : {
          "file" : "lib/File/KDBX/Util.pm",
-         "version" : "0.901"
+         "version" : "0.902"
       }
    },
    "release_status" : "stable",
          "web" : "https://github.com/chazmcgarvey/File-KDBX"
       }
    },
-   "version" : "0.901",
+   "version" : "0.902",
    "x_authority" : "cpan:CCM",
    "x_generated_by_perl" : "v5.34.1",
    "x_serialization_backend" : "Cpanel::JSON::XS version 4.27",
index 3473a03e913e86f1a0760025deb0c4f12ab0810b..02a301d311029429925248cd893e24588d6cfcc4 100644 (file)
--- a/META.yml
+++ b/META.yml
@@ -14,7 +14,6 @@ build_requires:
   Test::More: '0'
   Test::Warnings: '0'
   lib: '0'
-  perl: '5.006'
   utf8: '0'
 configure_requires:
   ExtUtils::MakeMaker: '0'
@@ -50,118 +49,118 @@ optional_features:
 provides:
   File::KDBX:
     file: lib/File/KDBX.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Cipher:
     file: lib/File/KDBX/Cipher.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Cipher::CBC:
     file: lib/File/KDBX/Cipher/CBC.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Cipher::Stream:
     file: lib/File/KDBX/Cipher/Stream.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Constants:
     file: lib/File/KDBX/Constants.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Dumper:
     file: lib/File/KDBX/Dumper.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Dumper::KDB:
     file: lib/File/KDBX/Dumper/KDB.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Dumper::Raw:
     file: lib/File/KDBX/Dumper/Raw.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Dumper::V3:
     file: lib/File/KDBX/Dumper/V3.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Dumper::V4:
     file: lib/File/KDBX/Dumper/V4.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Dumper::XML:
     file: lib/File/KDBX/Dumper/XML.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Entry:
     file: lib/File/KDBX/Entry.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Error:
     file: lib/File/KDBX/Error.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Group:
     file: lib/File/KDBX/Group.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::IO:
     file: lib/File/KDBX/IO.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::IO::Crypt:
     file: lib/File/KDBX/IO/Crypt.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::IO::HashBlock:
     file: lib/File/KDBX/IO/HashBlock.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::IO::HmacBlock:
     file: lib/File/KDBX/IO/HmacBlock.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Iterator:
     file: lib/File/KDBX/Iterator.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::KDF:
     file: lib/File/KDBX/KDF.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::KDF::AES:
     file: lib/File/KDBX/KDF/AES.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::KDF::Argon2:
     file: lib/File/KDBX/KDF/Argon2.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Key:
     file: lib/File/KDBX/Key.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Key::ChallengeResponse:
     file: lib/File/KDBX/Key/ChallengeResponse.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Key::Composite:
     file: lib/File/KDBX/Key/Composite.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Key::File:
     file: lib/File/KDBX/Key/File.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Key::Password:
     file: lib/File/KDBX/Key/Password.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Key::YubiKey:
     file: lib/File/KDBX/Key/YubiKey.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Loader:
     file: lib/File/KDBX/Loader.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Loader::KDB:
     file: lib/File/KDBX/Loader/KDB.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Loader::Raw:
     file: lib/File/KDBX/Loader/Raw.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Loader::V3:
     file: lib/File/KDBX/Loader/V3.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Loader::V4:
     file: lib/File/KDBX/Loader/V4.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Loader::XML:
     file: lib/File/KDBX/Loader/XML.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Object:
     file: lib/File/KDBX/Object.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Safe:
     file: lib/File/KDBX/Safe.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Transaction:
     file: lib/File/KDBX/Transaction.pm
-    version: '0.901'
+    version: '0.902'
   File::KDBX::Util:
     file: lib/File/KDBX/Util.pm
-    version: '0.901'
+    version: '0.902'
 recommends:
   Compress::Raw::Zlib: '0'
   File::KDBX::XS: '0'
@@ -175,7 +174,7 @@ requires:
   Crypt::Cipher: '0'
   Crypt::Digest: '0'
   Crypt::Mac::HMAC: '0'
-  Crypt::Misc: '0.029'
+  Crypt::Misc: '0.049'
   Crypt::Mode::CBC: '0'
   Crypt::PRNG: '0'
   Data::Dumper: '0'
@@ -185,9 +184,10 @@ requires:
   File::Temp: '0'
   Hash::Util::FieldHash: '0'
   IO::Handle: '0'
-  IPC::Cmd: '0.52'
+  IPC::Cmd: '0.84'
   Iterator::Simple: '0'
   List::Util: '1.33'
+  Math::BigInt: '0'
   Module::Load: '0'
   Module::Loaded: '0'
   POSIX: '0'
@@ -203,13 +203,14 @@ requires:
   boolean: '0'
   namespace::clean: '0'
   overload: '0'
+  perl: '5.010'
   strict: '0'
   warnings: '0'
 resources:
   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.901'
+version: '0.902'
 x_authority: cpan:CCM
 x_generated_by_perl: v5.34.1
 x_serialization_backend: 'YAML::Tiny version 1.73'
index 7c6ce7ce73d0c7cf4cb3b22e654183056154b2d9..9b138131eefd03d12c6c7c2a2d5da20d6c311c78 100644 (file)
@@ -2,7 +2,7 @@
 use strict;
 use warnings;
 
-use 5.006;
+use 5.010;
 
 use ExtUtils::MakeMaker;
 
@@ -14,7 +14,7 @@ my %WriteMakefileArgs = (
   },
   "DISTNAME" => "File-KDBX",
   "LICENSE" => "perl",
-  "MIN_PERL_VERSION" => "5.006",
+  "MIN_PERL_VERSION" => "5.010",
   "NAME" => "File::KDBX",
   "PREREQ_PM" => {
     "Carp" => 0,
@@ -22,7 +22,7 @@ my %WriteMakefileArgs = (
     "Crypt::Cipher" => 0,
     "Crypt::Digest" => 0,
     "Crypt::Mac::HMAC" => 0,
-    "Crypt::Misc" => "0.029",
+    "Crypt::Misc" => "0.049",
     "Crypt::Mode::CBC" => 0,
     "Crypt::PRNG" => 0,
     "Data::Dumper" => 0,
@@ -32,9 +32,10 @@ my %WriteMakefileArgs = (
     "File::Temp" => 0,
     "Hash::Util::FieldHash" => 0,
     "IO::Handle" => 0,
-    "IPC::Cmd" => "0.52",
+    "IPC::Cmd" => "0.84",
     "Iterator::Simple" => 0,
     "List::Util" => "1.33",
+    "Math::BigInt" => 0,
     "Module::Load" => 0,
     "Module::Loaded" => 0,
     "POSIX" => 0,
@@ -67,7 +68,7 @@ my %WriteMakefileArgs = (
     "lib" => 0,
     "utf8" => 0
   },
-  "VERSION" => "0.901",
+  "VERSION" => "0.902",
   "test" => {
     "TESTS" => "t/*.t"
   }
@@ -80,7 +81,7 @@ my %FallbackPrereqs = (
   "Crypt::Cipher" => 0,
   "Crypt::Digest" => 0,
   "Crypt::Mac::HMAC" => 0,
-  "Crypt::Misc" => "0.029",
+  "Crypt::Misc" => "0.049",
   "Crypt::Mode::CBC" => 0,
   "Crypt::PRNG" => 0,
   "Data::Dumper" => 0,
@@ -94,10 +95,11 @@ my %FallbackPrereqs = (
   "Getopt::Std" => 0,
   "Hash::Util::FieldHash" => 0,
   "IO::Handle" => 0,
-  "IPC::Cmd" => "0.52",
+  "IPC::Cmd" => "0.84",
   "IPC::Open3" => 0,
   "Iterator::Simple" => 0,
   "List::Util" => "1.33",
+  "Math::BigInt" => 0,
   "Module::Load" => 0,
   "Module::Loaded" => 0,
   "POSIX" => 0,
diff --git a/README b/README
index 06be87c3ad1d7f20b7f645e13de64a2c92eadc68..ec6508e533074da94cef2083aa26c75a1028c4e5 100644 (file)
--- a/README
+++ b/README
@@ -4,28 +4,33 @@ NAME
 
 VERSION
 
-    version 0.901
+    version 0.902
 
 SYNOPSIS
 
         use File::KDBX;
     
+        # Create a new database from scratch
         my $kdbx = File::KDBX->new;
     
+        # Add some objects to the database
         my $group = $kdbx->add_group(
             name => 'Passwords',
         );
-    
         my $entry = $group->add_entry(
             title    => 'My Bank',
+            username => 'mreynolds',
             password => 's3cr3t',
         );
     
+        # Save the database to the filesystem
         $kdbx->dump_file('passwords.kdbx', 'M@st3rP@ssw0rd!');
     
-        $kdbx = File::KDBX->load_file('passwords.kdbx', 'M@st3rP@ssw0rd!');
+        # Load the database from the filesystem into a new database instance
+        my $kdbx2 = File::KDBX->load_file('passwords.kdbx', 'M@st3rP@ssw0rd!');
     
-        $kdbx->entries->each(sub {
+        # Iterate over database entries, print entry titles
+        $kdbx2->entries->each(sub {
             my ($entry) = @_;
             say 'Entry: ', $entry->title;
         });
@@ -148,7 +153,7 @@ ATTRIBUTES
     The UUID of a cipher used to encrypt the database when stored as a
     file.
 
-    See "File::KDBX::Cipher".
+    See File::KDBX::Cipher.
 
  compression_flags
 
@@ -464,8 +469,8 @@ METHODS
     was introduced with KDBX4.
 
     This method never returns less than KDBX_VERSION_3_1 (i.e. 0x00030001).
-    That file version is so ubiquitious and well-supported, there are
-    seldom reasons to dump in a lesser format nowadays.
+    That file version is so ubiquitous and well-supported, there are seldom
+    reasons to dump in a lesser format nowadays.
 
     WARNING: If you dump a database with a minimum version higher than the
     current "version", the dumper will typically issue a warning and
@@ -1456,7 +1461,7 @@ QUERY
     Iterators are the built-in way to navigate or walk the database tree.
     You get an iterator from "entries", "groups" and "objects". You can
     specify the search algorithm to iterate over objects in different
-    orders using the algorith option, which can be one of these constants:
+    orders using the algorithm option, which can be one of these constants:
 
       * ITERATION_IDS - Iterative deepening search (default)
 
@@ -1582,15 +1587,6 @@ ENVIRONMENT
 
       * NO_FORK - Do not fork if true (default: false)
 
-CAVEATS
-
-    Some features (e.g. parsing) require 64-bit perl. It should be possible
-    and actually pretty easy to make it work using Math::BigInt, but I need
-    to build a 32-bit perl in order to test it and frankly I'm still
-    figuring out how. I'm sure it's simple so I'll mark this one "TODO",
-    but for now an exception will be thrown when trying to use such
-    features with undersized IVs.
-
 SEE ALSO
 
       * KeePass Password Safe <https://keepass.info/> - The original
index c8686eff66625f34fb280169a598f2e27b79cd57..b6283751f104b1a41d14f127f8246642244d7bd2 100644 (file)
@@ -1,6 +1,7 @@
 package File::KDBX;
 # ABSTRACT: Encrypted database to store secret text and files
 
+use 5.010;
 use warnings;
 use strict;
 
@@ -19,7 +20,7 @@ use Time::Piece;
 use boolean;
 use namespace::clean;
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 our $WARNINGS = 1;
 
 fieldhashes \my (%SAFE, %KEYS);
@@ -419,7 +420,7 @@ sub groups {
     my %args = @_ % 2 == 0 ? @_ : (base => shift, @_);
     my $base = delete $args{base} // $self->root;
 
-    return $base->groups_deeply(%args);
+    return $base->all_groups(%args);
 }
 
 ##############################################################################
@@ -451,7 +452,7 @@ sub entries {
     my %args = @_ % 2 == 0 ? @_ : (base => shift, @_);
     my $base = delete $args{base} // $self->root;
 
-    return $base->entries_deeply(%args);
+    return $base->all_entries(%args);
 }
 
 ##############################################################################
@@ -462,7 +463,7 @@ sub objects {
     my %args = @_ % 2 == 0 ? @_ : (base => shift, @_);
     my $base = delete $args{base} // $self->root;
 
-    return $base->objects_deeply(%args);
+    return $base->all_objects(%args);
 }
 
 sub __iter__ { $_[0]->objects }
@@ -1120,28 +1121,33 @@ File::KDBX - Encrypted database to store secret text and files
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
     use File::KDBX;
 
+    # Create a new database from scratch
     my $kdbx = File::KDBX->new;
 
+    # Add some objects to the database
     my $group = $kdbx->add_group(
         name => 'Passwords',
     );
-
     my $entry = $group->add_entry(
         title    => 'My Bank',
+        username => 'mreynolds',
         password => 's3cr3t',
     );
 
+    # Save the database to the filesystem
     $kdbx->dump_file('passwords.kdbx', 'M@st3rP@ssw0rd!');
 
-    $kdbx = File::KDBX->load_file('passwords.kdbx', 'M@st3rP@ssw0rd!');
+    # Load the database from the filesystem into a new database instance
+    my $kdbx2 = File::KDBX->load_file('passwords.kdbx', 'M@st3rP@ssw0rd!');
 
-    $kdbx->entries->each(sub {
+    # Iterate over database entries, print entry titles
+    $kdbx2->entries->each(sub {
         my ($entry) = @_;
         say 'Entry: ', $entry->title;
     });
@@ -1279,7 +1285,7 @@ A text string associated with the database. Often unset.
 
 The UUID of a cipher used to encrypt the database when stored as a file.
 
-See L</File::KDBX::Cipher>.
+See L<File::KDBX::Cipher>.
 
 =head2 compression_flags
 
@@ -1384,7 +1390,7 @@ Number of days until the agent should prompt to recommend changing the master ke
 Number of days until the agent should prompt to force changing the master key.
 
 Note: This is purely advisory. It is up to the individual agent software to actually enforce it.
-C<File::KDBX> does NOT enforce it.
+B<File::KDBX> does NOT enforce it.
 
 =head2 custom_icons
 
@@ -1569,7 +1575,7 @@ might increase this value. For example, setting the KDF to Argon2 will increase
 least C<KDBX_VERSION_4_0> (i.e. C<0x00040000>) because Argon2 was introduced with KDBX4.
 
 This method never returns less than C<KDBX_VERSION_3_1> (i.e. C<0x00030001>). That file version is so
-ubiquitious and well-supported, there are seldom reasons to dump in a lesser format nowadays.
+ubiquitous and well-supported, there are seldom reasons to dump in a lesser format nowadays.
 
 B<WARNING:> If you dump a database with a minimum version higher than the current L</version>, the dumper will
 typically issue a warning and automatically upgrade the database. This seems like the safest behavior in order
@@ -2640,7 +2646,7 @@ your own query logic, like this:
 
 Iterators are the built-in way to navigate or walk the database tree. You get an iterator from L</entries>,
 L</groups> and L</objects>. You can specify the search algorithm to iterate over objects in different orders
-using the C<algorith> option, which can be one of these L<constants|File::KDBX::Constants/":iteration">:
+using the C<algorithm> option, which can be one of these L<constants|File::KDBX::Constants/":iteration">:
 
 =over 4
 
@@ -2796,13 +2802,6 @@ C<NO_FORK> - Do not fork if true (default: false)
 
 =back
 
-=head1 CAVEATS
-
-Some features (e.g. parsing) require 64-bit perl. It should be possible and actually pretty easy to make it
-work using L<Math::BigInt>, but I need to build a 32-bit perl in order to test it and frankly I'm still
-figuring out how. I'm sure it's simple so I'll mark this one "TODO", but for now an exception will be thrown
-when trying to use such features with undersized IVs.
-
 =head1 SEE ALSO
 
 =over 4
index 250b9cf3c4d493e2734a2cbd92c2018bdc6abd99..37bdb58fb2ec62a7aeccff4e950e7291ab10c019 100644 (file)
@@ -12,7 +12,7 @@ use Module::Load;
 use Scalar::Util qw(looks_like_number);
 use namespace::clean;
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 my %CIPHERS;
 
@@ -158,7 +158,7 @@ File::KDBX::Cipher - A block cipher mode or cipher stream
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index a759452d830eefa98410b490b12578a826318a0d..8f798de195a76babc14d9d45def4e75378d2bfa2 100644 (file)
@@ -11,7 +11,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Cipher';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 has key_size => 32;
 sub iv_size     { 16 }
@@ -63,7 +63,7 @@ File::KDBX::Cipher::CBC - A CBC block cipher mode encrypter/decrypter
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index 2b0c9f203f58ab0f366d2add19209ee307888274..b5112008749bb9b76e30f995b7a196f2c3d06791 100644 (file)
@@ -14,7 +14,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Cipher';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 
 has 'counter',  is => 'ro', default => 0;
@@ -123,7 +123,7 @@ File::KDBX::Cipher::Stream - A cipher stream encrypter/decrypter
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index f31cc0ce55a509828b70f174de50d06a822b655b..c7b31bdd18e9c190c402ceef5f0119be80f0948c 100644 (file)
@@ -6,14 +6,16 @@ package File::KDBX::Constants;
 #  2. List it in the pod at the bottom of this file in the section corresponding to its tag.
 #  3. There is no step three.
 
+use 5.010;
 use warnings;
 use strict;
 
 use Exporter qw(import);
+use File::KDBX::Util qw(int64);
 use Scalar::Util qw(dualvar);
 use namespace::clean -except => 'import';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 BEGIN {
     my %CONSTANTS = (
@@ -213,7 +215,7 @@ BEGIN {
         },
         time        => {
             __prefix                    => 'TIME',
-            SECONDS_AD1_TO_UNIX_EPOCH   => 62_135_596_800,
+            SECONDS_AD1_TO_UNIX_EPOCH   => int64('62135596800'),
         },
         yubikey     => {
             YUBICO_VID              => dualvar( 0x1050, 'Yubico'),
@@ -346,7 +348,7 @@ File::KDBX::Constants - All the KDBX-related constants you could ever want
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index f6d6657abd9ec00819248715012756251312ce10..c73ddcf4a84c81f76bf7db4488e71ae36006c9e7 100644 (file)
@@ -15,7 +15,7 @@ use Ref::Util qw(is_ref is_scalarref);
 use Scalar::Util qw(looks_like_number openhandle);
 use namespace::clean;
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 
 sub new {
@@ -287,7 +287,7 @@ File::KDBX::Dumper - Write KDBX files
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 ATTRIBUTES
 
index 4f35970617b38ffe40362a08306dcf4ba9fc4485..ea0db6f218f19d440f8cebae0993b70f7189fabd 100644 (file)
@@ -14,7 +14,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Dumper';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 sub _write_magic_numbers { '' }
 sub _write_headers { '' }
@@ -29,8 +29,6 @@ sub _write_body {
     my $k = File::KeePass::KDBX->new($self->kdbx)->to_fkp;
     $self->_write_custom_icons($self->kdbx, $k);
 
-    # TODO create a KPX_CUSTOM_ICONS_4 meta stream. FKP itself handles KPX_GROUP_TREE_STATE
-
     substr($k->header->{seed_rand}, 16) = '';
 
     $key = $self->kdbx->composite_key($key, keep_primitive => 1);
@@ -138,7 +136,7 @@ File::KDBX::Dumper::KDB - Write KDB files
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
index d6d2173daf05d7235b7fdc8421b60d45564f28b6..70aa0c6ac5d17bbffd007c40b2cf4fed40dd791b 100644 (file)
@@ -9,7 +9,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Dumper';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 sub _dump {
     my $self = shift;
@@ -48,7 +48,7 @@ File::KDBX::Dumper::Raw - A no-op dumper that dumps content as-is
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index a5f7ef0963ccce82ab5b56611bc15fedea1cdbd7..f06db6b8a34db9cae1e2f9e2fb997259fb1aeb91 100644 (file)
@@ -10,13 +10,13 @@ use File::KDBX::Constants qw(:header :compression);
 use File::KDBX::Error;
 use File::KDBX::IO::Crypt;
 use File::KDBX::IO::HashBlock;
-use File::KDBX::Util qw(:class :empty :load assert_64bit erase_scoped);
+use File::KDBX::Util qw(:class :empty :int :load erase_scoped);
 use IO::Handle;
 use namespace::clean;
 
 extends 'File::KDBX::Dumper';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 sub _write_headers {
     my $self = shift;
@@ -81,8 +81,7 @@ sub _write_header {
         # nothing
     }
     elsif ($type == HEADER_TRANSFORM_ROUNDS) {
-        assert_64bit;
-        $val = pack('Q<', $val);
+        $val = pack_Ql($val);
     }
     elsif ($type == HEADER_ENCRYPTION_IV) {
         # nothing
@@ -152,7 +151,6 @@ sub _write_body {
 
     $fh->print($kdbx->headers->{+HEADER_STREAM_START_BYTES})
         or throw 'Failed to write start bytes';
-    $fh->flush;
 
     $kdbx->key($key);
 
@@ -189,7 +187,7 @@ File::KDBX::Dumper::V3 - Dump KDBX3 files
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 BUGS
 
index c5644d4ebf545715cc8191496b93d0b1de89325e..0dec6517071c38457d231c806672b109befee4ce 100644 (file)
@@ -11,7 +11,7 @@ use File::KDBX::Constants qw(:header :inner_header :compression :kdf :variant_ma
 use File::KDBX::Error;
 use File::KDBX::IO::Crypt;
 use File::KDBX::IO::HmacBlock;
-use File::KDBX::Util qw(:class :empty :load assert_64bit erase_scoped);
+use File::KDBX::Util qw(:class :empty :int :load erase_scoped);
 use IO::Handle;
 use Scalar::Util qw(looks_like_number);
 use boolean qw(:all);
@@ -19,7 +19,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Dumper';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 has _binaries_written => {}, is => 'ro';
 
@@ -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);
@@ -377,7 +374,7 @@ File::KDBX::Dumper::V4 - Dump KDBX4 files
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 BUGS
 
index 1d7ec39a90e353edb64e7b9137cf80b505819f04..ebf67958ab969ccc776dc277db14900cce29b648 100644 (file)
@@ -9,7 +9,7 @@ use Crypt::Misc 0.029 qw(encode_b64);
 use Encode qw(encode);
 use File::KDBX::Constants qw(:version :time);
 use File::KDBX::Error;
-use File::KDBX::Util qw(:class assert_64bit erase_scoped gzip snakify);
+use File::KDBX::Util qw(:class :int erase_scoped gzip snakify);
 use IO::Handle;
 use Scalar::Util qw(blessed isdual looks_like_number);
 use Time::Piece;
@@ -19,7 +19,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Dumper';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 
 has allow_protection => 1;
@@ -526,9 +526,8 @@ sub _encode_datetime {
 
 sub _encode_datetime_binary {
     local $_ = shift;
-    assert_64bit;
     my $seconds_since_ad1 = $_ + TIME_SECONDS_AD1_TO_UNIX_EPOCH;
-    my $buf = pack('Q<', $seconds_since_ad1->epoch);
+    my $buf = pack_Ql($seconds_since_ad1->epoch);
     return eval { encode_b64($buf) };
 }
 
@@ -564,7 +563,7 @@ File::KDBX::Dumper::XML - Dump unencrypted XML KeePass files
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 ATTRIBUTES
 
index 801237238c22a78da9130c22dacbbd9631eb14f7..df8cf4d372f0039238cacac558efc37ab8a43cb0 100644 (file)
@@ -4,7 +4,7 @@ package File::KDBX::Entry;
 use warnings;
 use strict;
 
-use Crypt::Misc 0.029 qw(decode_b64 encode_b32r);
+use Crypt::Misc 0.049 qw(decode_b64 encode_b32r);
 use Devel::GlobalDestruction;
 use Encode qw(encode);
 use File::KDBX::Constants qw(:history :icon);
@@ -21,7 +21,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Object';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 my $PLACEHOLDER_MAX_DEPTH = 10;
 my %PLACEHOLDERS;
@@ -681,7 +681,7 @@ File::KDBX::Entry - A KDBX database entry
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
@@ -720,7 +720,8 @@ There is also some metadata associated with an entry. Each entry in a database i
 a UUID. An entry can also have an icon associated with it, and there are various timestamps. Take a look at
 the attributes to see what's available.
 
-A B<File::KDBX::Entry> is a subclass of L<File::KDBX::Object>.
+A B<File::KDBX::Entry> is a subclass of L<File::KDBX::Object>. View its documentation to see other attributes
+and methods available on entries.
 
 =head2 Placeholders
 
index 5e3de9073cb776d03b906d3ee1a5bff650827f30..ae02c5fa74d4e3fe3c2babc807f068bd02399f15 100644 (file)
@@ -1,6 +1,7 @@
 package File::KDBX::Error;
 # ABSTRACT: Represents something bad that happened
 
+use 5.010;
 use warnings;
 use strict;
 
@@ -8,7 +9,7 @@ use Exporter qw(import);
 use Scalar::Util qw(blessed looks_like_number);
 use namespace::clean -except => 'import';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 our @EXPORT = qw(alert error throw);
 
@@ -166,7 +167,7 @@ File::KDBX::Error - Represents something bad that happened
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 ATTRIBUTES
 
index c81f34b8691ba14305cf7f3de2c95c55ef1ac251..cf24d71f8f4eb4adf1609357d69b75e0b4a706ff 100644 (file)
@@ -19,7 +19,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Object';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 
 # has uuid                        => sub { generate_uuid(printable => 1) };
@@ -78,7 +78,7 @@ sub entries {
 }
 
 
-sub entries_deeply {
+sub all_entries {
     my $self = shift;
     my %args = @_;
 
@@ -86,7 +86,7 @@ sub entries_deeply {
     my $auto_type   = delete $args{auto_type};
     my $history     = delete $args{history};
 
-    my $groups = $self->groups_deeply(%args);
+    my $groups = $self->all_groups(%args);
     my @entries;
 
     return File::KDBX::Iterator->new(sub {
@@ -149,7 +149,7 @@ sub groups {
 }
 
 
-sub groups_deeply {
+sub all_groups {
     my $self = shift;
     my %args = @_;
 
@@ -220,7 +220,7 @@ sub remove_group {
 ##############################################################################
 
 
-sub objects_deeply {
+sub all_objects {
     my $self = shift;
     my %args = @_;
 
@@ -228,7 +228,7 @@ sub objects_deeply {
     my $auto_type   = delete $args{auto_type};
     my $history     = delete $args{history};
 
-    my $groups = $self->groups_deeply(%args);
+    my $groups = $self->all_groups(%args);
     my @entries;
 
     return File::KDBX::Iterator->new(sub {
@@ -398,7 +398,7 @@ File::KDBX::Group - A KDBX database group
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
@@ -408,6 +408,9 @@ There is also some metadata associated with a group. Each group in a database is
 a UUID. An entry can also have an icon associated with it, and there are various timestamps. Take a look at
 the attributes to see what's available.
 
+A B<File::KDBX::Group> is a subclass of L<File::KDBX::Object>. View its documentation to see other attributes
+and methods available on groups.
+
 =head1 ATTRIBUTES
 
 =head2 name
@@ -454,9 +457,9 @@ Array of subgroups contained within the group.
 
 Get an array of direct child entries within a group.
 
-=head2 entries_deeply
+=head2 all_entries
 
-    \&iterator = $kdbx->entries_deeply(%options);
+    \&iterator = $kdbx->all_entries(%options);
 
 Get an L<File::KDBX::Iterator> over I<entries> within a group. Supports the same options as L</groups>,
 plus some new ones:
@@ -498,9 +501,9 @@ Remove an entry from a group's array of entries. Returns the entry removed or C<
 
 Get an array of direct subgroups within a group.
 
-=head2 groups_deeply
+=head2 all_groups
 
-    \&iterator = $group->groups_deeply(%options);
+    \&iterator = $group->all_groups(%options);
 
 Get an L<File::KDBX::Iterator> over I<groups> within a groups, deeply. Options:
 
@@ -531,9 +534,9 @@ being added to C<$group>.
 
 Remove a group from a group's array of subgroups. Returns the group removed or C<undef> if nothing removed.
 
-=head2 objects_deeply
+=head2 all_objects
 
-    \&iterator = $groups->objects_deeply(%options);
+    \&iterator = $groups->all_objects(%options);
 
 Get an L<File::KDBX::Iterator> over I<objects> within a group, deeply. Groups and entries are considered
 objects, so this is essentially a combination of L</groups> and L</entries>. This won't often be useful, but
index 0ac45298509e5e7058ac00da58ad41117963ff17..135820e71ca8daa331764ed040ca171117a6c4f4 100644 (file)
@@ -14,7 +14,7 @@ use namespace::clean;
 
 extends 'IO::Handle';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 sub _croak { require Carp; goto &Carp::croak }
 
@@ -390,7 +390,7 @@ File::KDBX::IO - Base IO class for KDBX-related streams
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
index 09749334d6ee4f06bbd363b9a13e3291cd555860..7675776d36f2ce80890a42df5fd4ee4753a3e58d 100644 (file)
@@ -11,7 +11,7 @@ use namespace::clean;
 
 extends 'File::KDBX::IO';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 our $BUFFER_SIZE = 16384;
 our $ERROR;
 
@@ -139,7 +139,7 @@ File::KDBX::IO::Crypt - Encrypter/decrypter IO handle
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index f1bdf92be3e2afa5b9c266ec25b35cdc62c22c30..2d83249c748035e05d48eef3f64a04bab7138b54 100644 (file)
@@ -13,7 +13,7 @@ use namespace::clean;
 
 extends 'File::KDBX::IO';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 our $ALGORITHM = 'SHA256';
 our $BLOCK_SIZE = 1048576;  # 1MiB
 our $ERROR;
@@ -208,7 +208,7 @@ File::KDBX::IO::HashBlock - Hash block stream IO handle
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
index ae36c95f7c09471055e95451a4b2d3107203a30c..e14100e4407bfceae900939670cfafb08045e643 100644 (file)
@@ -8,18 +8,18 @@ use Crypt::Digest qw(digest_data);
 use Crypt::Mac::HMAC qw(hmac);
 use Errno;
 use File::KDBX::Error;
-use File::KDBX::Util qw(:class :io assert_64bit);
+use File::KDBX::Util qw(:class :int :io);
 use namespace::clean;
 
 extends 'File::KDBX::IO';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 our $BLOCK_SIZE = 1048576;  # 1MiB
 our $ERROR;
 
 
 my %ATTRS = (
-    _block_index    => 0,
+    _block_index    => int64(0),
     _buffer         => sub { \(my $buf = '') },
     _finished       => 0,
     block_size      => sub { $BLOCK_SIZE },
@@ -36,8 +36,6 @@ while (my ($attr, $default) = each %ATTRS) {
 
 
 sub new {
-    assert_64bit;
-
     my $class = shift;
     my %args = @_ % 2 == 1 ? (fh => shift, @_) : @_;
     my $self = $class->SUPER::new;
@@ -141,7 +139,7 @@ sub _read_hashed_block {
             or throw 'Failed to read HMAC block', index => $self->_block_index, size => $size;
     }
 
-    my $packed_index = pack('Q<', $self->_block_index);
+    my $packed_index = pack_Ql($self->_block_index);
     my $got_hmac = hmac('SHA256', $self->_hmac_key,
         $packed_index,
         $packed_size,
@@ -168,7 +166,7 @@ sub _write_next_hmac_block {
     my $block = '';
     $block = substr($$buffer, 0, $size, '') if 0 < $size;
 
-    my $packed_index = pack('Q<', $self->_block_index);
+    my $packed_index = pack_Ql($self->_block_index);
     my $packed_size  = pack('L<', $size);
     my $hmac = hmac('SHA256', $self->_hmac_key,
         $packed_index,
@@ -195,7 +193,7 @@ sub _hmac_key {
     my $key = shift // $self->key;
     my $index = shift // $self->_block_index;
 
-    my $packed_index = pack('Q<', $index);
+    my $packed_index = pack_Ql($index);
     my $hmac_key = digest_data('SHA512', $packed_index, $key);
     return $hmac_key;
 }
@@ -214,7 +212,7 @@ File::KDBX::IO::HmacBlock - HMAC block stream IO handle
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
index 72de0011ab933d59890e493c1a033a9311449b02..b5d0b9113a4de76dd6240fd9581c031fb7c106f9 100644 (file)
@@ -14,7 +14,7 @@ use namespace::clean;
 BEGIN { mark_as_loaded('Iterator::Simple::Iterator') }
 extends 'Iterator::Simple::Iterator';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 
 sub new {
@@ -221,7 +221,7 @@ File::KDBX::Iterator - KDBX database iterator
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index f1e0196a57227ba5b4c95ecbb74e36b906c8ab29..1cf335d3a94ce461a2c3d494767ef8946f3c3942 100644 (file)
@@ -12,7 +12,7 @@ use Module::Load;
 use Scalar::Util qw(blessed);
 use namespace::clean;
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 my %KDFS;
 
@@ -120,7 +120,7 @@ File::KDBX::KDF - A key derivation function
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
index b5d22c9867e50615930f7b7f562e323718e6529d..d86ce4845a2b634c02cd68d6d18968f9acb83a9e 100644 (file)
@@ -13,7 +13,7 @@ use namespace::clean;
 
 extends 'File::KDBX::KDF';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 # Rounds higher than this are eligible for forking:
 my $FORK_OPTIMIZATION_THRESHOLD = 100_000;
@@ -111,7 +111,7 @@ File::KDBX::KDF::AES - Using the AES cipher as a key derivation function
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
index 4c9146f2f7f95626ce3eb527fb777790d720bf14..9f88f746fda5faa53b66da3b82e7b3b52fcde30d 100644 (file)
@@ -12,7 +12,7 @@ use namespace::clean;
 
 extends 'File::KDBX::KDF';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 
 sub salt        { $_[0]->{+KDF_PARAM_ARGON2_SALT} or throw 'Salt is not set' }
@@ -69,7 +69,7 @@ File::KDBX::KDF::Argon2 - The Argon2 family of key derivation functions
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
index 12fa430b8b32a4adad195d3919fd7ab040dccaa4..1fa09f6b23cd336c54886fa706997fd4dea92c9e 100644 (file)
@@ -14,7 +14,7 @@ use Ref::Util qw(is_arrayref is_coderef is_hashref is_ref is_scalarref);
 use Scalar::Util qw(blessed openhandle);
 use namespace::clean;
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 fieldhashes \my %SAFE;
 
@@ -140,7 +140,7 @@ File::KDBX::Key - A credential that can protect a KDBX file
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
index 843c892a68eb9ebf7cc8fb3aa36ab4b2ce07f837..74555f4daa69b486dbcc9a3dd78be8c4c58819db 100644 (file)
@@ -10,7 +10,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Key';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 sub init {
     my $self = shift;
@@ -56,7 +56,7 @@ File::KDBX::Key::ChallengeResponse - A challenge-response key
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index e6f3d932d2885891208b6e03b24ccb8a5b1945b0..fcaef54e1c1d27b33e403f9df9413b29e8e2b7cf 100644 (file)
@@ -13,7 +13,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Key';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 sub init {
     my $self = shift;
@@ -92,7 +92,7 @@ File::KDBX::Key::Composite - A composite key made up of component keys
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index 2223870ab7bf8fe14b105cfdfe370d087dcfcfe6..10b57d47677249c1ad96ba5bdca493f055b50e92 100644 (file)
@@ -17,7 +17,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Key';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 
 has 'type',     is => 'ro';
@@ -262,7 +262,7 @@ File::KDBX::Key::File - A file key
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index fe0facebbe34f94cfe80a19037cd16ebffc27b70..ba2809ddca86ee44ffeca3e764adcd5411090945 100644 (file)
@@ -12,7 +12,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Key';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 sub init {
     my $self = shift;
@@ -37,7 +37,7 @@ File::KDBX::Key::Password - A password key
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index 1185fa12199cb1edb1086591c8bb143d7ef199fe..d55cdaf5e9f5754b494d89d8de05f0add9bfb8ba 100644 (file)
@@ -7,14 +7,14 @@ use strict;
 use File::KDBX::Constants qw(:yubikey);
 use File::KDBX::Error;
 use File::KDBX::Util qw(:class :io pad_pkcs7);
-use IPC::Cmd 0.52 qw(run_forked);
+use IPC::Cmd 0.84 qw(run_forked);
 use Ref::Util qw(is_arrayref);
 use Symbol qw(gensym);
 use namespace::clean;
 
 extends 'File::KDBX::Key::ChallengeResponse';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # 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;
@@ -296,7 +296,7 @@ File::KDBX::Key::YubiKey - A Yubico challenge-response key
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
@@ -487,7 +487,7 @@ C<run_forked> from L<IPC::Cmd> worked in Windows, but it probably doesn't. I spe
 various quirks to L<IPC::Open3> and L<IPC::Cmd> implementations but never quite got it to worked reliably
 without deadlocks. Maybe I'll revisit this later. Hit me up so I know if there's demand.
 
-It would also be possible to implement this is an XS module that incorporated ykcore, using libusb-1 which
+It would also be possible to implement this as an XS module that incorporated ykcore, using libusb-1 which
 would probably make it more portable with Windows. Perhaps if I get around to it.
 
 =head1 BUGS
index 69a7bfb61de90c3a4ecb1eab9d69b27721877dcf..727f4c6fc94be3dc54c809dc6bc549aa868af6fb 100644 (file)
@@ -14,7 +14,7 @@ use Ref::Util qw(is_ref is_scalarref);
 use Scalar::Util qw(looks_like_number openhandle);
 use namespace::clean;
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 
 sub new {
@@ -249,7 +249,7 @@ File::KDBX::Loader - Load KDBX files
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
index 7dad5d2582bf0214272f3d5669226162dc7016fe..1edccb29982202e797d95118c28af43cbb2b26d6 100644 (file)
@@ -17,7 +17,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Loader';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 my $DEFAULT_EXPIRATION = Time::Piece->new(32503677839); # 2999-12-31 23:59:59
 
@@ -397,7 +397,7 @@ File::KDBX::Loader::KDB - Read KDB files
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
index ddb64a75f6933355a4f8856889b6c76aee6fac5a..0352c626019cc8588d8f7f623a94797052e6116c 100644 (file)
@@ -9,7 +9,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Loader';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 sub _read {
     my $self = shift;
@@ -47,7 +47,7 @@ File::KDBX::Loader::Raw - A no-op loader that doesn't do any parsing
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index 6be4090ff2bbc2287b6744a5f56ae802509b35fe..1d42365f0afcb33eabe2947cd103cb4216971042 100644 (file)
@@ -22,12 +22,12 @@ use File::KDBX::Constants qw(:header :compression :kdf);
 use File::KDBX::Error;
 use File::KDBX::IO::Crypt;
 use File::KDBX::IO::HashBlock;
-use File::KDBX::Util qw(:class :io :load assert_64bit erase_scoped);
+use File::KDBX::Util qw(:class :int :io :load erase_scoped);
 use namespace::clean;
 
 extends 'File::KDBX::Loader';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 sub _read_header {
     my $self = shift;
@@ -62,8 +62,7 @@ sub _read_header {
         # nothing
     }
     elsif ($type == HEADER_TRANSFORM_ROUNDS) {
-        assert_64bit;
-        $val = unpack('Q<', $val);
+        ($val) = unpack_Ql($val);
     }
     elsif ($type == HEADER_ENCRYPTION_IV) {
         # nothing
@@ -75,7 +74,7 @@ sub _read_header {
         # nothing
     }
     elsif ($type == HEADER_INNER_RANDOM_STREAM_ID) {
-        $val = unpack('L<', $val);
+        ($val) = unpack('L<', $val);
     }
     elsif ($type == HEADER_KDF_PARAMETERS ||
            $type == HEADER_PUBLIC_CUSTOM_DATA) {
@@ -175,7 +174,7 @@ File::KDBX::Loader::V3 - Load KDBX3 files
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 BUGS
 
index 0e33fc9d17a4aecae8f6d83c9cc5eff155ac3be4..8f73e42fad3b0329c539c45ac0408e2ad899f5c3 100644 (file)
@@ -22,7 +22,7 @@ use Crypt::Mac::HMAC qw(hmac);
 use Encode qw(decode);
 use File::KDBX::Constants qw(:header :inner_header :variant_map :compression);
 use File::KDBX::Error;
-use File::KDBX::Util qw(:class :io :load assert_64bit erase_scoped);
+use File::KDBX::Util qw(:class :int :io :load erase_scoped);
 use File::KDBX::IO::Crypt;
 use File::KDBX::IO::HmacBlock;
 use boolean;
@@ -30,7 +30,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Loader';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 sub _read_header {
     my $self = shift;
@@ -116,8 +116,7 @@ sub _read_variant_dictionary {
             ($val) = unpack('L<', $val);
         }
         elsif ($type == VMAP_TYPE_UINT64) {
-            assert_64bit;
-            ($val) = unpack('Q<', $val);
+            ($val) = unpack_Ql($val);
         }
         elsif ($type == VMAP_TYPE_BOOL) {
             ($val) = unpack('C', $val);
@@ -127,8 +126,7 @@ sub _read_variant_dictionary {
             ($val) = unpack('l<', $val);
         }
         elsif ($type == VMAP_TYPE_INT64) {
-            assert_64bit;
-            ($val) = unpack('q<', $val);
+            ($val) = unpack_ql($val);
         }
         elsif ($type == VMAP_TYPE_STRING) {
             $val = decode('UTF-8', $val);
@@ -275,7 +273,7 @@ File::KDBX::Loader::V4 - Load KDBX4 files
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 BUGS
 
index a0826e9f53466615d3de80b6bb765416e780c5a5..412de239f5ea8f62bdde84f48fb62a7df5d20bb2 100644 (file)
@@ -9,7 +9,7 @@ use Encode qw(decode);
 use File::KDBX::Constants qw(:version :time);
 use File::KDBX::Error;
 use File::KDBX::Safe;
-use File::KDBX::Util qw(:class :text assert_64bit gunzip erase_scoped);
+use File::KDBX::Util qw(:class :int :text gunzip erase_scoped);
 use Scalar::Util qw(looks_like_number);
 use Time::Piece;
 use XML::LibXML::Reader;
@@ -18,7 +18,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Loader';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 has '_reader',  is => 'ro';
 has '_safe',    is => 'ro', default => sub { File::KDBX::Safe->new(cipher => $_[0]->kdbx->random_stream) };
@@ -533,9 +533,8 @@ sub _decode_datetime {
             throw 'Failed to parse binary datetime', text => $_, error => $err;
         }
         throw $@ if $@;
-        assert_64bit;
         $binary .= \0 x (8 - length($binary)) if length($binary) < 8;
-        my ($seconds_since_ad1) = unpack('Q<', $binary);
+        my ($seconds_since_ad1) = unpack_Ql($binary);
         my $epoch = $seconds_since_ad1 - TIME_SECONDS_AD1_TO_UNIX_EPOCH;
         return Time::Piece->new($epoch);
     }
@@ -591,7 +590,7 @@ File::KDBX::Loader::XML - Load unencrypted XML KeePass files
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 BUGS
 
index b7b96445e515331337e95011edf64a9b5bf72825..33d1e034cc2809b1c09a03c17581988afce03924 100644 (file)
@@ -14,7 +14,7 @@ use Ref::Util qw(is_arrayref is_plain_arrayref is_plain_hashref is_ref);
 use Scalar::Util qw(blessed weaken);
 use namespace::clean;
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 fieldhashes \my (%KDBX, %PARENT, %TXNS, %REFS, %SIGNALS);
 
@@ -526,7 +526,7 @@ File::KDBX::Object - A KDBX database object
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 DESCRIPTION
 
index b88b86ce78a805063c32d5164a80c3382c2d7397..4052404a76ed8efd3e0e34b24f4c980b5a9ef3fa 100644 (file)
@@ -14,7 +14,7 @@ use Ref::Util qw(is_arrayref is_coderef is_hashref is_scalarref);
 use Scalar::Util qw(refaddr);
 use namespace::clean;
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 
 sub new {
@@ -217,7 +217,7 @@ File::KDBX::Safe - Keep strings encrypted while in memory
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 SYNOPSIS
 
index 86c380f9a25ed85745c5de64f59f6b9ab4aa39ac..d71863ca208a0c68272a3ce3baf501f340c46317 100644 (file)
@@ -8,7 +8,7 @@ use Devel::GlobalDestruction;
 use File::KDBX::Util qw(:class);
 use namespace::clean;
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 
 sub new {
@@ -59,7 +59,7 @@ File::KDBX::Transaction - Make multiple database edits atomically
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 ATTRIBUTES
 
index 7223f6a7fe60815cf19bf0130eefc07b1f58220a..57e0e18f46da82faeed32301b78872538aad711f 100644 (file)
@@ -1,13 +1,13 @@
 package File::KDBX::Util;
 # ABSTRACT: Utility functions for working with KDBX files
 
+use 5.010;
 use warnings;
 use strict;
 
 use Crypt::PRNG qw(random_bytes random_string);
 use Encode qw(decode encode);
 use Exporter qw(import);
-use File::KDBX::Constants qw(:bool);
 use File::KDBX::Error;
 use List::Util 1.33 qw(any all);
 use Module::Load;
@@ -17,10 +17,10 @@ use Time::Piece;
 use boolean;
 use namespace::clean -except => 'import';
 
-our $VERSION = '0.901'; # VERSION
+our $VERSION = '0.902'; # VERSION
 
 our %EXPORT_TAGS = (
-    assert      => [qw(DEBUG assert assert_64bit)],
+    assert      => [qw(DEBUG assert)],
     class       => [qw(extends has list_attributes)],
     clone       => [qw(clone clone_nomagic)],
     coercion    => [qw(to_bool to_number to_string to_time to_tristate to_uuid)],
@@ -31,7 +31,8 @@ our %EXPORT_TAGS = (
     empty       => [qw(empty nonempty)],
     erase       => [qw(erase erase_scoped)],
     gzip        => [qw(gzip gunzip)],
-    io          => [qw(is_readable is_writable read_all)],
+    int         => [qw(int64 pack_ql pack_Ql unpack_ql unpack_Ql)],
+    io          => [qw(read_all)],
     load        => [qw(load_optional load_xs try_load_optional)],
     search      => [qw(query query_any search simple_expression_query)],
     text        => [qw(snakify trim)],
@@ -104,7 +105,7 @@ sub load_xs {
     goto IS_LOADED if defined $XS_LOADED;
 
     if ($ENV{PERL_ONLY} || (exists $ENV{PERL_FILE_KDBX_XS} && !$ENV{PERL_FILE_KDBX_XS})) {
-        return $XS_LOADED = FALSE;
+        return $XS_LOADED = !1;
     }
 
     $XS_LOADED = !!eval { require File::KDBX::XS; 1 };
@@ -137,13 +138,6 @@ sub assert(&) { ## no critic (ProhibitSubroutinePrototypes)
 }
 
 
-sub assert_64bit() {
-    require Config;
-    $Config::Config{ivsize} < 8
-        and throw "64-bit perl is required to use this feature.\n", ivsize => $Config::Config{ivsize};
-}
-
-
 sub can_fork {
     require Config;
     return 1 if $Config::Config{d_fork};
@@ -413,8 +407,80 @@ sub gzip {
 }
 
 
-sub is_readable { $_[0] !~ /^[aw]b?$/ }
-sub is_writable { $_[0] !~ /^rb?$/ }
+sub int64 {
+    require Config;
+    if ($Config::Config{ivsize} < 8) {
+        require Math::BigInt;
+        return Math::BigInt->new(@_);
+    }
+    return 0 + shift;
+}
+
+
+sub pack_Ql {
+    my $num = shift;
+    require Config;
+    if ($Config::Config{ivsize} < 8) {
+        if (blessed $num && $num->can('as_hex')) {
+            return "\xff\xff\xff\xff\xff\xff\xff\xff" if Math::BigInt->new('18446744073709551615') <= $num;
+            return "\x00\x00\x00\x00\x00\x00\x00\x80" if $num <= Math::BigInt->new('-9223372036854775808');
+            my $neg;
+            if ($num < 0) {
+                $neg = 1;
+                $num = -$num;
+            }
+            my $hex = $num->as_hex;
+            $hex =~ s/^0x/000000000000000/;
+            my $bytes = reverse pack('H16', substr($hex, -16));
+            $bytes .= "\0" x (8 - length $bytes) if length $bytes < 8;
+            if ($neg) {
+                # two's compliment
+                $bytes = join('', map { chr(~ord($_) & 0xff) } split(//, $bytes));
+                substr($bytes, 0, 1, chr(ord(substr($bytes, 0, 1)) + 1));
+            }
+            return $bytes;
+        }
+        else {
+            my $pad = $num < 0 ? "\xff" : "\0";
+            return pack('L<', $num) . ($pad x 4);
+        };
+    }
+    return pack('Q<', $num);
+}
+
+
+sub pack_ql { goto &pack_Ql }
+
+
+sub unpack_Ql {
+    my $bytes = shift;
+    require Config;
+    if ($Config::Config{ivsize} < 8) {
+        require Math::BigInt;
+        return Math::BigInt->new('0x' . unpack('H*', scalar reverse $bytes));
+    }
+    return unpack('Q<', $bytes);
+}
+
+
+sub unpack_ql {
+    my $bytes = shift;
+    require Config;
+    if ($Config::Config{ivsize} < 8) {
+        require Math::BigInt;
+        if (ord(substr($bytes, -1, 1)) & 128) {
+            return Math::BigInt->new('-9223372036854775808') if $bytes eq "\x00\x00\x00\x00\x00\x00\x00\x80";
+            # two's compliment
+            substr($bytes, 0, 1, chr(ord(substr($bytes, 0, 1)) - 1));
+            $bytes = join('', map { chr(~ord($_) & 0xff) } split(//, $bytes));
+            return -Math::BigInt->new('0x' . unpack('H*', scalar reverse $bytes));
+        }
+        else {
+            return Math::BigInt->new('0x' . unpack('H*', scalar reverse $bytes));
+        }
+    }
+    return unpack('q<', $bytes);
+}
 
 
 sub is_uuid { defined $_[0] && !is_ref($_[0]) && length($_[0]) == 16 }
@@ -803,7 +869,7 @@ File::KDBX::Util - Utility functions for working with KDBX files
 
 =head1 VERSION
 
-version 0.901
+version 0.902
 
 =head1 FUNCTIONS
 
@@ -812,8 +878,8 @@ version 0.901
     $bool = load_xs();
     $bool = load_xs($version);
 
-Attempt to load L<File::KDBX::XS>. Return truthy if C<XS> is loaded. If C<$version> is given, it will check
-that at least the given version is loaded.
+Attempt to load L<File::KDBX::XS>. Return truthy if it is loaded. If C<$version> is given, it will check that
+at least the given version is loaded.
 
 =head2 assert
 
@@ -821,12 +887,6 @@ that at least the given version is loaded.
 
 Write an executable comment. Only executed if C<DEBUG> is set in the environment.
 
-=head2 assert_64bit
-
-    assert_64bit();
-
-Throw if perl doesn't support 64-bit IVs.
-
 =head2 can_fork
 
     $bool = can_fork;
@@ -992,14 +1052,36 @@ Decompress an octet stream.
 
 Compress an octet stream.
 
-=head2 is_readable
+=head2 int64
+
+    $int = int64($string);
+
+Get a scalar integer capable of holding 64-bit values, initialized with a given default value. On a 64-bit
+perl, it will return a regular SvIV. On a 32-bit perl it will return a L<Math::BigInt>.
+
+=head2 pack_Ql
+
+    $bytes = pack_Ql($int);
+
+Like C<pack('QE<lt>', $int)>, but also works on 32-bit perls.
+
+=head2 pack_ql
+
+    $bytes = pack_ql($int);
+
+Like C<pack('qE<lt>', $int)>, but also works on 32-bit perls.
+
+=head2 unpack_Ql
+
+    $int = unpack_Ql($bytes);
+
+Like C<unpack('QE<lt>', $bytes)>, but also works on 32-bit perls.
 
-=head2 is_writable
+=head2 unpack_ql
 
-    $bool = is_readable($mode);
-    $bool = is_writable($mode);
+    $int = unpack_ql($bytes);
 
-Determine of an C<fopen>-style mode is readable, writable or both.
+Like C<unpack('qE<lt>', $bytes)>, but also works on 32-bit perls.
 
 =head2 is_uuid
 
index b34f59df584865961eddcc6ee5cdfa33e76ca190..3979100fd737dfa0629605c2559936f59c5aa433 100644 (file)
@@ -48,7 +48,7 @@ do { my $x = {
                                       'Crypt::Cipher' => '0',
                                       'Crypt::Digest' => '0',
                                       'Crypt::Mac::HMAC' => '0',
-                                      'Crypt::Misc' => '0.029',
+                                      'Crypt::Misc' => '0.049',
                                       'Crypt::Mode::CBC' => '0',
                                       'Crypt::PRNG' => '0',
                                       'Data::Dumper' => '0',
@@ -58,9 +58,10 @@ do { my $x = {
                                       'File::Temp' => '0',
                                       'Hash::Util::FieldHash' => '0',
                                       'IO::Handle' => '0',
-                                      'IPC::Cmd' => '0.52',
+                                      'IPC::Cmd' => '0.84',
                                       'Iterator::Simple' => '0',
                                       'List::Util' => '1.33',
+                                      'Math::BigInt' => '0',
                                       'Module::Load' => '0',
                                       'Module::Loaded' => '0',
                                       'POSIX' => '0',
@@ -76,6 +77,7 @@ do { my $x = {
                                       'boolean' => '0',
                                       'namespace::clean' => '0',
                                       'overload' => '0',
+                                      'perl' => '5.010',
                                       'strict' => '0',
                                       'warnings' => '0'
                                     }
@@ -97,7 +99,6 @@ do { my $x = {
                                    'Test::More' => '0',
                                    'Test::Warnings' => '0',
                                    'lib' => '0',
-                                   'perl' => '5.006',
                                    'utf8' => '0'
                                  },
                    'suggests' => {
index 8bed335b351ef60e87d4f2d71ae6ff15b7b8de5a..94e1ea86966d035a14401cf9143f3a0825cbd453 100644 (file)
@@ -133,7 +133,7 @@ subtest 'Recycle bin' => sub {
 
     is $kdbx->entries->size, 1, 'Database is not empty';
     is $kdbx->entries(searching => 1)->size, 0, 'Database has no entries if searching';
-    cmp_ok $bin->entries_deeply->size, '==', 1, 'Recycle bin has an entry';
+    cmp_ok $bin->all_entries->size, '==', 1, 'Recycle bin has an entry';
 
     $entry->recycle_or_remove;
     is $kdbx->entries->size, 0, 'Remove entry if it is already in the recycle bin';
index f08b683036af4f71eed1d627bde8149a31c660a7..1581608520220b84ba71f530c6008d0922ab08e1 100644 (file)
--- a/t/entry.t
+++ b/t/entry.t
@@ -82,7 +82,7 @@ subtest 'Accessors' => sub {
     my $entry = File::KDBX::Entry->new;
 
     $entry->creation_time('2022-02-02 12:34:56');
-    cmp_ok $entry->creation_time, '==', 1643805296, 'Creation time coerced into a Time::Piece (epoch)';
+    cmp_ok $entry->creation_time->epoch, '==', 1643805296, 'Creation time coerced into a Time::Piece (epoch)';
     is $entry->creation_time->datetime, '2022-02-02T12:34:56', 'Creation time coerced into a Time::Piece';
 };
 
index fabaa172cf2a9f9644f267d4bd5eec93fe377546..79ad54f8657eb966be346839ded8d444f41e15de 100644 (file)
--- a/t/error.t
+++ b/t/error.t
@@ -80,7 +80,7 @@ subtest 'Warnings' => sub {
     }
 
     SKIP: {
-        skip 'warnings::warnif_at_level is required', 1 if !warnings->can('warnif_at_level');
+        skip 'warnings::warnif_at_level is required', 1 if !warnings::->can('warnif_at_level');
         no warnings 'File::KDBX';
         my @warnings = warnings { alert 'uh oh' };
         is @warnings, 0, 'Warnings can be disabled lexically'
@@ -88,7 +88,7 @@ subtest 'Warnings' => sub {
     }
 
     SKIP: {
-        skip 'warnings::fatal_enabled_at_level is required', 1 if !warnings->can('fatal_enabled_at_level');
+        skip 'warnings::fatal_enabled_at_level is required', 1 if !warnings::->can('fatal_enabled_at_level');
         use warnings FATAL => 'File::KDBX';
         my $exception = exception { alert 'uh oh' };
         like $exception, qr/uh oh/, 'Warnings can be fatal';
index 958348a226c8f4375e388e3b94bab07ffea21719..af670618c5688384c2b23696057d5ff62f7af735 100644 (file)
--- a/t/kdbx2.t
+++ b/t/kdbx2.t
@@ -38,7 +38,7 @@ sub verify_kdbx2 {
         inner_random_stream_key => "\214\aW\253\362\177<\346n`\263l\245\353T\25\261BnFp\177\357\335\36(b\372z\231b\355",
         kdf_parameters => {
             "\$UUID" => "\311\331\363\232b\212D`\277t\r\b\301\212O\352",
-            R => 6000,
+            R => num(6000),
             S => "S\202\207A\3475\265\177\220\331\263[\334\326\365\324B\\\2222zb-f\263m\220\333S\361L\332",
         },
         master_seed => "\253!\2\241\r*|{\227\0276Lx\215\32\\\17\372d\254\255*\21r\376\251\313+gMI\343",
index fac610197039aea31a76d6afc3a6cb6148854d20..e1e5838041deef2f1a213049a71af908e33502ae 100644 (file)
--- a/t/kdbx3.t
+++ b/t/kdbx3.t
@@ -25,7 +25,7 @@ subtest 'Verify Format300' => sub {
         inner_random_stream_key => "\346\n8\2\322\264i\5\5\274\22\377+\16tB\353\210\1\2m\2U%\326\347\355\313\313\340A\305",
         kdf_parameters => {
             "\$UUID" => "\311\331\363\232b\212D`\277t\r\b\301\212O\352",
-            R => 6000,
+            R => num(6000),
             S => "\340\377\235\255\222o\1(\226m\373\tC{K\352\f\332M\302|~P\e\346J\@\275A\227\236\366",
         },
         master_seed => "Z\230\355\353\2303\361\237-p\345\27nM\22<E\252\314k\20\257\302\343p\"y\5sfw ",
@@ -49,7 +49,7 @@ subtest 'Verify NonAscii' => sub {
         inner_random_stream_key => "Z\244]\373\13`\2108=>\r\224\351\373\316\276\253\6\317z\356\302\36\fW\1776Q\366\32\34,",
         kdf_parameters => {
             "\$UUID" => "\311\331\363\232b\212D`\277t\r\b\301\212O\352",
-            R => 6000,
+            R => num(6000),
             S => "l\254\250\255\240U\313\364\336\316#\254\306\231\f%U\207J\235\275\34\b\25036\26\241\a\300\26\332",
         },
         master_seed => "\13\350\370\214{\0276\17dv\31W[H\26\272\4\335\377\356\275N\"\2A1\364\213\226\237\303M",
@@ -72,7 +72,7 @@ subtest 'Verify Compressed' => sub {
         inner_random_stream_key => "+\232\222\302\20\333\254\342YD\371\34\373,\302:\303\247\t\26\$\a\370g\314\32J\240\371;U\234",
         kdf_parameters => {
             "\$UUID" => "\311\331\363\232b\212D`\277t\r\b\301\212O\352",
-            R => 6000,
+            R => num(6000),
             S => "\3!\230hx\363\220nV\23\340\316\262\210\26Z\al?\343\240\260\325\262\31i\223y\b\306\344V",
         },
         master_seed => "\0206\244\265\203m14\257T\372o\16\271\306\347\215\365\376\304\20\356\344\3713\3\303\363\a\5\205\325",
@@ -96,7 +96,7 @@ subtest 'Verify ProtectedStrings' => sub {
         kdf_parameters => ignore(),
         kdf_parameters => {
             "\$UUID" => "\311\331\363\232b\212D`\277t\r\b\301\212O\352",
-            R => 6000,
+            R => num(6000),
             S => "y\251\327\312mW8B\351\273\364#T#m:\370k1\240v\360E\245\304\325\265\313\337\245\211E",
         },
         master_seed => "\355\32<1\311\320\315\24\204\325\250\35+\2525\321\224x?\361\355\310V\322\20\331\324\"\372\334\210\233",
index f1e9cbc69498b932b6b2b4953a13555fb5c95d27..5afceeb7dd8b7d155d4bfd00ed2879afb744d783 100644 (file)
--- a/t/kdbx4.t
+++ b/t/kdbx4.t
@@ -25,11 +25,11 @@ subtest 'Verify Format400' => sub {
         encryption_iv => "3?\207P\233or\220\215h\2240",
         kdf_parameters => {
             "\$UUID" => "\357cm\337\214)DK\221\367\251\244\3\343\n\f",
-            I => 2,
-            M => 1048576,
-            P => 2,
+            I => num(2),
+            M => num(1048576),
+            P => num(2),
             S => "V\254\6m-\206*\260\305\f\0\366\24:4\235\364A\362\346\221\13)}\250\217P\303\303\2\331\245",
-            V => 19,
+            V => num(19),
         },
         master_seed => ";\372y\300yS%\3331\177\231\364u\265Y\361\225\3273h\332R,\22\240a\240\302\271\357\313\23",
     }, 'Extract headers' or diag explain $kdbx->headers;
index e499251a896679b00f7428228aaa806f228e976a..33438d3f9538bd0e1e498d2c4e43fde8d75f6755 100644 (file)
@@ -98,4 +98,5 @@ sub fast_kdf {
     }
     return $params;
 }
+
 1;
index 5ea4359a4894ac40b19baabcd3f8053bc069bbb8..a785b2f7ce1c7dde8f51b270f59474e153daa1d7 100644 (file)
--- a/t/util.t
+++ b/t/util.t
@@ -7,10 +7,11 @@ use lib 't/lib';
 use TestCommon;
 
 use File::KDBX::Util qw(:all);
+use Math::BigInt;
+use Scalar::Util qw(blessed);
 use Test::More;
 
 can_ok('File::KDBX::Util', qw{
-    assert_64bit
     can_fork
     dumper
     empty
@@ -132,4 +133,58 @@ subtest 'Padding' => sub {
     like exception { pad_pkcs7('bar', 0) }, qr/must provide block size/i, 'Size must be non-zero';
 };
 
+subtest '64-bit packing' => sub {
+    for my $test (
+        # bytes, value
+        ["\xfe\xff\xff\xff\xff\xff\xff\xff", -2],
+        ["\xff\xff\xff\xff\xff\xff\xff\xff", -1],
+        ["\x00\x00\x00\x00\x00\x00\x00\x00",  0],
+        ["\x01\x00\x00\x00\x00\x00\x00\x00",  1],
+        ["\x02\x00\x00\x00\x00\x00\x00\x00",  2],
+        ["\x01\x01\x00\x00\x00\x00\x00\x00", 257],
+        ["\xfe\xff\xff\xff\xff\xff\xff\xff", Math::BigInt->new('-2')],
+        ["\xff\xff\xff\xff\xff\xff\xff\xff", Math::BigInt->new('-1')],
+        ["\x00\x00\x00\x00\x00\x00\x00\x00", Math::BigInt->new('0')],
+        ["\x01\x00\x00\x00\x00\x00\x00\x00", Math::BigInt->new('1')],
+        ["\x02\x00\x00\x00\x00\x00\x00\x00", Math::BigInt->new('2')],
+        ["\x01\x01\x00\x00\x00\x00\x00\x00", Math::BigInt->new('257')],
+        ["\xfe\xff\xff\xff\xff\xff\xff\xff", Math::BigInt->new('18446744073709551614')],
+        ["\xff\xff\xff\xff\xff\xff\xff\xff", Math::BigInt->new('18446744073709551615')],
+        ["\xff\xff\xff\xff\xff\xff\xff\xff", Math::BigInt->new('18446744073709551616')], # overflow
+        ["\x02\x00\x00\x00\x00\x00\x00\x80", Math::BigInt->new('-9223372036854775806')],
+        ["\x01\x00\x00\x00\x00\x00\x00\x80", Math::BigInt->new('-9223372036854775807')],
+        ["\x00\x00\x00\x00\x00\x00\x00\x80", Math::BigInt->new('-9223372036854775808')],
+        ["\x00\x00\x00\x00\x00\x00\x00\x80", Math::BigInt->new('-9223372036854775809')], # overflow
+    ) {
+        my ($bytes, $num) = @$test;
+        my $desc = sprintf('Pack %s => %s', $num, unpack('H*', $bytes));
+        $desc =~ s/^(Pack)/$1 bigint/ if blessed $num;
+        my $p = pack_Ql($num);
+        is $p, $bytes, $desc or diag unpack('H*', $p);
+    }
+
+    for my $test (
+        # bytes, unsigned value, signed value
+        ["\x00\x00\x00\x00\x00\x00\x00\x00", 0, 0],
+        ["\x01\x00\x00\x00\x00\x00\x00\x00", 1, 1],
+        ["\x02\x00\x00\x00\x00\x00\x00\x00", 2, 2],
+        ["\xfe\xff\xff\xff\xff\xff\xff\xff", Math::BigInt->new('18446744073709551614'), -2],
+        ["\xff\xff\xff\xff\xff\xff\xff\xff", Math::BigInt->new('18446744073709551615'), -1],
+        ["\x02\x00\x00\x00\x00\x00\x00\x80", Math::BigInt->new('9223372036854775810'),
+            Math::BigInt->new('-9223372036854775806')],
+        ["\x01\x00\x00\x00\x00\x00\x00\x80", Math::BigInt->new('9223372036854775809'),
+            Math::BigInt->new('-9223372036854775807')],
+        ["\x00\x00\x00\x00\x00\x00\x00\x80", Math::BigInt->new('9223372036854775808'),
+            Math::BigInt->new('-9223372036854775808')],
+    ) {
+        my ($bytes, $num1, $num2) = @$test;
+        my $desc = sprintf('Unpack %s => %s', unpack('H*', $bytes), $num1);
+        my $p = unpack_Ql($bytes);
+        cmp_ok $p, '==', $num1, $desc or diag $p;
+        $desc = sprintf('Unpack signed %s => %s', unpack('H*', $bytes), $num2);
+        my $q = unpack_ql($bytes);
+        cmp_ok $q, '==', $num2, $desc or diag $q;
+    };
+};
+
 done_testing;
This page took 0.118778 seconds and 4 git commands to generate.