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   199083 use warnings;
  8         19  
  8         233  
5 8     8   41 use strict;
  8         15  
  8         142  
6              
7 8     8   1067 use Devel::GlobalDestruction;
  8         1508  
  8         38  
8 8     8   406 use File::KDBX::Error;
  8         14  
  8         326  
9 8     8   1141 use File::KDBX::Safe;
  8         15  
  8         280  
10 8     8   41 use File::KDBX::Util qw(erase);
  8         14  
  8         321  
11 8     8   1593 use Hash::Util::FieldHash qw(fieldhashes);
  8         2398  
  8         359  
12 8     8   45 use Module::Load;
  8         14  
  8         53  
13 8     8   399 use Ref::Util qw(is_arrayref is_coderef is_hashref is_ref is_scalarref);
  8         17  
  8         470  
14 8     8   51 use Scalar::Util qw(blessed openhandle);
  8         14  
  8         309  
15 8     8   50 use namespace::clean;
  8         14  
  8         53  
16              
17             our $VERSION = '0.905'; # VERSION
18              
19             fieldhashes \my %SAFE;
20              
21              
22             sub new {
23 193     193 1 46404 my $class = shift;
24 193 100       834 my %args = @_ % 2 == 1 ? (primitive => shift, @_) : @_;
25              
26 193         320 my $primitive = $args{primitive};
27 193 50       439 delete $args{primitive} if !$args{keep_primitive};
28 193 100 66     689 return $primitive->hide if blessed $primitive && $primitive->isa($class);
29              
30 157         295 my $self = bless \%args, $class;
31 157 100       437 return $self->init($primitive) if defined $primitive;
32 13         42 return $self;
33             }
34              
35             sub DESTROY {
36 157     157   17934 local ($., $@, $!, $^E, $?);
37 157 50       3102 !in_global_destruction and do { $_[0]->_clear_raw_key; eval { erase \$_[0]->{primitive} } }
  157         1071  
  157         264  
  157         447  
38             }
39              
40              
41             sub init {
42 85     85 1 121 my $self = shift;
43 85   33     173 my $primitive = shift // throw 'Missing key primitive';
44              
45 85         105 my $pkg;
46              
47 85 100 66     391 if (is_arrayref($primitive)) {
    100 0        
    100 0        
    50 0        
    0 0        
    0          
    0          
    0          
48 1         3 $pkg = __PACKAGE__.'::Composite';
49             }
50             elsif (is_scalarref($primitive) || openhandle($primitive)) {
51 19         30 $pkg = __PACKAGE__.'::File';
52             }
53             elsif (is_coderef($primitive)) {
54 18         30 $pkg = __PACKAGE__.'::ChallengeResponse';
55             }
56             elsif (!is_ref($primitive)) {
57 47         87 $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         3956 bless $self, $pkg;
81 85         250 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 1289 my $self = shift;
90 95 100       199 return $self->{raw_key} if !$self->is_hidden;
91 86         175 return $self->_safe->peek(\$self->{raw_key});
92             }
93              
94             sub _set_raw_key {
95 81     81   2977 my $self = shift;
96 81         200 $self->_clear_raw_key;
97 81         148 $self->{raw_key} = shift; # after clear
98 81         172 $self->_new_safe->add(\$self->{raw_key}); # auto-hide
99             }
100              
101             sub _clear_raw_key {
102 238     238   318 my $self = shift;
103 238         451 my $safe = $self->_safe;
104 238 100       623 $safe->clear if $safe;
105 238         844 erase \$self->{raw_key};
106             }
107              
108              
109             sub hide {
110 256     256 1 348 my $self = shift;
111 256 50       457 $self->_new_safe->add(\$self->{raw_key}) if defined $self->{raw_key};
112 256         744 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 397 sub is_hidden { !!$SAFE{$_[0]} }
125              
126 324     324   962 sub _safe { $SAFE{$_[0]} }
127 81     81   381 sub _new_safe { $SAFE{$_[0]} = File::KDBX::Safe->new }
128              
129             1;
130              
131             __END__