File Coverage

blib/lib/Password/Policy/Rule/Pwned.pm
Criterion Covered Total %
statement 40 40 100.0
branch 6 6 100.0
condition n/a
subroutine 10 10 100.0
pod 1 1 100.0
total 57 57 100.0


line stmt bran cond sub pod time code
1             #
2             #===============================================================================
3             #
4             # FILE: Pwned.pm
5             #
6             # DESCRIPTION: Check HIBP to see if this password has been pwned
7             #
8             # FILES: ---
9             # BUGS: ---
10             # NOTES: https://haveibeenpwned.com/API/v2#PwnedPasswords
11             # AUTHOR: Pete Houston (pete), cpan@openstrike.co.uk
12             # ORGANIZATION: Openstrike
13             # VERSION: See $VERSION in code
14             # CREATED: 29/05/18 14:44:30
15             # REVISION: ---
16             #===============================================================================
17              
18 4     4   1142595 use strict;
  4         9  
  4         164  
19 4     4   21 use warnings;
  4         10  
  4         264  
20              
21             package Password::Policy::Rule::Pwned;
22              
23 4     4   34 use parent 'Password::Policy::Rule';
  4         8  
  4         22  
24              
25 4     4   4487 use Password::Policy::Exception::Pwned;
  4         13  
  4         153  
26 4     4   1554 use Password::Policy::Exception::PwnedError;
  4         13  
  4         116  
27 4     4   3202 use LWP::UserAgent;
  4         289955  
  4         266  
28 4     4   2906 use Digest::SHA 'sha1_hex';
  4         16079  
  4         482  
29 4     4   1551 use String::Multibyte;
  4         12792  
  4         396  
30 4     4   1362 use Encode 'encode';
  4         44667  
  4         1836  
31              
32             our $VERSION = '0.03';
33             my $ua = __PACKAGE__ . '/' . $VERSION;
34             my $timeout = 5;
35             our $base_url = 'https://api.pwnedpasswords.com/range/';
36              
37             sub check {
38 25     25 1 375177 my $self = shift;
39 25         98 my $password = $self->prepare (shift);
40 25         212 my $strmb = String::Multibyte->new ('UTF8');
41 25 100       22392 my $hash = uc sha1_hex ($strmb->islegal($password) ? $password :
42             encode ('UTF-8', $password));
43 25         1301 my $range = substr ($hash, 0, 5, '');
44 25         84 my $url = $base_url . $range;
45 25         295 my $res = LWP::UserAgent->new (agent => $ua, timeout => $timeout)->get ($url);
46 25 100       6502477 if ($res->code != 200) {
47 3         63 warn $res->status_line;
48 3         178 Password::Policy::Exception::PwnedError->throw;
49             }
50 22 100       569 if (index ($res->content, "$hash:") > -1) {
51 12         9163 Password::Policy::Exception::Pwned->throw;
52             }
53 10         8400 return 1;
54             }
55              
56             __END__