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   193960 use warnings;
  8         17  
  8         255  
5 8     8   36 use strict;
  8         19  
  8         145  
6              
7 8     8   1078 use Devel::GlobalDestruction;
  8         1429  
  8         35  
8 8     8   400 use File::KDBX::Error;
  8         15  
  8         278  
9 8     8   1079 use File::KDBX::Safe;
  8         19  
  8         244  
10 8     8   43 use File::KDBX::Util qw(erase);
  8         12  
  8         305  
11 8     8   1464 use Hash::Util::FieldHash qw(fieldhashes);
  8         2190  
  8         332  
12 8     8   47 use Module::Load;
  8         12  
  8         51  
13 8     8   417 use Ref::Util qw(is_arrayref is_coderef is_hashref is_ref is_scalarref);
  8         15  
  8         381  
14 8     8   51 use Scalar::Util qw(blessed openhandle);
  8         18  
  8         307  
15 8     8   37 use namespace::clean;
  8         15  
  8         44  
16              
17             our $VERSION = '0.904'; # VERSION
18              
19             fieldhashes \my %SAFE;
20              
21              
22             sub new {
23 193     193 1 40595 my $class = shift;
24 193 100       861 my %args = @_ % 2 == 1 ? (primitive => shift, @_) : @_;
25              
26 193         348 my $primitive = $args{primitive};
27 193 50       440 delete $args{primitive} if !$args{keep_primitive};
28 193 100 66     731 return $primitive->hide if blessed $primitive && $primitive->isa($class);
29              
30 157         308 my $self = bless \%args, $class;
31 157 100       507 return $self->init($primitive) if defined $primitive;
32 13         43 return $self;
33             }
34              
35             sub DESTROY {
36 157     157   20402 local ($., $@, $!, $^E, $?);
37 157 50       3072 !in_global_destruction and do { $_[0]->_clear_raw_key; eval { erase \$_[0]->{primitive} } }
  157         1079  
  157         292  
  157         444  
38             }
39              
40              
41             sub init {
42 85     85 1 129 my $self = shift;
43 85   33     215 my $primitive = shift // throw 'Missing key primitive';
44              
45 85         119 my $pkg;
46              
47 85 100 66     534 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         41 $pkg = __PACKAGE__.'::File';
52             }
53             elsif (is_coderef($primitive)) {
54 18         34 $pkg = __PACKAGE__.'::ChallengeResponse';
55             }
56             elsif (!is_ref($primitive)) {
57 47         104 $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         247 load $pkg;
80 85         4577 bless $self, $pkg;
81 85         368 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 1348 my $self = shift;
90 95 100       219 return $self->{raw_key} if !$self->is_hidden;
91 86         197 return $self->_safe->peek(\$self->{raw_key});
92             }
93              
94             sub _set_raw_key {
95 81     81   3680 my $self = shift;
96 81         260 $self->_clear_raw_key;
97 81         177 $self->{raw_key} = shift; # after clear
98 81         211 $self->_new_safe->add(\$self->{raw_key}); # auto-hide
99             }
100              
101             sub _clear_raw_key {
102 238     238   343 my $self = shift;
103 238         504 my $safe = $self->_safe;
104 238 100       619 $safe->clear if $safe;
105 238         814 erase \$self->{raw_key};
106             }
107              
108              
109             sub hide {
110 256     256 1 397 my $self = shift;
111 256 50       491 $self->_new_safe->add(\$self->{raw_key}) if defined $self->{raw_key};
112 256         713 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 381 sub is_hidden { !!$SAFE{$_[0]} }
125              
126 324     324   1004 sub _safe { $SAFE{$_[0]} }
127 81     81   424 sub _new_safe { $SAFE{$_[0]} = File::KDBX::Safe->new }
128              
129             1;
130              
131             __END__