1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
package Data::Password::zxcvbn::Match::Sequence;
use Moo;
with 'Data::Password::zxcvbn::Match';
our $VERSION = '1.1.2'; # VERSION
# ABSTRACT: match class for sequences of uniformly-spaced codepoints
has ascending => (is => 'ro', default => 1);
sub estimate_guesses {
my ($self,$min_guesses) = @_;
my $first_char = substr($self->token,0,1);
my $guesses;
# lower guesses for obvious starting points
if ($first_char =~ m{[aAzZ019]}) {
$guesses = 4;
}
elsif ($first_char =~ m{[0-9]}) {
$guesses = 10; # digits
}
else {
# could give a higher base for uppercase, assigning 26 to both
# upper and lower sequences is more conservative.
$guesses = 26;
}
$guesses *= 2 unless $self->ascending;
return $guesses * length($self->token);
}
sub feedback_warning {
my ($self) = @_;
return 'Sequences like abc or 6543 are easy to guess';
}
sub feedback_suggestions {
return [ 'Avoid sequences' ];
}
my $MAX_DELTA = 5;
sub make {
my ($class, $password) = @_;
# Identifies sequences by looking for repeated differences in
# unicode codepoint. this allows skipping, such as 9753, and also
# matches some extended unicode sequences such as Greek and
# Cyrillic alphabets.
#
# for example, consider the input 'abcdb975zy'
#
# password: a b c d b 9 7 5 z y
# index: 0 1 2 3 4 5 6 7 8 9
# delta: 1 1 1 -2 -41 -2 -2 69 1
#
# expected result:
# [(i, j, delta), ...] = [(0, 3, 1), (5, 7, -2), (8, 9, 1)]
my $length = length($password);
return [] if $length <= 1;
my @matches;
my $update = sub {
my ($i,$j,$delta) = @_;
my $abs_delta = abs($delta||0);
return unless $j-$i>1 or $abs_delta == 1;
return if $abs_delta == 0;
return if $abs_delta > $MAX_DELTA;
my $token = substr($password,$i,$j-$i+1);
push @matches, $class->new({
token => $token,
i => $i, j => $j,
ascending => !!($delta>0),
});
};
my $i=0;
my $last_delta;
for my $k (1..$length-1) {
my $delta = ord(substr($password,$k,1)) - ord(substr($password,$k-1,1));
$last_delta = $delta unless defined($last_delta);
next if $delta == $last_delta;
my $j = $k-1;
$update->($i,$j,$last_delta);
$i = $j; $last_delta = $delta;
}
$update->($i,$length-1,$last_delta);
return \@matches;
}
around fields_for_json => sub {
my ($orig,$self) = @_;
( $self->$orig(), qw(ascending) )
};
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Data::Password::zxcvbn::Match::Sequence - match class for sequences of uniformly-spaced codepoints
=head1 VERSION
version 1.1.2
=head1 DESCRIPTION
This class represents the guess that a certain substring of a
password, consisting of uniformly-spaced codepoints, is easy to guess.
=head1 ATTRIBUTES
=head2 C<ascending>
Boolean, true if the sequence starts at a lower codepoint and ends at
a higher one (e.g. C<acegi> is ascending, C<86420> is not).
=head1 METHODS
=head2 C<estimate_guesses>
The number of guesses is I<linear> with the length of the
sequence. Descending sequences get a higher estimate, sequences that
start at obvious points (e.g. C<A> or C<1>) get lower estimates.
=head2 C<feedback_warning>
=head2 C<feedback_suggestions>
This class suggests not using sequences.
=head2 C<make>
my @matches = @{ Data::Password::zxcvbn::Match::Sequence->make(
$password,
) };
Scans the C<$password> for sequences of characters whose codepoints
increase or decrease by a constant.
=head2 C<fields_for_json>
The JSON serialisation for matches of this class will contain C<token
i j guesses guesses_log10 ascending>.
=head1 AUTHOR
Gianni Ceccarelli <gianni.ceccarelli@broadbean.com>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2022 by BroadBean UK, a CareerBuilder Company.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
|