File Coverage

blib/lib/File/KDBX/Key/Composite.pm
Criterion Covered Total %
statement 59 63 93.6
branch 13 16 81.2
condition 4 8 50.0
subroutine 13 14 92.8
pod 6 6 100.0
total 95 107 88.7


line stmt bran cond sub pod time code
1             package File::KDBX::Key::Composite;
2             # ABSTRACT: A composite key made up of component keys
3              
4 6     6   442 use warnings;
  6         14  
  6         202  
5 6     6   27 use strict;
  6         23  
  6         130  
6              
7 6     6   25 use Crypt::Digest qw(digest_data);
  6         9  
  6         238  
8 6     6   39 use File::KDBX::Error;
  6         22  
  6         259  
9 6     6   50 use File::KDBX::Util qw(:class :erase);
  6         16  
  6         646  
10 6     6   35 use Ref::Util qw(is_arrayref);
  6         8  
  6         246  
11 6     6   34 use Scalar::Util qw(blessed);
  6         10  
  6         231  
12 6     6   31 use namespace::clean;
  6         9  
  6         36  
13              
14             extends 'File::KDBX::Key';
15              
16             our $VERSION = '0.904'; # VERSION
17              
18             sub init {
19 46     46 1 75 my $self = shift;
20 46   33     117 my $primitive = shift // throw 'Missing key primitive';
21              
22 46 100       163 my @primitive = grep { defined } is_arrayref($primitive) ? @$primitive : $primitive;
  85         225  
23 46 50       117 @primitive or throw 'Composite key must have at least one component key', count => scalar @primitive;
24              
25 46         96 my @keys = map { blessed $_ && $_->can('raw_key') ? $_ : File::KDBX::Key->new($_,
26 85 100 66     578 keep_primitive => $self->{keep_primitive}) } @primitive;
27 46         136 $self->{keys} = \@keys;
28              
29 46         144 return $self->hide;
30             }
31              
32              
33             sub raw_key {
34 46     46 1 581 my $self = shift;
35 46         79 my $challenge = shift;
36              
37 46 50       64 my @keys = @{$self->keys} or throw 'Cannot generate a raw key from an empty composite key';
  46         93  
38              
39 46         121 my @basic_keys = map { $_->raw_key } grep { !$_->can('challenge') } @keys;
  67         253  
  85         326  
40 46         96 my $response;
41 46 100       160 $response = $self->challenge($challenge, @_) if defined $challenge;
42 46         170 my $cleanup = erase_scoped \@basic_keys, $response;
43              
44 46 100       813 return digest_data('SHA256',
45             @basic_keys,
46             defined $response ? $response : (),
47             );
48             }
49              
50              
51             sub keys {
52 173     173 1 263 my $self = shift;
53 173 50       321 $self->{keys} = shift if @_;
54 173   50     662 return $self->{keys} ||= [];
55             }
56              
57              
58             sub challenge {
59 45     45 1 89 my $self = shift;
60              
61 45 100       79 my @chalresp_keys = grep { $_->can('challenge') } @{$self->keys} or return '';
  81         357  
  45         137  
62              
63 18         44 my @responses = map { $_->challenge(@_) } @chalresp_keys;
  18         54  
64 18         116 my $cleanup = erase_scoped \@responses;
65              
66 18         364 return digest_data('SHA256', @responses);
67             }
68              
69             sub hide {
70 82     82 1 128 my $self = shift;
71 82         104 $_->hide for @{$self->keys};
  82         188  
72 82         420 return $self;
73             }
74              
75             sub show {
76 0     0 1   my $self = shift;
77 0           $_->show for @{$self->keys};
  0            
78 0           return $self;
79             }
80              
81             1;
82              
83             __END__