#!/usr/bin/perl # # call this file passcheck.pl in order to test it with the # test script use strict ; use warnings ; sub passcheck { my ($username,$password,$name,$surname,$city) = @_ ; my ($minlen,$maxlen,$maxfreq) = (5,8,.5) ; my $plen = length $password ; my $pclean = lc $password ; $pclean =~ s/[^a-z]//g ; my %prots = map {$_,qr/$_/} ($pclean,leftrotations($pclean)) ; # Check length { return "password is too short" if $plen < $minlen ; return "password is too long" if $plen > $maxlen ; } # Check repetitions { my @chars = split //,$password ; my %unique ; foreach my $char (@chars) { $unique{$char}++ } ; while (my ($char,$count) = each %unique) { return "Too many repetions of char $char" if $count/$plen > $maxfreq ; } } # Check password against username, name, surname and city # All but username could be composed, like "Alan Louis", or "Di Cioccio" # or "Los Angeles", so we have to treat each chunk separately. { my %chunks = map { ($_,qr/$_/) } split(/\s+/,lc(join(" ",$name,$surname,$city))) ; # Add username to %chunks # You can compact the code below in one line, but why? :-) { my $lcuser = lc $username ; $chunks{$lcuser} = qr/$lcuser/ ; } foreach my $chunk (keys %chunks) { foreach my $rot (keys %prots) { return "password matches personal data after some left rotation" if $rot =~ $chunks{$chunk} or $chunk =~ $prots{$rot} ; } } } # Left rotations of the password don't match it { foreach my $rot (leftrotations($password)) { return "Password matches itself after some left rotation" if $rot eq $password ; } } # Password contains alphas, digits and non-alpha-digits { local $_ = $password ; return "Password must contain alphanumeric characters, digits and symbols" unless /[a-z]/i and /\d/ and /[^a-z0-9]/i ; } return "password ok" ; } sub leftrotations { my $string = shift ; my $n = length $string ; my @result ; # note: $i < $n, since the n-th permutation is the password again for (my $i = 1 ; $i < $n ; $i++) { $string =~ s/^(.)(.*)$/$2$1/ ; push @result,$string ; } return @result ; } 1 ; #### #!/usr/bin/perl use Test::More qw(no_plan) ; my ($username,@userinfo) = qw(bronto Marco Marongiu Capoterra) ; my $good = 'c0m&c@z%' ; my @passwords = qw(shrt waytoolong manyyyyy nto12bro% comar1$ marmaron poterr@1 t1c&t1c& pitbull) ; my $ok = "password ok" ; require './passcheck.pl' ; is($ok,passcheck($username,$good,@userinfo),"$good is good") ; isnt($ok,passcheck($username,$_,@userinfo),"$_ is bad") foreach @passwords ;