File Coverage

blib/lib/App/diceware.pm
Criterion Covered Total %
statement 67 67 100.0
branch 4 6 66.6
condition 6 6 100.0
subroutine 17 17 100.0
pod 0 2 0.0
total 94 98 95.9


line stmt bran cond sub pod time code
1             package App::diceware;
2              
3 2     2   153485 use strict;
  2         12  
  2         53  
4 2     2   7 use warnings;
  2         4  
  2         72  
5              
6             our $VERSION = '0.01';
7              
8 2     2   672 use File::Share ':all';
  2         12159  
  2         265  
9 2     2   692 use Crypt::Rijndael;
  2         679  
  2         47  
10 2     2   809 use Crypt::URandom;
  2         8642  
  2         73  
11 2     2   685 use Data::Entropy qw(with_entropy_source);
  2         6420  
  2         105  
12 2     2   795 use Data::Entropy::Algorithms qw(rand_int);
  2         17157  
  2         119  
13 2     2   777 use Data::Entropy::RawSource::CryptCounter;
  2         3536  
  2         47  
14 2     2   804 use Data::Entropy::Source;
  2         2393  
  2         833  
15              
16             sub new {
17 2     2 0 3091 my ($class, $arg_ref) = @_;
18 2   100     14 my $self = $arg_ref // {};
19 2         6 bless $self, $class;
20 2         7 $self->_init();
21 2         10 return $self;
22             }
23              
24             sub _dice {
25 60     60   70 my ($self) = shift;
26             my $dice = with_entropy_source(
27             $self->{entropy},
28             sub {
29 60     60   265 rand_int(6) + 1;
30             }
31 60         156 );
32 60         3472 return $dice;
33             }
34              
35             sub _init {
36 2     2   4 my ($self) = shift;
37 2   100     11 $self->{language} //= 'en';
38 2         8 $self->{wordlist} = $self->_load_wordlist();
39 2         14 $self->{entropy} = $self->_build_entropy();
40 2         9662 return;
41             }
42              
43             sub _load_wordlist {
44 2     2   4 my ($self) = shift;
45 2 50       14 die "language not supported" unless $self->{language} =~ m/^(de|en)$/xms;
46 2         12 my $file = dist_file('App-diceware', "wordlist_$self->{language}.tsv");
47 1 50   1   6 open(my $fh, '<:encoding(UTF-8)', $file)
  1         9  
  1         5  
  2         480  
48             or die "Couldn't open '$file': $!";
49 2         9472 my $wordlist;
50 2         373 while (my $line = <$fh>) {
51 15552         19318 chomp $line;
52 15552         29215 my ($key, $value) = split /\t/, $line, 2;
53 15552         41525 $wordlist->{$key} = $value;
54             }
55 2         53 return $wordlist;
56             }
57              
58             sub passphrase {
59 3     3 0 2659 my ($self, $arg_ref) = @_;
60 3   100     13 my $length = $arg_ref->{length} // 5;
61 3         5 my @passwords;
62 3         8 for (my $i = 0; $i < $length; $i++) {
63 12         12 my $key;
64 12         20 for (0 .. 4) {
65 60         80 $key .= $self->_dice();
66             }
67 12         48 push @passwords, $self->{wordlist}->{$key};
68             }
69 3 100       7 if ($arg_ref->{pretty}) {
70 2         23 return join '-', @passwords;
71             }
72 1         11 return join '', @passwords;
73             }
74              
75             sub _build_entropy {
76 2     2   4 my $self = shift;
77 2         10 return Data::Entropy::Source->new(
78             Data::Entropy::RawSource::CryptCounter->new(
79             Crypt::Rijndael->new(Crypt::URandom::urandom(32))
80             ),
81             "getc"
82             );
83             }
84              
85             1;
86             __END__