File Coverage

blib/lib/HTML/Widget/Constraint/ComplexPassword.pm
Criterion Covered Total %
statement 12 28 42.8
branch 0 14 0.0
condition 0 6 0.0
subroutine 4 5 80.0
pod n/a
total 16 53 30.1


line stmt bran cond sub pod time code
1             package HTML::Widget::Constraint::ComplexPassword;
2              
3             =head1 NAME
4              
5             HTML::Widget::Constraint::ComplexPassword - HTML::Widget form constraint that checks if the field is a complex password.
6              
7             =head1 SYNOPSIS
8              
9             use HTML::Widget;
10            
11             my $widget = HTML::Widget->new('widget')->method('get')->action('/');
12            
13             ...
14            
15             #constraints
16             $widget->constraint('Length' => @columns)
17             ->min($HTML::Widget::Constraint::ComplexPassword::MIN_LENGTH)
18             ->message('Must be at least '.$HTML::Widget::Constraint::ComplexPassword::MIN_LENGTH.' characters long');
19             $widget->constraint('ComplexPassword' => @columns)
20             ->message(qq{
21             Must contain at least one upper and one lower case character.
22             Must contain at least one number or a special character -
23             "$HTML::Widget::Constraint::ComplexPassword::SPECIAL_CHARACTERS"
24             )};
25            
26             #or this will be enought but then the error text is too long
27             $widget->constraint(ComplexPassword => @columns)
28             ->message(qq{
29             Must contain at least $HTML::Widget::Constraint::ComplexPassword::MIN_LENGTH characters and include
30             one upper and one lower case character. Must contain at least one number or a
31             special character - "$HTML::Widget::Constraint::ComplexPassword::SPECIAL_CHARACTERS"
32             });
33              
34             =head1 DESCRIPTION
35              
36             A constraint for L to check if the password is complex enought. Password must have
37             at least MIN_LENGTH characters count, one lower case character is required, one upper case character
38             is required and either number or one of SPECIAL_CHARACTERS is needed.
39              
40             =head2 EXPORTS
41              
42             our $MIN_LENGTH = 8;
43             our $NUMBER_CHARACTERS = '0123456789';
44             our $SPECIAL_CHARACTERS = '~`!@#$%^&*()-_+={}[]\\|:;"\'<>,.?/';
45              
46             =head2 TIPS
47              
48             If you want to force different password lenght then do:
49              
50             use HTML::Widget::Constraint::ComplexPassword;
51             $HTML::Widget::Constraint::ComplexPassword::MIN_LENGTH = 10;
52              
53             or
54              
55             $widget->constraint(ComplexPassword => @columns)
56             ->min_length(10)
57             ->message("bla bla");
58              
59             If you want just numbers and no other special characters then remove characters from the
60             SPECIAL_CHARACTERS list:
61              
62             use HTML::Widget::Constraint::ComplexPassword;
63             $HTML::Widget::Constraint::ComplexPassword::SPECIAL_CHARACTERS = '';
64              
65             You can change both NUMBER_CHARACTERS and SPECIAL_CHARACTERS if you really need to.
66              
67             =head1 TODO
68              
69             It will be nice to have more variants of "complexity". Let's say we can create
70             method ->level($level_type) that will switch between them. For me this default
71             is enought. If you have different demant just drop me an email and i can include it
72             here may be somebody else will reuse.
73              
74             =cut
75              
76 1     1   22913 use warnings;
  1         3  
  1         32  
77 1     1   5 use strict;
  1         2  
  1         35  
78 1     1   5 use base 'HTML::Widget::Constraint';
  1         1  
  1         752  
79              
80             our $VERSION = '0.01';
81              
82 1     1   6 use Exporter 'import';
  1         1  
  1         356  
83             our @EXPORT_OK = qw(
84             $MIN_LENGTH
85             $SPECIAL_CHARACTERS
86             );
87              
88             our $MIN_LENGTH = 8;
89             our $NUMBER_CHARACTERS = '0123456789';
90             our $SPECIAL_CHARACTERS = '~`!@#$%^&*()-_+={}[]\\|:;"\'<>,.?/';
91              
92             =head1 METHODS
93              
94             =over 4
95              
96             =cut
97              
98             __PACKAGE__->mk_accessors(qw{
99             min_length
100             });
101              
102             =item min_length()
103              
104             Set minimum length of password just for current widget.
105              
106             =item validate($value)
107              
108             Perform validation $value validation.
109              
110             Return true or false if the password is or isn't ok.
111              
112             =cut
113              
114             sub validate {
115 0     0     my $self = shift;
116 0           my $value = shift;
117              
118             #undefined value is not valid
119 0 0         return 0 if not defined $value;
120              
121             #must have some length
122 0 0 0       return 0 if length($value) < ($self->min_length || $MIN_LENGTH);
123            
124             #must have one upper case character
125 0 0         return 0 if not $value =~ m{[A-Z]};
126              
127             #must have one lower case character
128 0 0         return 0 if not $value =~ m{[a-z]};
129              
130             #must have one special character or number
131 0           my $special_char;
132 0           my $dup_value = $value;
133 0           while ($special_char = chop($dup_value)) {
134 0 0         last if (index($SPECIAL_CHARACTERS, $special_char) != -1);
135             }
136 0           my $number_char;
137 0           $dup_value = $value;
138 0           while ($number_char = chop($dup_value)) {
139 0 0         last if (index($NUMBER_CHARACTERS, $number_char) != -1);
140             }
141 0 0 0       return 0 if (
142             ($special_char eq '') #special char
143             and
144             ($number_char eq '') #number char
145             );
146              
147             #if it passed until here it's valid
148 0           return 1;
149             }
150              
151             =back
152              
153             =cut
154              
155             1;
156              
157             __END__