File-KDBX

 view release on metacpan or  search on metacpan

lib/File/KDBX/Safe.pm  view on Meta::CPAN

package File::KDBX::Safe;
# ABSTRACT: Keep strings encrypted while in memory

use warnings;
use strict;

use Crypt::PRNG qw(random_bytes);
use Devel::GlobalDestruction;
use Encode qw(encode decode);
use File::KDBX::Constants qw(:random_stream);
use File::KDBX::Error;
use File::KDBX::Util qw(erase erase_scoped);
use Ref::Util qw(is_arrayref is_coderef is_hashref is_scalarref);
use Scalar::Util qw(refaddr);
use namespace::clean;

our $VERSION = '0.906'; # VERSION


sub new {
    my $class = shift;
    my %args = @_ % 2 == 0 ? @_ : (strings => shift, @_);

    if (!$args{cipher} && $args{key}) {
        require File::KDBX::Cipher;
        $args{cipher} = File::KDBX::Cipher->new(stream_id => STREAM_ID_CHACHA20, key => $args{key});
    }

    my $self = bless \%args, $class;
    $self->cipher->finish;
    $self->{counter} = 0;

    my $strings = delete $args{strings};
    $self->{items} = [];
    $self->{index} = {};
    $self->add($strings) if $strings;

    return $self;
}

sub DESTROY { local ($., $@, $!, $^E, $?); !in_global_destruction and $_[0]->unlock }


sub clear {
    my $self = shift;
    $self->{items} = [];
    $self->{index} = {};
    $self->{counter} = 0;
    return $self;
}


sub lock { shift->add(@_) }

sub add {
    my $self    = shift;
    my @strings = map { is_arrayref($_) ? @$_ : $_ } @_;

    @strings or throw 'Must provide strings to lock';

    my $cipher = $self->cipher;

    for my $string (@strings) {
        my $item = {str => $string, off => $self->{counter}};
        if (is_scalarref($string)) {
            next if !defined $$string;
            $item->{enc} = 'UTF-8' if utf8::is_utf8($$string);
            if (my $encoding = $item->{enc}) {
                my $encoded = encode($encoding, $$string);
                $item->{val} = $cipher->crypt(\$encoded);
                erase $encoded;
            }
            else {



( run in 0.794 second using v1.01-cache-2.11-cpan-39bf76dae61 )