File Coverage

lib/Haineko/CLI/Password.pm
Criterion Covered Total %
statement 66 100 66.0
branch 14 30 46.6
condition 10 15 66.6
subroutine 11 12 91.6
pod 4 5 80.0
total 105 162 64.8


line stmt bran cond sub pod time code
1             package Haineko::CLI::Password;
2 1     1   3111 use parent 'Haineko::CLI';
  1         350  
  1         5  
3 1     1   34 use strict;
  1         2  
  1         31  
4 1     1   5 use warnings;
  1         2  
  1         18  
5 1     1   4 use Try::Tiny;
  1         2  
  1         640  
6              
7             sub options {
8             return {
9 4     4 0 2205 'exec' => ( 1 << 0 ),
10             'stdin'=> ( 1 << 1 ),
11             };
12             }
13              
14             sub make {
15 2     2 1 5 my $self = shift;
16 2         14 my $o = __PACKAGE__->options;
17              
18 2 50       7 return undef unless( $self->r & $o->{'exec'} );
19 2         6 my $password01 = undef;
20 2         6 my $password02 = undef;
21 2         2 my $filehandle = undef;
22              
23             try {
24 2     2   1769 require Crypt::SaltedHash;
25             } catch {
26 0     0   0 $self->e( 'Cannot load "Crypt::SaltedHash"' );
27 2         21 };
28              
29 2 50       5034 if( $self->r & $o->{'stdin'} ) {
30             # Read a password from STDIN
31 0         0 require IO::Handle;
32 0         0 $filehandle = IO::Handle->new;
33 0 0       0 $self->e( 'Cannot open STDIN' ) unless $filehandle->fdopen( fileno(STDIN), 'r' );
34              
35 0         0 system('stty -echo');
36 0         0 while(1) {
37             # Password(1)
38 0         0 printf( STDERR 'New password: ' );
39 0         0 while( my $p = $filehandle->gets ) {
40 0         0 $password01 = $p;
41 0 0       0 last if length $password01;
42             }
43 0         0 printf( STDERR "\n" );
44 0         0 chomp $password01;
45 0 0       0 last if $self->validate( $password01 );
46             }
47              
48 0         0 while(1) {
49             # Password(2)
50 0         0 printf( STDERR 'Re-type new password: ' );
51 0         0 while( my $p = $filehandle->gets ) {
52 0         0 $password02 = $p;
53 0 0       0 last if length $password02;
54             }
55 0         0 printf( STDERR "\n" );
56 0         0 chomp $password02;
57 0 0       0 last if $password01 eq $password02;
58 0         0 $self->e( 'Passwords dit not match', 1 );
59             }
60 0         0 system('stty echo');
61              
62             } else {
63             # Password string is in the argument of -p option
64 2         8 $password01 = $self->{'params'}->{'password'};
65 2         9 $self->validate( $password01 );
66             }
67              
68 2         4 my $methodargv = undef;
69 2         3 my $saltedhash = undef;
70 2         4 my $passwdhash = undef;
71 2         3 my $credential = undef;
72              
73 2         11 $methodargv = { 'algorithm' => $self->{'params'}->{'algorithm'} };
74 2         17 $saltedhash = Crypt::SaltedHash->new( %$methodargv );
75 2         5539 $saltedhash->add( $password01 );
76 2         30 $passwdhash = $saltedhash->generate;
77              
78 2 100       148 if( length $self->{'params'}->{'username'} ) {
79 1         8 $credential = sprintf( "%s: '%s'", $self->{'params'}->{'username'}, $passwdhash );
80             } else {
81 1         2 $credential = $passwdhash;
82             }
83 2         15 return $credential;
84             }
85              
86             sub validate {
87 2     2 1 5 my $self = shift;
88 2         6 my $argv = shift;
89              
90 2 50       12 if( not length $argv ) {
    50          
91 0         0 $self->e( 'Empty password is not permitted', 1 );
92             } elsif( length $argv < 8 ) {
93 0         0 $self->e( 'Password is too short < 8', 1 );
94             } else {
95 2         6 return 1;
96             }
97              
98 0         0 return 0;
99             }
100              
101             sub parseoptions {
102 1     1 1 378 my $self = shift;
103 1         5 my $opts = __PACKAGE__->options;
104              
105 1         2 my $r = 0; # Run mode value
106 1         2 my $p = {}; # Parsed options
107              
108 1     1   1226 use Getopt::Long qw/:config posix_default no_ignore_case bundling auto_help/;
  1         10800  
  1         6  
109 1         6 Getopt::Long::GetOptions( $p,
110             'algorithm|a=s',# Algorithm
111             'help', # --help
112             'password|p=s', # Password string
113             'user|u=s', # Username
114             'verbose|v+', # Verbose
115             );
116              
117 1 50       403 if( $p->{'help'} ) {
118             # --help
119 0         0 require Haineko::CLI::Help;
120 0         0 my $o = Haineko::CLI::Help->new( 'command' => [ caller ]->[1] );
121 0         0 $o->add( __PACKAGE__->help('s'), 'subcommand' );
122 0         0 $o->add( __PACKAGE__->help('o'), 'option' );
123 0         0 $o->add( __PACKAGE__->help('e'), 'example' );
124 0         0 $o->mesg;
125 0         0 exit(0);
126             }
127              
128 1 50       4 if( defined $p->{'password'} ) {
129             # Password string
130 0         0 $self->{'params'}->{'password'} = $p->{'password'};
131              
132             } else {
133             # Read a password from STDIN
134 1         2 $r |= $opts->{'stdin'};
135             }
136 1   50     13 $self->{'params'}->{'username'} = $p->{'user'} // q();
137 1   50     8 $self->{'params'}->{'algorithm'} = $p->{'algorithm'} // 'SHA-1';
138              
139 1         7 $self->v( $p->{'verbose'} );
140 1         3 $r |= $opts->{'exec'};
141 1         5 $self->r( $r );
142 1         7 return $r;
143             }
144              
145             sub help {
146 4     4 1 2600 my $class = shift;
147 4   100     19 my $argvs = shift || q();
148              
149 4         17 my $commoption = [
150             '-a, --algorithm ' => 'Algorithm, if it omitted "SHA-1" will be used.',
151             '-p, --password ' => 'Password string',
152             '-u, --user ' => 'Username for Basic-Authentication',
153             '-v, --verbose' => 'Verbose mode.',
154             '--help' => 'This screen',
155             ];
156 4         8 my $subcommand = [ 'pw' => 'Generate a new password for Basic-Authentication' ];
157 4         10 my $forexample = [
158             'hainekoctl pw',
159             'hainekoctl pw -u username -p newpassword',
160             ];
161              
162 4 100 66     31 return $commoption if $argvs eq 'o' || $argvs eq 'option';
163 3 100 66     22 return $subcommand if $argvs eq 's' || $argvs eq 'subcommand';
164 2 100 66     19 return $forexample if $argvs eq 'e' || $argvs eq 'example';
165 1         6 return undef;
166             }
167              
168             1;
169             __END__