File Coverage

blib/lib/PasswordMonkey.pm
Criterion Covered Total %
statement 121 136 88.9
branch 30 48 62.5
condition 3 6 50.0
subroutine 16 16 100.0
pod 4 5 80.0
total 174 211 82.4


line stmt bran cond sub pod time code
1             ###########################################
2             package PasswordMonkey;
3             ###########################################
4 11     11   201667 use strict;
  11         23  
  11         415  
5 11     11   57 use warnings;
  11         19  
  11         314  
6 11     11   16692 use Expect qw(exp_continue);
  11         605659  
  11         891  
7 11     11   15580 use Log::Log4perl qw(:easy);
  11         659391  
  11         116  
8 11     11   15587 use Module::Pluggable require => 1;
  11         116585  
  11         77  
9              
10             our $VERSION = "0.09";
11             our $PACKAGE = __PACKAGE__;
12              
13             our $PASSWORD_MONKEY_OK = 1;
14             our $PASSWORD_MONKEY_TIMEOUT = 2;
15              
16             __PACKAGE__->make_accessor( $_ ) for qw(
17             expect
18             fills
19             is_success
20             timed_out
21             exit_status
22             );
23              
24             ###########################################
25             sub new {
26             ###########################################
27 15     15 1 3544 my($class, %options) = @_;
28              
29 15         177 my $self = {
30             expect => Expect->new(),
31             timeout => 60,
32             fillers => [],
33             filler_report => [],
34             %options,
35             };
36              
37 15         20596 bless $self, $class;
38             }
39              
40             ###########################################
41             sub filler_add {
42             ###########################################
43 14     14 1 751 my($self, $filler) = @_;
44              
45 14 50 33     477 if( ! defined ref $filler or
46             ! ref($filler) =~ /^$PACKAGE/ ) {
47 0         0 LOGDIE "filler_add expects a filler object";
48             }
49              
50 14         36 push @{ $self->{fillers} }, $filler;
  14         76  
51             }
52              
53             ###########################################
54             sub spawn {
55             ###########################################
56 15     15 1 123 my($self, $command, @parameters) = @_;
57              
58 15         135 DEBUG "Spawning $command @parameters";
59              
60 15 50       297 $self->{expect}->spawn($command, @parameters)
61             or die "Cannot spawn $command: $!\n";
62             }
63              
64             ###########################################
65             sub go {
66             ###########################################
67 15     15 1 93939 my($self) = @_;
68              
69 15         540 DEBUG "Monkey starts";
70              
71 15         402 my @regex_callbacks = ();
72              
73 15         151 $self->{fills} = 0;
74 15         162 $self->{is_success} = 1;
75 15         135 $self->{timed_out} = 0;
76 15         184 $self->{eof} = 0;
77              
78 15         55 for my $filler ( @{ $self->{ fillers } } ) {
  15         163  
79 14         685 $filler->init();
80             push @regex_callbacks, [
81             $filler->prompt(),
82             sub {
83 16     16   2297967 DEBUG "Running filler '", $filler->name(), "'";
84 16         377 for my $bouncer ( $filler->bouncers() ) {
85             # configure the bouncer object with
86             # the expect engine
87 11         202 $bouncer->init();
88 11         571 DEBUG "Running bouncer '", $bouncer->name(), "'\n";
89 11         555 $bouncer->expect( $self->{expect} );
90 11 100       118 if( $bouncer->check() ) {
91 8         1117 DEBUG "Bouncer [", $bouncer->name(),
92             "] check succeeded";
93             } else {
94 3         115 ERROR "Bouncer [", $bouncer->name(),
95             "] check failed";
96             # continue without filling
97 3         32 return exp_continue;
98             }
99             }
100 13         262 $filler->pre_fill( @_ );
101 13         288 $filler->fill( @_ );
102 13         127 $filler->post_fill( @_ );
103              
104             # reporting
105 13         133 push @{ $self->{filler_report} },
  13         1043  
106             [ $self->expect->match, $filler->password ];
107            
108 13         53 $self->{fills}++;
109 13         64 return exp_continue;
110 14         1193 }, $self];
111              
112 14         176 for my $dealbreaker ( @{ $filler->dealbreakers() } ) {
  14         2006  
113 1         4 my($pattern, $exit_code) = @$dealbreaker;
114             push @regex_callbacks,
115             [ $pattern, sub {
116 1     1   29923 DEBUG "Encountered dealbreaker [$pattern], exiting";
117 1         16 $self->{exit_status} = ($exit_code << 8);
118 1         5 $self->{is_success} = 0;
119             # no exp_continue
120 1         26 }];
121             }
122             }
123              
124             push @regex_callbacks,
125             [ "eof" => sub {
126 13     13   5023280 DEBUG "Received 'eof'.";
127 13         210 $self->{eof} = 1;
128 13         52 return 0;
129             }, $self
130             ],
131             [ "timeout" => sub {
132 1     1   1026661 ERROR "Received 'timeout'.";
133 1         18 $self->{ is_success } = 0;
134 1         4 $self->{ timed_out } = 1;
135 1         4 return 0;
136 15         436 }, $self
137             ],
138             ;
139              
140 15         510 my @expect_return =
141             $self->{expect}->expect( $self->{timeout}, @regex_callbacks );
142              
143 15         4189 for ( qw(matched_pattern_position
144             error
145             successfully_matching_string
146             before_match
147             after_match) ) {
148 75         551 $self->{expect_return}->{$_} = shift @expect_return;
149             }
150              
151             # Expect.pm sets the exit status *after* calling the 'eof' hook
152             # defined above, so we need to do some post processing here.
153 15 100       204 if( $self->{eof} ) {
154 13         276 $self->{exit_status} = $self->{expect}->exitstatus();
155 13 50       678 if( defined $self->{exit_status} ) {
156 13         108 DEBUG "Exit status is $self->{exit_status}";
157             } else {
158 0         0 DEBUG "Exit status undefined";
159             }
160 13 100 66     414 if( !defined $self->{exit_status} or
161             $self->{exit_status} != 0 ) {
162 2         8 $self->{ is_success } = 0;
163             }
164             }
165              
166 15         114 DEBUG "Monkey stops (success=$self->{is_success})";
167 15         507 return $self->{is_success};
168             }
169              
170             ##################################################
171             # Poor man's Class::Struct
172             ##################################################
173             sub make_accessor {
174             ##################################################
175 100     100 0 172 my($package, $name) = @_;
176              
177 11     11   10757 no strict qw(refs);
  11         24  
  11         1416  
178              
179 100         324 my $code = <
180             *{"$package\\::$name"} = sub {
181             my(\$self, \$value) = \@_;
182              
183             if(defined \$value) {
184             \$self->{$name} = \$value;
185             }
186             if(exists \$self->{$name}) {
187             return (\$self->{$name});
188             } else {
189             return "";
190             }
191             }
192             EOT
193 100 50       114 if(! defined *{"$package\::$name"}) {
  100         565  
194 100 50   6   11431 eval $code or die "$@";
  6 50       1272  
  6 50       51  
  0 50       0  
  6 50       28  
  6 100       47  
  0 50       0  
  21 50       114  
  21 50       99  
  0 50       0  
  21 50       94  
  21 100       182  
  0 50       0  
  16 100       221  
  16 50       107  
  8 50       27  
  16 50       110  
  16         288  
  0         0  
  9         5050  
  9         254  
  0         0  
  9         57  
  9         79  
  0         0  
  8         3534  
  8         48  
  0         0  
  8         92  
  8         115  
  0         0  
  9         450  
  9         42  
  1         13  
  9         50  
  9         68  
  0         0  
  18         234  
  18         103  
  1         3  
  18         137  
  18         196  
  0         0  
  14         66  
  14         83  
  0         0  
  14         119  
  14         159  
  0         0  
195             }
196             }
197              
198             1;
199              
200             __END__