Passed
Push — master ( 05b9f0...2260f3 )
by Simon
01:51
created

PasswordValidatorExtension::checkPwndSites()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 2
dl 0
loc 11
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Firesphere\HaveIBeenPwnd\Extensions;
4
5
use Firesphere\HaveIBeenPwnd\Services\HaveIBeenPwndService;
6
use SilverStripe\Core\Config\Configurable;
7
use SilverStripe\Core\Extension;
8
use SilverStripe\Core\Injector\Injector;
9
use SilverStripe\Dev\Debug;
10
use SilverStripe\ORM\ValidationResult;
11
use SilverStripe\Security\Member;
12
use SilverStripe\Security\PasswordValidator;
13
14
/**
15
 * Class \Firesphere\HaveIBeenPwnd\Extensions\PasswordValidatorExtension
16
 *
17
 * @property PasswordValidator|PasswordValidatorExtension $owner
18
 */
19
class PasswordValidatorExtension extends Extension
20
{
21
    use Configurable;
22
23
    /**
24
     * @var HaveIBeenPwndService
25
     */
26
    protected $service;
27
28
    /**
29
     * @param string $pwd
30
     * @param Member $member
31
     * @param ValidationResult $valid
32
     * @param array $params
33
     * @return void
34
     * @throws \GuzzleHttp\Exception\GuzzleException
35
     */
36
    public function updateValidatePassword($pwd, $member, $valid, $params = [])
37
    {
38
        $this->service = Injector::inst()->createWithArgs(HaveIBeenPwndService::class, [$params]);
39
40
        $allowPwnd = HaveIBeenPwndService::config()->get('allow_pwnd');
41
        $savePwnd = HaveIBeenPwndService::config()->get('save_pwnd');
42
43
        $isPwndCount = $this->checkPwnCount($pwd, $member, $allowPwnd);
44
        $breached = $this->checkPwndSites($member, $savePwnd);
45
46
47
        // Although it would be stupid, the pwnd check can be disabled
48
        // Or even allow for breached passwords. Not exactly ideal
49
        if ($isPwndCount && !$allowPwnd) {
50
            $valid->addFieldError(
51
                'Password',
52
                _t(static::class . 'KNOWN', 'Your password appears in the Have I Been Pwnd database')
53
            );
54
            if ($breached) {
55
                $message = _t(
56
                    static::class . 'KNOWN_BREACH_PLUS_BREACHES',
57
                    "To help you identify where you have been breached, your username or email address appears in the following breaches:\r\n"
58
                );
59
60
                $valid->addError($message . $breached);
61
            }
62
        }
63
    }
64
65
    /**
66
     * @param $pwd
67
     * @param $member
68
     * @param $allowPwnd
69
     * @return int
70
     * @throws \GuzzleHttp\Exception\GuzzleException
71
     */
72
    protected function checkPwnCount($pwd, $member, $allowPwnd)
73
    {
74
        $isPwndCount = 0;
75
        // There's no need to check if breaches are allowed, it's a pointless excercise
76
        if (!$allowPwnd) {
77
            $isPwndCount = $this->service->checkPwndPassword($pwd);
78
        }
79
80
        // Always mark as Pwnd if it's true
81
        $member->PasswordIsPwnd = $isPwndCount;
82
83
        return $isPwndCount;
84
    }
85
86
    /**
87
     * @param $member
88
     * @param $savePwnd
89
     * @return string
90
     * @throws \GuzzleHttp\Exception\GuzzleException
91
     */
92
    protected function checkPwndSites($member, $savePwnd)
93
    {
94
        $breached = '';
95
        // If storing the breached sites, check the email as well
96
        if ($savePwnd) {
97
            usleep(1500); // We need to conform to the FUP, max 1 request per 1500ms
98
            $breached = $this->service->checkPwndEmail($member);
99
            $member->BreachedSites = $breached;
100
        }
101
102
        return $breached;
103
    }
104
}
105