]> Dogcows Code - chaz/p5-File-KDBX/commitdiff
Version 0.901
authorCharles McGarvey <ccm@cpan.org>
Mon, 2 May 2022 07:19:01 +0000 (01:19 -0600)
committerCharles McGarvey <ccm@cpan.org>
Mon, 2 May 2022 07:19:01 +0000 (01:19 -0600)
48 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/database.t
t/hash-block.t
t/hmac-block.t
t/kdbx3.t
t/keys.t

diff --git a/Changes b/Changes
index 6475c061e1649d7b886d9f93309a4a844b0b00ff..c74d78a99023ca6dc9ae75126e8648e95c882a59 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,12 @@
 Revision history for File-KDBX.
 
+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.
+  * 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
@@ -7,7 +14,7 @@ Revision history for File-KDBX.
   * Now use the database maintenance_history_days value as the default
     "max_age" value in prune_history method.
   * Fixed distribution prereq issues.
-  * Clean up a lot of pod typos and other inaccuracies.
+  * Cleaned up a lot of pod typos and other inaccuracies.
 
 0.800     2022-04-30 21:14:30-0600
 
index 995a8d9cc048144c41066291d8eb6864ea7e24fe..7ee8a969689244bbdb30e6916ffa2d9cb4725061 100644 (file)
--- a/META.json
+++ b/META.json
    "provides" : {
       "File::KDBX" : {
          "file" : "lib/File/KDBX.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Cipher" : {
          "file" : "lib/File/KDBX/Cipher.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Cipher::CBC" : {
          "file" : "lib/File/KDBX/Cipher/CBC.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Cipher::Stream" : {
          "file" : "lib/File/KDBX/Cipher/Stream.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Constants" : {
          "file" : "lib/File/KDBX/Constants.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Dumper" : {
          "file" : "lib/File/KDBX/Dumper.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Dumper::KDB" : {
          "file" : "lib/File/KDBX/Dumper/KDB.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Dumper::Raw" : {
          "file" : "lib/File/KDBX/Dumper/Raw.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Dumper::V3" : {
          "file" : "lib/File/KDBX/Dumper/V3.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Dumper::V4" : {
          "file" : "lib/File/KDBX/Dumper/V4.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Dumper::XML" : {
          "file" : "lib/File/KDBX/Dumper/XML.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Entry" : {
          "file" : "lib/File/KDBX/Entry.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Error" : {
          "file" : "lib/File/KDBX/Error.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Group" : {
          "file" : "lib/File/KDBX/Group.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::IO" : {
          "file" : "lib/File/KDBX/IO.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::IO::Crypt" : {
          "file" : "lib/File/KDBX/IO/Crypt.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::IO::HashBlock" : {
          "file" : "lib/File/KDBX/IO/HashBlock.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::IO::HmacBlock" : {
          "file" : "lib/File/KDBX/IO/HmacBlock.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Iterator" : {
          "file" : "lib/File/KDBX/Iterator.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::KDF" : {
          "file" : "lib/File/KDBX/KDF.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::KDF::AES" : {
          "file" : "lib/File/KDBX/KDF/AES.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::KDF::Argon2" : {
          "file" : "lib/File/KDBX/KDF/Argon2.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Key" : {
          "file" : "lib/File/KDBX/Key.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Key::ChallengeResponse" : {
          "file" : "lib/File/KDBX/Key/ChallengeResponse.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Key::Composite" : {
          "file" : "lib/File/KDBX/Key/Composite.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Key::File" : {
          "file" : "lib/File/KDBX/Key/File.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Key::Password" : {
          "file" : "lib/File/KDBX/Key/Password.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Key::YubiKey" : {
          "file" : "lib/File/KDBX/Key/YubiKey.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Loader" : {
          "file" : "lib/File/KDBX/Loader.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Loader::KDB" : {
          "file" : "lib/File/KDBX/Loader/KDB.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Loader::Raw" : {
          "file" : "lib/File/KDBX/Loader/Raw.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Loader::V3" : {
          "file" : "lib/File/KDBX/Loader/V3.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Loader::V4" : {
          "file" : "lib/File/KDBX/Loader/V4.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Loader::XML" : {
          "file" : "lib/File/KDBX/Loader/XML.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Object" : {
          "file" : "lib/File/KDBX/Object.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Safe" : {
          "file" : "lib/File/KDBX/Safe.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Transaction" : {
          "file" : "lib/File/KDBX/Transaction.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       },
       "File::KDBX::Util" : {
          "file" : "lib/File/KDBX/Util.pm",
-         "version" : "0.900"
+         "version" : "0.901"
       }
    },
    "release_status" : "stable",
          "web" : "https://github.com/chazmcgarvey/File-KDBX"
       }
    },
-   "version" : "0.900",
+   "version" : "0.901",
    "x_authority" : "cpan:CCM",
    "x_generated_by_perl" : "v5.34.1",
    "x_serialization_backend" : "Cpanel::JSON::XS version 4.27",
index 5f0f5ca58e96a69c8c6dfdbf58ba73403cdc92e3..3473a03e913e86f1a0760025deb0c4f12ab0810b 100644 (file)
--- a/META.yml
+++ b/META.yml
@@ -50,118 +50,118 @@ optional_features:
 provides:
   File::KDBX:
     file: lib/File/KDBX.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Cipher:
     file: lib/File/KDBX/Cipher.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Cipher::CBC:
     file: lib/File/KDBX/Cipher/CBC.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Cipher::Stream:
     file: lib/File/KDBX/Cipher/Stream.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Constants:
     file: lib/File/KDBX/Constants.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Dumper:
     file: lib/File/KDBX/Dumper.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Dumper::KDB:
     file: lib/File/KDBX/Dumper/KDB.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Dumper::Raw:
     file: lib/File/KDBX/Dumper/Raw.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Dumper::V3:
     file: lib/File/KDBX/Dumper/V3.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Dumper::V4:
     file: lib/File/KDBX/Dumper/V4.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Dumper::XML:
     file: lib/File/KDBX/Dumper/XML.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Entry:
     file: lib/File/KDBX/Entry.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Error:
     file: lib/File/KDBX/Error.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Group:
     file: lib/File/KDBX/Group.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::IO:
     file: lib/File/KDBX/IO.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::IO::Crypt:
     file: lib/File/KDBX/IO/Crypt.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::IO::HashBlock:
     file: lib/File/KDBX/IO/HashBlock.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::IO::HmacBlock:
     file: lib/File/KDBX/IO/HmacBlock.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Iterator:
     file: lib/File/KDBX/Iterator.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::KDF:
     file: lib/File/KDBX/KDF.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::KDF::AES:
     file: lib/File/KDBX/KDF/AES.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::KDF::Argon2:
     file: lib/File/KDBX/KDF/Argon2.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Key:
     file: lib/File/KDBX/Key.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Key::ChallengeResponse:
     file: lib/File/KDBX/Key/ChallengeResponse.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Key::Composite:
     file: lib/File/KDBX/Key/Composite.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Key::File:
     file: lib/File/KDBX/Key/File.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Key::Password:
     file: lib/File/KDBX/Key/Password.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Key::YubiKey:
     file: lib/File/KDBX/Key/YubiKey.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Loader:
     file: lib/File/KDBX/Loader.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Loader::KDB:
     file: lib/File/KDBX/Loader/KDB.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Loader::Raw:
     file: lib/File/KDBX/Loader/Raw.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Loader::V3:
     file: lib/File/KDBX/Loader/V3.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Loader::V4:
     file: lib/File/KDBX/Loader/V4.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Loader::XML:
     file: lib/File/KDBX/Loader/XML.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Object:
     file: lib/File/KDBX/Object.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Safe:
     file: lib/File/KDBX/Safe.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Transaction:
     file: lib/File/KDBX/Transaction.pm
-    version: '0.900'
+    version: '0.901'
   File::KDBX::Util:
     file: lib/File/KDBX/Util.pm
-    version: '0.900'
+    version: '0.901'
 recommends:
   Compress::Raw::Zlib: '0'
   File::KDBX::XS: '0'
@@ -209,7 +209,7 @@ 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.900'
+version: '0.901'
 x_authority: cpan:CCM
 x_generated_by_perl: v5.34.1
 x_serialization_backend: 'YAML::Tiny version 1.73'
index 40792ca90ee0711cdb9d88a365a57f9194e245ce..7c6ce7ce73d0c7cf4cb3b22e654183056154b2d9 100644 (file)
@@ -67,7 +67,7 @@ my %WriteMakefileArgs = (
     "lib" => 0,
     "utf8" => 0
   },
-  "VERSION" => "0.900",
+  "VERSION" => "0.901",
   "test" => {
     "TESTS" => "t/*.t"
   }
diff --git a/README b/README
index 42cd205d53e5bcbde85da97bf5202733a712bfab..06be87c3ad1d7f20b7f645e13de64a2c92eadc68 100644 (file)
--- a/README
+++ b/README
@@ -4,7 +4,7 @@ NAME
 
 VERSION
 
-    version 0.900
+    version 0.901
 
 SYNOPSIS
 
@@ -784,12 +784,12 @@ METHODS
 
         $kdbx->lock;
 
-    Encrypt all protected binaries strings in a database. The encrypted
-    strings are stored in a File::KDBX::Safe associated with the database
-    and the actual strings will be replaced with undef to indicate their
+    Encrypt all protected strings and binaries in a database. The encrypted
+    data is stored in a File::KDBX::Safe associated with the database and
+    the actual values will be replaced with undef to indicate their
     protected state. Returns itself to allow method chaining.
 
-    You can call code on an already-locked database to memory-protect any
+    You can call lock on an already-locked database to memory-protect any
     unprotected strings and binaries added after the last time the database
     was locked.
 
@@ -797,9 +797,9 @@ METHODS
 
         $kdbx->unlock;
 
-    Decrypt all protected strings in a database, replacing undef
-    placeholders with unprotected values. Returns itself to allow method
-    chaining.
+    Decrypt all protected strings and binaries in a database, replacing
+    undef value placeholders with their actual, unprotected values. Returns
+    itself to allow method chaining.
 
  unlock_scoped
 
@@ -811,6 +811,14 @@ METHODS
 
     See "lock" and "unlock".
 
+    Example:
+
+        {
+            my $guard = $kdbx->unlock_scoped;
+            ...;
+        }
+        # $kdbx is now memory-locked
+
  peek
 
         $string = $kdbx->peek(\%string);
@@ -825,10 +833,10 @@ METHODS
 
         $bool = $kdbx->is_locked;
 
-    Get whether or not a database's strings are memory-protected. If this
-    is true, then some or all of the protected strings within the database
-    will be unavailable (literally have undef values) until "unlock" is
-    called.
+    Get whether or not a database's contents are in a locked (i.e.
+    memory-protected) state. If this is true, then some or all of the
+    protected strings and binaries within the database will be unavailable
+    (literally have undef values) until "unlock" is called.
 
  remove_empty_groups
 
@@ -896,8 +904,8 @@ METHODS
 
     Get or set a File::KDBX::Key. This is the master key (e.g. a password
     or a key file that can decrypt a database). You can also pass a
-    primitive that can be cast to a Key. See "new" in File::KDBX::Key for
-    an explanation of what the primitive can be.
+    primitive castable to a Key. See "new" in File::KDBX::Key for an
+    explanation of what the primitive can be.
 
     You generally don't need to call this directly because you can provide
     the key directly to the loader or dumper when loading or dumping a KDBX
@@ -1500,14 +1508,14 @@ ERRORS
 
     Errors in this package are constructed as File::KDBX::Error objects and
     propagated using perl's built-in mechanisms. Fatal errors are
-    propagated using "die" in functions and non-fatal errors (a.k.a.
-    warnings) are propagated using "warn" in functions while adhering to
-    perl's warnings system. If you're already familiar with these
+    propagated using "die LIST" in perlfunc and non-fatal errors (a.k.a.
+    warnings) are propagated using "warn LIST" in perlfunc while adhering
+    to perl's warnings system. If you're already familiar with these
     mechanisms, you can skip this section.
 
-    You can catch fatal errors using "eval" in functions (or something like
-    Try::Tiny) and non-fatal errors using $SIG{__WARN__} (see "%SIG" in
-    variables). Examples:
+    You can catch fatal errors using "eval BLOCK" in perlfunc (or something
+    like Try::Tiny) and non-fatal errors using $SIG{__WARN__} (see "%SIG"
+    in perlvar). Examples:
 
         use File::KDBX::Error qw(error);
     
index d2dc04f8d27118a2ce6cef89b87ef6697f6bfb35..c8686eff66625f34fb280169a598f2e27b79cd57 100644 (file)
@@ -19,7 +19,7 @@ use Time::Piece;
 use boolean;
 use namespace::clean;
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 our $WARNINGS = 1;
 
 fieldhashes \my (%SAFE, %KEYS);
@@ -796,7 +796,7 @@ sub peek {
 }
 
 
-sub is_locked { $_[0]->_safe ? 1 : 0 }
+sub is_locked { !!$_[0]->_safe }
 
 ##############################################################################
 
@@ -1120,7 +1120,7 @@ File::KDBX - Encrypted database to store secret text and files
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 SYNOPSIS
 
@@ -1933,19 +1933,19 @@ To get the I<Password> string of a specific entry (identified by its UUID):
 
     $kdbx->lock;
 
-Encrypt all protected binaries strings in a database. The encrypted strings are stored in
-a L<File::KDBX::Safe> associated with the database and the actual strings will be replaced with C<undef> to
+Encrypt all protected strings and binaries in a database. The encrypted data is stored in
+a L<File::KDBX::Safe> associated with the database and the actual values will be replaced with C<undef> to
 indicate their protected state. Returns itself to allow method chaining.
 
-You can call C<code> on an already-locked database to memory-protect any unprotected strings and binaries
+You can call C<lock> on an already-locked database to memory-protect any unprotected strings and binaries
 added after the last time the database was locked.
 
 =head2 unlock
 
     $kdbx->unlock;
 
-Decrypt all protected strings in a database, replacing C<undef> placeholders with unprotected values. Returns
-itself to allow method chaining.
+Decrypt all protected strings and binaries in a database, replacing C<undef> value placeholders with their
+actual, unprotected values. Returns itself to allow method chaining.
 
 =head2 unlock_scoped
 
@@ -1956,6 +1956,14 @@ C<undef> if the database is already unlocked.
 
 See L</lock> and L</unlock>.
 
+Example:
+
+    {
+        my $guard = $kdbx->unlock_scoped;
+        ...;
+    }
+    # $kdbx is now memory-locked
+
 =head2 peek
 
     $string = $kdbx->peek(\%string);
@@ -1968,9 +1976,9 @@ a string or binary hashref as returned by L<File::KDBX::Entry/string> or L<File:
 
     $bool = $kdbx->is_locked;
 
-Get whether or not a database's strings are memory-protected. If this is true, then some or all of the
-protected strings within the database will be unavailable (literally have C<undef> values) until L</unlock> is
-called.
+Get whether or not a database's contents are in a locked (i.e. memory-protected) state. If this is true, then
+some or all of the protected strings and binaries within the database will be unavailable (literally have
+C<undef> values) until L</unlock> is called.
 
 =head2 remove_empty_groups
 
@@ -2053,8 +2061,8 @@ You normally do not need to call this method explicitly because the dumper does
     $key = $kdbx->key($primitive);
 
 Get or set a L<File::KDBX::Key>. This is the master key (e.g. a password or a key file that can decrypt
-a database). You can also pass a primitive that can be cast to a B<Key>. See L<File::KDBX::Key/new> for an
-explanation of what the primitive can be.
+a database). You can also pass a primitive castable to a B<Key>. See L<File::KDBX::Key/new> for an explanation
+of what the primitive can be.
 
 You generally don't need to call this directly because you can provide the key directly to the loader or
 dumper when loading or dumping a KDBX file.
@@ -2711,12 +2719,12 @@ B<TODO> - This is a planned feature, not yet implemented.
 =head1 ERRORS
 
 Errors in this package are constructed as L<File::KDBX::Error> objects and propagated using perl's built-in
-mechanisms. Fatal errors are propagated using L<functions/die> and non-fatal errors (a.k.a. warnings) are
-propagated using L<functions/warn> while adhering to perl's L<warnings> system. If you're already familiar
-with these mechanisms, you can skip this section.
+mechanisms. Fatal errors are propagated using L<perlfunc/"die LIST"> and non-fatal errors (a.k.a. warnings)
+are propagated using L<perlfunc/"warn LIST"> while adhering to perl's L<warnings> system. If you're already
+familiar with these mechanisms, you can skip this section.
 
-You can catch fatal errors using L<functions/eval> (or something like L<Try::Tiny>) and non-fatal errors using
-C<$SIG{__WARN__}> (see L<variables/%SIG>). Examples:
+You can catch fatal errors using L<perlfunc/"eval BLOCK"> (or something like L<Try::Tiny>) and non-fatal
+errors using C<$SIG{__WARN__}> (see L<perlvar/%SIG>). Examples:
 
     use File::KDBX::Error qw(error);
 
index fd335a38a877f10f3582438560f0fa23fe974c61..250b9cf3c4d493e2734a2cbd92c2018bdc6abd99 100644 (file)
@@ -12,7 +12,7 @@ use Module::Load;
 use Scalar::Util qw(looks_like_number);
 use namespace::clean;
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 my %CIPHERS;
 
@@ -158,7 +158,7 @@ File::KDBX::Cipher - A block cipher mode or cipher stream
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 SYNOPSIS
 
index 0dbdc6c5e74257eb53639a74e4fec8c5b0f8c9c7..a759452d830eefa98410b490b12578a826318a0d 100644 (file)
@@ -11,7 +11,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Cipher';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # 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.900
+version 0.901
 
 =head1 SYNOPSIS
 
index 2cd4033c21f3cc16d20a6b27d41584ef7275c628..2b0c9f203f58ab0f366d2add19209ee307888274 100644 (file)
@@ -14,7 +14,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Cipher';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 
 has 'counter',  is => 'ro', default => 0;
@@ -123,7 +123,7 @@ File::KDBX::Cipher::Stream - A cipher stream encrypter/decrypter
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 SYNOPSIS
 
index a3d5baaeb7bb70eedba7729e2bbfe41e808a9408..f31cc0ce55a509828b70f174de50d06a822b655b 100644 (file)
@@ -13,7 +13,7 @@ use Exporter qw(import);
 use Scalar::Util qw(dualvar);
 use namespace::clean -except => 'import';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 BEGIN {
     my %CONSTANTS = (
@@ -346,7 +346,7 @@ File::KDBX::Constants - All the KDBX-related constants you could ever want
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 SYNOPSIS
 
index 3b3d311f19d5e1f22cb4de896676ea9eaaccdd25..f6d6657abd9ec00819248715012756251312ce10 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.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 
 sub new {
@@ -118,16 +118,27 @@ sub dump_file {
     my $filepath = shift;
     my %args     = @_ % 2 == 0 ? @_ : (key => shift, @_);
 
-    my $key = delete $args{key};
+    my $key     = delete $args{key};
+    my $mode    = delete $args{mode};
+    my $uid     = delete $args{uid};
+    my $gid     = delete $args{gid};
+    my $atomic  = delete $args{atomic} // 1;
+
     $args{kdbx} //= $self->kdbx;
 
-    require File::Temp;
-    my ($fh, $filepath_temp) = eval { File::Temp::tempfile("${filepath}-XXXXXX", CLEANUP => 1) };
-    if (!$fh or my $err = $@) {
-        $err //= 'Unknown error';
-        throw sprintf('Open file failed (%s): %s', $filepath_temp, $err),
-            error       => $err,
-            filepath    => $filepath_temp;
+    my ($fh, $filepath_temp);
+    if ($atomic) {
+        require File::Temp;
+        ($fh, $filepath_temp) = eval { File::Temp::tempfile("${filepath}-XXXXXX", UNLINK => 1) };
+        if (!$fh or my $err = $@) {
+            $err //= 'Unknown error';
+            throw sprintf('Open file failed (%s): %s', $filepath_temp, $err),
+                error       => $err,
+                filepath    => $filepath_temp;
+        }
+    }
+    else {
+        open($fh, '>:raw', $filepath) or throw "Open file failed ($filepath): $!", filepath => $filepath;
     }
     $fh->autoflush(1);
 
@@ -138,12 +149,15 @@ sub dump_file {
 
     my ($file_mode, $file_uid, $file_gid) = (stat($filepath))[2, 4, 5];
 
-    my $mode = $args{mode} // $file_mode // do { my $m = umask; defined $m ? oct(666) &~ $m : undef };
-    my $uid  = $args{uid}  // $file_uid  // -1;
-    my $gid  = $args{gid}  // $file_gid  // -1;
-    chmod($mode, $filepath_temp) if defined $mode;
-    chown($uid, $gid, $filepath_temp);
-    rename($filepath_temp, $filepath) or throw "Failed to write file ($filepath): $!", filepath => $filepath;
+    if ($filepath_temp) {
+        $mode //= $file_mode // do { my $m = umask; defined $m ? oct(666) &~ $m : undef };
+        $uid  //= $file_uid  // -1;
+        $gid  //= $file_gid  // -1;
+        chmod($mode, $filepath_temp) if defined $mode;
+        chown($uid, $gid, $filepath_temp);
+        rename($filepath_temp, $filepath) or throw "Failed to write file ($filepath): $!",
+            filepath => $filepath;
+    }
 
     return $self;
 }
@@ -273,7 +287,7 @@ File::KDBX::Dumper - Write KDBX files
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 ATTRIBUTES
 
@@ -379,33 +393,108 @@ Set a L<File::KDBX::Dumper> to a blank state, ready to dump another KDBX file.
 
 =head2 dump
 
-    $dumper->dump(\$string, $key);
-    $dumper->dump(*IO, $key);
-    $dumper->dump($filepath, $key);
+    $dumper->dump(\$string, %options);
+    $dumper->dump(\$string, $key, %options);
+    $dumper->dump(*IO, %options);
+    $dumper->dump(*IO, $key, %options);
+    $dumper->dump($filepath, %options);
+    $dumper->dump($filepath, $key, %options);
 
 Dump a KDBX file.
 
-The C<$key> is either a L<File::KDBX::Key> or a primitive that can be cast to a Key object.
+The C<$key> is either a L<File::KDBX::Key> or a primitive castable to a Key object. Available options:
+
+=over 4
+
+=item *
+
+C<kdbx> - Database to dump (default: value of L</kdbx>)
+
+=item *
+
+C<key> - Alternative way to specify C<$key> (default: value of L</File::KDBX/key>)
+
+=back
+
+Other options are supported depending on the first argument. See L</dump_string>, L</dump_file> and
+L</dump_handle>.
 
 =head2 dump_string
 
-    $dumper->dump_string(\$string, $key);
-    \$string = $dumper->dump_string($key);
+    $dumper->dump_string(\$string, %options);
+    $dumper->dump_string(\$string, $key, %options);
+    \$string = $dumper->dump_string(%options);
+    \$string = $dumper->dump_string($key, %options);
+
+Dump a KDBX file to a string / memory buffer. Available options:
+
+=over 4
+
+=item *
 
-Dump a KDBX file to a string / memory buffer.
+C<kdbx> - Database to dump (default: value of L</kdbx>)
+
+=item *
+
+C<key> - Alternative way to specify C<$key> (default: value of L</File::KDBX/key>)
+
+=back
 
 =head2 dump_file
 
-    $dumper->dump_file($filepath, $key);
+    $dumper->dump_file($filepath, %options);
+    $dumper->dump_file($filepath, $key, %options);
 
-Dump a KDBX file to a filesystem.
+Dump a KDBX file to a filesystem. Available options:
+
+=over 4
+
+=item *
+
+C<kdbx> - Database to dump (default: value of L</kdbx>)
+
+=item *
+
+C<key> - Alternative way to specify C<$key> (default: value of L</File::KDBX/key>)
+
+=item *
+
+C<mode> - File mode / permissions (see L<perlfunc/"chmod LIST">
+
+=item *
+
+C<uid> - User ID (see L<perlfunc/"chown LIST">)
+
+=item *
+
+C<gid> - Group ID (see L<perlfunc/"chown LIST">)
+
+=item *
+
+C<atomic> - Write to the filepath atomically (default: true)
+
+=back
 
 =head2 dump_handle
 
-    $dumper->dump_handle($fh, $key);
-    $dumper->dump_handle(*IO, $key);
+    $dumper->dump_handle($fh, %options);
+    $dumper->dump_handle(*IO, $key, %options);
+    $dumper->dump_handle($fh, %options);
+    $dumper->dump_handle(*IO, $key, %options);
+
+Dump a KDBX file to an output stream / file handle. Available options:
+
+=over 4
+
+=item *
+
+C<kdbx> - Database to dump (default: value of L</kdbx>)
 
-Dump a KDBX file to an output stream / file handle.
+=item *
+
+C<key> - Alternative way to specify C<$key> (default: value of L</File::KDBX/key>)
+
+=back
 
 =head1 BUGS
 
index 39ab4f64d8c6f1e92a2c878cb9790d8777bcb4c5..4f35970617b38ffe40362a08306dcf4ba9fc4485 100644 (file)
@@ -14,7 +14,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Dumper';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 sub _write_magic_numbers { '' }
 sub _write_headers { '' }
@@ -138,7 +138,7 @@ File::KDBX::Dumper::KDB - Write KDB files
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 DESCRIPTION
 
index 1153fccdb8ff8a9ba6e374fd0d4deeb1d54eeb23..d6d2173daf05d7235b7fdc8421b60d45564f28b6 100644 (file)
@@ -9,7 +9,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Dumper';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # 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.900
+version 0.901
 
 =head1 SYNOPSIS
 
index 394dce33b71c99a0cdbc4a5373589a6a270c0519..a5f7ef0963ccce82ab5b56611bc15fedea1cdbd7 100644 (file)
@@ -16,7 +16,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Dumper';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 sub _write_headers {
     my $self = shift;
@@ -189,7 +189,7 @@ File::KDBX::Dumper::V3 - Dump KDBX3 files
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 BUGS
 
index 061bd087f339045a7d5883b297dbe620d71bfa31..c5644d4ebf545715cc8191496b93d0b1de89325e 100644 (file)
@@ -19,7 +19,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Dumper';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 has _binaries_written => {}, is => 'ro';
 
@@ -377,7 +377,7 @@ File::KDBX::Dumper::V4 - Dump KDBX4 files
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 BUGS
 
index f5b62f07230e1ebfa022f1e3e364183e0437e21e..1d7ec39a90e353edb64e7b9137cf80b505819f04 100644 (file)
@@ -19,7 +19,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Dumper';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 
 has allow_protection => 1;
@@ -564,7 +564,7 @@ File::KDBX::Dumper::XML - Dump unencrypted XML KeePass files
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 ATTRIBUTES
 
index be4a6a37f4cba04aba1e69a3d896e46ccefa5c34..801237238c22a78da9130c22dacbbd9631eb14f7 100644 (file)
@@ -21,7 +21,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Object';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 my $PLACEHOLDER_MAX_DEPTH = 10;
 my %PLACEHOLDERS;
@@ -681,7 +681,7 @@ File::KDBX::Entry - A KDBX database entry
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 DESCRIPTION
 
index f902f79e8749f9c72804f2c8543a991e56d02b9a..5e3de9073cb776d03b906d3ee1a5bff650827f30 100644 (file)
@@ -8,7 +8,7 @@ use Exporter qw(import);
 use Scalar::Util qw(blessed looks_like_number);
 use namespace::clean -except => 'import';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 our @EXPORT = qw(alert error throw);
 
@@ -166,7 +166,7 @@ File::KDBX::Error - Represents something bad that happened
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 ATTRIBUTES
 
index fe087d24cecab38a832fd06e177ea84b59320553..c81f34b8691ba14305cf7f3de2c95c55ef1ac251 100644 (file)
@@ -19,7 +19,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Object';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 
 # has uuid                        => sub { generate_uuid(printable => 1) };
@@ -398,7 +398,7 @@ File::KDBX::Group - A KDBX database group
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 DESCRIPTION
 
index 6dc5c9bb97af250f5b30e2f2e1399b75a214234f..0ac45298509e5e7058ac00da58ad41117963ff17 100644 (file)
@@ -14,7 +14,7 @@ use namespace::clean;
 
 extends 'IO::Handle';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # 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.900
+version 0.901
 
 =head1 DESCRIPTION
 
index 0d597234e140ba2b37ccbfed94dfffc6cf705153..09749334d6ee4f06bbd363b9a13e3291cd555860 100644 (file)
@@ -11,7 +11,7 @@ use namespace::clean;
 
 extends 'File::KDBX::IO';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 our $BUFFER_SIZE = 16384;
 our $ERROR;
 
@@ -139,7 +139,7 @@ File::KDBX::IO::Crypt - Encrypter/decrypter IO handle
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 SYNOPSIS
 
index 21e8a108d0cdd95c603275e591e6765c6545852a..f1bdf92be3e2afa5b9c266ec25b35cdc62c22c30 100644 (file)
@@ -13,7 +13,7 @@ use namespace::clean;
 
 extends 'File::KDBX::IO';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # 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.900
+version 0.901
 
 =head1 DESCRIPTION
 
index 650d6816e2b3430984917d7b7fc572904c7df650..ae36c95f7c09471055e95451a4b2d3107203a30c 100644 (file)
@@ -13,7 +13,7 @@ use namespace::clean;
 
 extends 'File::KDBX::IO';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 our $BLOCK_SIZE = 1048576;  # 1MiB
 our $ERROR;
 
@@ -214,7 +214,7 @@ File::KDBX::IO::HmacBlock - HMAC block stream IO handle
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 DESCRIPTION
 
index 3f0124d78b1cc8984c1bc6aac3515708a9a4d919..72de0011ab933d59890e493c1a033a9311449b02 100644 (file)
@@ -14,7 +14,7 @@ use namespace::clean;
 BEGIN { mark_as_loaded('Iterator::Simple::Iterator') }
 extends 'Iterator::Simple::Iterator';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 
 sub new {
@@ -221,7 +221,7 @@ File::KDBX::Iterator - KDBX database iterator
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 SYNOPSIS
 
index 4b7c9208fe96d7bb16c43c4cf7076552a133efd7..f1e0196a57227ba5b4c95ecbb74e36b906c8ab29 100644 (file)
@@ -12,7 +12,7 @@ use Module::Load;
 use Scalar::Util qw(blessed);
 use namespace::clean;
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 my %KDFS;
 
@@ -120,7 +120,7 @@ File::KDBX::KDF - A key derivation function
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 DESCRIPTION
 
index 07ff122fd7c6113c1a9d9d352a23c6b666b712fa..b5d22c9867e50615930f7b7f562e323718e6529d 100644 (file)
@@ -13,7 +13,7 @@ use namespace::clean;
 
 extends 'File::KDBX::KDF';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # 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.900
+version 0.901
 
 =head1 DESCRIPTION
 
index 995147305c938e812ae68f57648d988b066a78be..4c9146f2f7f95626ce3eb527fb777790d720bf14 100644 (file)
@@ -12,7 +12,7 @@ use namespace::clean;
 
 extends 'File::KDBX::KDF';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # 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.900
+version 0.901
 
 =head1 DESCRIPTION
 
index 93330729085ec4578857cec034b0df873cbecae6..12fa430b8b32a4adad195d3919fd7ab040dccaa4 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.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 fieldhashes \my %SAFE;
 
@@ -140,7 +140,7 @@ File::KDBX::Key - A credential that can protect a KDBX file
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 DESCRIPTION
 
index 1dd88ee36934b4895c4ae47c44261c9997a3a354..843c892a68eb9ebf7cc8fb3aa36ab4b2ce07f837 100644 (file)
@@ -10,7 +10,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Key';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 sub init {
     my $self = shift;
@@ -56,7 +56,7 @@ File::KDBX::Key::ChallengeResponse - A challenge-response key
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 SYNOPSIS
 
index 9ecc0f1022233d6fae7ba9778e3874c7a67bd6f4..e6f3d932d2885891208b6e03b24ccb8a5b1945b0 100644 (file)
@@ -13,7 +13,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Key';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # 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.900
+version 0.901
 
 =head1 SYNOPSIS
 
index 6e4173e987bd883261685b9d8b3639733537f51d..2223870ab7bf8fe14b105cfdfe370d087dcfcfe6 100644 (file)
@@ -17,7 +17,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Key';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 
 has 'type',     is => 'ro';
@@ -99,18 +99,24 @@ sub save {
     my $version     = $args{version} // $self->version // 2;
     my $filepath    = $args{filepath} // $self->filepath;
     my $fh          = $args{fh};
+    my $atomic      = $args{atomic} // 1;
 
     my $filepath_temp;
     if (!openhandle($fh)) {
         $filepath or throw 'Must specify where to safe the key file to';
 
-        require File::Temp;
-        ($fh, $filepath_temp) = eval { File::Temp::tempfile("${filepath}-XXXXXX", CLEANUP => 1) };
-        if (!$fh or my $err = $@) {
-            $err //= 'Unknown error';
-            throw sprintf('Open file failed (%s): %s', $filepath_temp, $err),
-                error       => $err,
-                filepath    => $filepath_temp;
+        if ($atomic) {
+            require File::Temp;
+            ($fh, $filepath_temp) = eval { File::Temp::tempfile("${filepath}-XXXXXX", UNLINK => 1) };
+            if (!$fh or my $err = $@) {
+                $err //= 'Unknown error';
+                throw sprintf('Open file failed (%s): %s', $filepath_temp, $err),
+                    error       => $err,
+                    filepath    => $filepath_temp;
+            }
+        }
+        else {
+            open($fh, '>:raw', $filepath) or throw "Open file failed ($filepath): $!", filepath => $filepath;
         }
     }
 
@@ -256,7 +262,7 @@ File::KDBX::Key::File - A file key
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 SYNOPSIS
 
@@ -377,6 +383,10 @@ C<fh> - IO handle to write to (overrides C<filepath>, one of which must be defin
 
 C<raw_key> - Raw key (default: value of L</raw_key>)
 
+=item *
+
+C<atomic> - Write to the filepath atomically (default: true)
+
 =back
 
 =head1 BUGS
index d7aa7d5a3b474e890f6d9839dc0e88b54e850a4c..fe0facebbe34f94cfe80a19037cd16ebffc27b70 100644 (file)
@@ -12,7 +12,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Key';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 sub init {
     my $self = shift;
@@ -37,7 +37,7 @@ File::KDBX::Key::Password - A password key
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 SYNOPSIS
 
index 949f34899ab0526a729c3e1ebb643593b581be24..1185fa12199cb1edb1086591c8bb143d7ef199fe 100644 (file)
@@ -14,7 +14,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Key::ChallengeResponse';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # 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.900
+version 0.901
 
 =head1 SYNOPSIS
 
index dd0caff93e8813ff376211d0ba3c704d1f1c244f..69a7bfb61de90c3a4ecb1eab9d69b27721877dcf 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.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 
 sub new {
@@ -249,7 +249,7 @@ File::KDBX::Loader - Load KDBX files
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 DESCRIPTION
 
@@ -333,37 +333,73 @@ Set a L<File::KDBX::Loader> to a blank state, ready to load another KDBX file.
 
 =head2 load
 
+    $kdbx = File::KDBX::Loader->load(\$string, %options);
     $kdbx = File::KDBX::Loader->load(\$string, $key);
+    $kdbx = File::KDBX::Loader->load(*IO, %options);
     $kdbx = File::KDBX::Loader->load(*IO, $key);
+    $kdbx = File::KDBX::Loader->load($filepath, %options);
     $kdbx = File::KDBX::Loader->load($filepath, $key);
-    $kdbx = $loader->load(...); # also instance method
 
-Load a KDBX file.
+Load a KDBX file. This works as an instance or a class method. The C<$key> is either
+a L<File::KDBX::Key> or a primitive castable to a Key object. Available options:
 
-The C<$key> is either a L<File::KDBX::Key> or a primitive that can be cast to a Key object.
+=over 4
+
+=item *
+
+C<key> - Alternative way to specify C<$key>
+
+=back
 
 =head2 load_string
 
+    $kdbx = File::KDBX::Loader->load_string($string, %options);
     $kdbx = File::KDBX::Loader->load_string($string, $key);
+    $kdbx = File::KDBX::Loader->load_string(\$string, %options);
     $kdbx = File::KDBX::Loader->load_string(\$string, $key);
-    $kdbx = $loader->load_string(...); # also instance method
 
-Load a KDBX file from a string / memory buffer.
+Load a KDBX file from a string / memory buffer. This works as an instance or class method. Available options:
+
+=over 4
+
+=item *
+
+C<key> - Alternative way to specify C<$key>
+
+=back
 
 =head2 load_file
 
+    $kdbx = File::KDBX::Loader->load_file($filepath, %options);
     $kdbx = File::KDBX::Loader->load_file($filepath, $key);
-    $kdbx = $loader->load_file(...); # also instance method
 
-Read a KDBX file from a filesystem.
+Read a KDBX file from a filesystem. This works as an instance or class method. Available options:
+
+=over 4
+
+=item *
+
+C<key> - Alternative way to specify C<$key>
+
+=back
 
 =head2 load_handle
 
+    $kdbx = File::KDBX::Loader->load_handle($fh, %options);
     $kdbx = File::KDBX::Loader->load_handle($fh, $key);
+    $kdbx = File::KDBX::Loader->load_handle(*IO, %options);
     $kdbx = File::KDBX::Loader->load_handle(*IO, $key);
-    $kdbx->load_handle(...); # also instance method
 
-Read a KDBX file from an input stream / file handle.
+Read a KDBX file from an input stream / file handle. This works as an instance or class method. Available
+options:
+
+=over 4
+
+=item *
+
+C<key> - Alternative way to specify C<$key>
+
+=back
 
 =head2 read_magic_numbers
 
index 3e1e35e326625dcee2624e5e621f34a174f917ce..7dad5d2582bf0214272f3d5669226162dc7016fe 100644 (file)
@@ -17,7 +17,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Loader';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # 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.900
+version 0.901
 
 =head1 DESCRIPTION
 
index d86b78207bc637e7a520c7768bc354847261ad9a..ddb64a75f6933355a4f8856889b6c76aee6fac5a 100644 (file)
@@ -9,7 +9,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Loader';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # 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.900
+version 0.901
 
 =head1 SYNOPSIS
 
index 8d2047c7c9659cd0652ffc9c2198170697fc9822..6be4090ff2bbc2287b6744a5f56ae802509b35fe 100644 (file)
@@ -27,7 +27,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Loader';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 sub _read_header {
     my $self = shift;
@@ -175,7 +175,7 @@ File::KDBX::Loader::V3 - Load KDBX3 files
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 BUGS
 
index 3cf1a154c7aa24e7b2c355e6bb97afe8f814f9c6..0e33fc9d17a4aecae8f6d83c9cc5eff155ac3be4 100644 (file)
@@ -30,7 +30,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Loader';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 sub _read_header {
     my $self = shift;
@@ -275,7 +275,7 @@ File::KDBX::Loader::V4 - Load KDBX4 files
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 BUGS
 
index 89234b5b0c7a66042ee3d8d2424b265971f3fe92..a0826e9f53466615d3de80b6bb765416e780c5a5 100644 (file)
@@ -18,7 +18,7 @@ use namespace::clean;
 
 extends 'File::KDBX::Loader';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 has '_reader',  is => 'ro';
 has '_safe',    is => 'ro', default => sub { File::KDBX::Safe->new(cipher => $_[0]->kdbx->random_stream) };
@@ -591,7 +591,7 @@ File::KDBX::Loader::XML - Load unencrypted XML KeePass files
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 BUGS
 
index bdf86a8808fe53e5af1228278951fd88bb1992f1..b7b96445e515331337e95011edf64a9b5bf72825 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.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 fieldhashes \my (%KDBX, %PARENT, %TXNS, %REFS, %SIGNALS);
 
@@ -526,7 +526,7 @@ File::KDBX::Object - A KDBX database object
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 DESCRIPTION
 
index ea0c402e58f6558278b3c7a6c995b212e41b73f1..b88b86ce78a805063c32d5164a80c3382c2d7397 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.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 
 sub new {
@@ -110,7 +110,7 @@ sub add_protected {
     @strings or throw 'Must provide strings to lock';
 
     for my $string (@strings) {
-        my $item = {str => $string};
+        my $item = {str => $string, off => $self->{counter}};
         $item->{filter} = $filter if defined $filter;
         if (is_scalarref($string)) {
             next if !defined $$string;
@@ -217,7 +217,7 @@ File::KDBX::Safe - Keep strings encrypted while in memory
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 SYNOPSIS
 
index d33a48f0bb73da87a182c3f99eee50f5ff26e366..86c380f9a25ed85745c5de64f59f6b9ab4aa39ac 100644 (file)
@@ -8,7 +8,7 @@ use Devel::GlobalDestruction;
 use File::KDBX::Util qw(:class);
 use namespace::clean;
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 
 sub new {
@@ -59,7 +59,7 @@ File::KDBX::Transaction - Make multiple database edits atomically
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 ATTRIBUTES
 
index 948cf16e5975284a081727a61fb60f88f6a07883..7223f6a7fe60815cf19bf0130eefc07b1f58220a 100644 (file)
@@ -17,7 +17,7 @@ use Time::Piece;
 use boolean;
 use namespace::clean -except => 'import';
 
-our $VERSION = '0.900'; # VERSION
+our $VERSION = '0.901'; # VERSION
 
 our %EXPORT_TAGS = (
     assert      => [qw(DEBUG assert assert_64bit)],
@@ -803,7 +803,7 @@ File::KDBX::Util - Utility functions for working with KDBX files
 
 =head1 VERSION
 
-version 0.900
+version 0.901
 
 =head1 FUNCTIONS
 
@@ -1054,8 +1054,8 @@ Get either a L</query> or L</simple_expression_query>, depending on the argument
     $size = read_all($fh, my $buffer, $size);
     $size = read_all($fh, my $buffer, $size, $offset);
 
-Like L<functions/read> but returns C<undef> if not all C<$size> bytes are read. This is considered an error,
-distinguishable from other errors by C<$!> not being set.
+Like L<perlfunc/"read FILEHANDLE,SCALAR,LENGTH,OFFSET"> but returns C<undef> if not all C<$size> bytes are
+read. This is considered an error, distinguishable from other errors by C<$!> not being set.
 
 =head2 recurse_limit
 
index d4edfb2662dc81e5624b72d6f44102075f0c3714..8bed335b351ef60e87d4f2d71ae6ff15b7b8de5a 100644 (file)
@@ -9,6 +9,7 @@ use lib "$Bin/lib";
 use TestCommon;
 
 use File::KDBX;
+use File::Temp qw(tempfile);
 use Test::Deep;
 use Test::More;
 use Time::Piece;
@@ -170,4 +171,24 @@ subtest 'Maintenance' => sub {
     is $entry->custom_icon_uuid, $icon_uuid, 'Uses of removed icon change';
 };
 
+subtest 'Dumping to filesystem' => sub {
+    my $kdbx = File::KDBX->new;
+    $kdbx->add_entry(title => 'Foo', password => 'whatever');
+
+    my ($fh, $filepath) = tempfile('kdbx-XXXXXX', TMPDIR => 1, UNLINK => 1);
+    close($fh);
+
+    $kdbx->dump($filepath, 'a');
+
+    my $kdbx2 = File::KDBX->load($filepath, 'a');
+    my $entry = $kdbx2->entries->map(sub { $_->title.'/'.$_->expand_password })->next;
+    is $entry, 'Foo/whatever', 'Dump and load an entry';
+
+    $kdbx->dump($filepath, key => 'a', atomic => 0);
+
+    $kdbx2 = File::KDBX->load($filepath, 'a');
+    $entry = $kdbx2->entries->map(sub { $_->title.'/'.$_->expand_password })->next;
+    is $entry, 'Foo/whatever', 'Dump and load an entry (non-atomic)';
+};
+
 done_testing;
index b42aa235e4d9699bb345da82236952402d711f68..3bf32617e0a15153339f0c9661b7d70677137af5 100644 (file)
@@ -40,9 +40,9 @@ SKIP: {
         $write = File::KDBX::IO::HashBlock->new($write);
         print $write $expected_plaintext;
         close($write) or die "close failed: $!";
-        exit;
-        require POSIX;
-        POSIX::_exit(0);
+        exit;
+        require POSIX;
+        POSIX::_exit(0);
     }
 
     $read = File::KDBX::IO::HashBlock->new($read);
index 87f280913f0b863c1eef8a6ed1fb9441d01b2ea8..035d43319170dc90341d5f31fcf1e88b2d4bae8d 100644 (file)
@@ -44,9 +44,9 @@ SKIP: {
         $write = File::KDBX::IO::HmacBlock->new($write, key => $KEY);
         print $write $expected_plaintext;
         close($write) or die "close failed: $!";
-        exit;
-        require POSIX;
-        POSIX::_exit(0);
+        exit;
+        require POSIX;
+        POSIX::_exit(0);
     }
 
     $read = File::KDBX::IO::HmacBlock->new($read, key => $KEY);
index 5fe53f7b820026fdc60ba1b9cf538bc49f0d6ac4..fac610197039aea31a76d6afc3a6cb6148854d20 100644 (file)
--- a/t/kdbx3.t
+++ b/t/kdbx3.t
@@ -105,10 +105,12 @@ subtest 'Verify ProtectedStrings' => sub {
 
     is $kdbx->meta->{database_name}, 'Protected Strings Test', 'Extract database name from meta';
 
-    $kdbx->unlock;
-
     my $entry = $kdbx->entries->next;
     is $entry->title, 'Sample Entry', 'Get entry title';
+
+    is $entry->string_peek('Password'), 'ProtectedPassword', 'Peek at password from entry';
+    is $entry->string_peek('TestProtected'), 'ABC', 'Peek at protected string from entry';
+    $kdbx->unlock;
     is $entry->username, 'Protected User Name', 'Get protected username from entry';
     is $entry->password, 'ProtectedPassword', 'Get protected password from entry';
     is $entry->string_value('TestProtected'), 'ABC', 'Get ABC string from entry';
index 65658e5a7391af4fb10ff2ca199ac22e5c2aa036..601260c69de981f7299322ee5263ab44afe5bb29 100644 (file)
--- a/t/keys.t
+++ b/t/keys.t
@@ -55,7 +55,8 @@ for my $test (
     subtest "Save $type key file" => sub {
         my ($type, $filename, $expected_key, $version) = @_;
 
-        my ($fh, $filepath) = tempfile('keyfile-XXXXXX', TMPDIR => 1, UNLINK => 1, SUFFIX => '.key');
+        my ($fh, $filepath) = tempfile('keyfile-XXXXXX', TMPDIR => 1, UNLINK => 1);
+        close($fh);
         note $filepath;
         my $key = File::KDBX::Key::File->new(
             filepath    => $filepath,
@@ -65,7 +66,6 @@ for my $test (
         );
 
         my $e = exception { $key->save };
-        close($fh);
 
         if ($type == KEY_FILE_TYPE_HASHED) {
             like $e, qr/invalid type/i, "Cannot save $type file";
@@ -88,7 +88,7 @@ subtest 'IO handle key files' => sub {
         'Can calculate raw key from file handle' or diag encode_b64($key->raw_key);
     is $key->type, 'hashed', 'file type is detected as hashed';
 
-    my ($fh_save, $filepath) = tempfile('keyfile-XXXXXX', TMPDIR => 1, UNLINK => 1, SUFFIX => '.key');
+    my ($fh_save, $filepath) = tempfile('keyfile-XXXXXX', TMPDIR => 1, UNLINK => 1);
     is exception { $key->save(fh => $fh_save, type => KEY_FILE_TYPE_XML) }, undef,
         'Save key file using IO handle';
     close($fh_save);
This page took 0.176909 seconds and 4 git commands to generate.