File Coverage

blib/lib/File/KDBX/Key.pm
Criterion Covered Total %
statement 74 88 84.0
branch 20 34 58.8
condition 5 21 23.8
subroutine 21 23 91.3
pod 7 7 100.0
total 127 173 73.4


line stmt bran cond sub pod time code
1             package File::KDBX::Key;
2             # ABSTRACT: A credential that can protect a KDBX file
3              
4 8     8   196646 use warnings;
  8         20  
  8         218  
5 8     8   41 use strict;
  8         17  
  8         131  
6              
7 8     8   1076 use Devel::GlobalDestruction;
  8         1450  
  8         38  
8 8     8   412 use File::KDBX::Error;
  8         13  
  8         282  
9 8     8   1101 use File::KDBX::Safe;
  8         13  
  8         246  
10 8     8   42 use File::KDBX::Util qw(erase);
  8         12  
  8         286  
11 8     8   1434 use Hash::Util::FieldHash qw(fieldhashes);
  8         2364  
  8         353  
12 8     8   43 use Module::Load;
  8         14  
  8         63  
13 8     8   422 use Ref::Util qw(is_arrayref is_coderef is_hashref is_ref is_scalarref);
  8         21  
  8         414  
14 8     8   40 use Scalar::Util qw(blessed openhandle);
  8         21  
  8         314  
15 8     8   40 use namespace::clean;
  8         14  
  8         35  
16              
17             our $VERSION = '0.906'; # VERSION
18              
19             fieldhashes \my %SAFE;
20              
21              
22             sub new {
23 193     193 1 41903 my $class = shift;
24 193 100       819 my %args = @_ % 2 == 1 ? (primitive => shift, @_) : @_;
25              
26 193         332 my $primitive = $args{primitive};
27 193 50       461 delete $args{primitive} if !$args{keep_primitive};
28 193 100 66     764 return $primitive->hide if blessed $primitive && $primitive->isa($class);
29              
30 157         283 my $self = bless \%args, $class;
31 157 100       454 return $self->init($primitive) if defined $primitive;
32 13         40 return $self;
33             }
34              
35             sub DESTROY {
36 157     157   17632 local ($., $@, $!, $^E, $?);
37 157 50       3045 !in_global_destruction and do { $_[0]->_clear_raw_key; eval { erase \$_[0]->{primitive} } }
  157         1057  
  157         296  
  157         384  
38             }
39              
40              
41             sub init {
42 85     85 1 167 my $self = shift;
43 85   33     173 my $primitive = shift // throw 'Missing key primitive';
44              
45 85         95 my $pkg;
46              
47 85 100 66     454 if (is_arrayref($primitive)) {
    100 0        
    100 0        
    50 0        
    0 0        
    0          
    0          
    0          
48 1         2 $pkg = __PACKAGE__.'::Composite';
49             }
50             elsif (is_scalarref($primitive) || openhandle($primitive)) {
51 19         45 $pkg = __PACKAGE__.'::File';
52             }
53             elsif (is_coderef($primitive)) {
54 18         39 $pkg = __PACKAGE__.'::ChallengeResponse';
55             }
56             elsif (!is_ref($primitive)) {
57 47         88 $pkg = __PACKAGE__.'::Password';
58             }
59             elsif (is_hashref($primitive) && defined $primitive->{composite}) {
60 0         0 $pkg = __PACKAGE__.'::Composite';
61 0         0 $primitive = $primitive->{composite};
62             }
63             elsif (is_hashref($primitive) && defined $primitive->{password}) {
64 0         0 $pkg = __PACKAGE__.'::Password';
65 0         0 $primitive = $primitive->{password};
66             }
67             elsif (is_hashref($primitive) && defined $primitive->{file}) {
68 0         0 $pkg = __PACKAGE__.'::File';
69 0         0 $primitive = $primitive->{file};
70             }
71             elsif (is_hashref($primitive) && defined $primitive->{responder}) {
72 0         0 $pkg = __PACKAGE__.'::ChallengeResponse';
73 0         0 $primitive = $primitive->{responder};
74             }
75             else {
76 0         0 throw 'Invalid key primitive', primitive => $primitive;
77             }
78              
79 85         228 load $pkg;
80 85         4069 bless $self, $pkg;
81 85         372 return $self->init($primitive);
82             }
83              
84              
85 0     0 1 0 sub reload { $_[0] }
86              
87              
88             sub raw_key {
89 95     95 1 1413 my $self = shift;
90 95 100       215 return $self->{raw_key} if !$self->is_hidden;
91 86         188 return $self->_safe->peek(\$self->{raw_key});
92             }
93              
94             sub _set_raw_key {
95 81     81   3267 my $self = shift;
96 81         200 $self->_clear_raw_key;
97 81         151 $self->{raw_key} = shift; # after clear
98 81         187 $self->_new_safe->add(\$self->{raw_key}); # auto-hide
99             }
100              
101             sub _clear_raw_key {
102 238     238   327 my $self = shift;
103 238         459 my $safe = $self->_safe;
104 238 100       627 $safe->clear if $safe;
105 238         760 erase \$self->{raw_key};
106             }
107              
108              
109             sub hide {
110 256     256 1 322 my $self = shift;
111 256 50       443 $self->_new_safe->add(\$self->{raw_key}) if defined $self->{raw_key};
112 256         735 return $self;
113             }
114              
115              
116             sub show {
117 0     0 1 0 my $self = shift;
118 0         0 my $safe = $self->_safe;
119 0 0       0 $safe->unlock if $safe;
120 0         0 return $self;
121             }
122              
123              
124 95     95 1 373 sub is_hidden { !!$SAFE{$_[0]} }
125              
126 324     324   1011 sub _safe { $SAFE{$_[0]} }
127 81     81   393 sub _new_safe { $SAFE{$_[0]} = File::KDBX::Safe->new }
128              
129             1;
130              
131             __END__