Passed
Branch master (acb862)
by Simon
03:16
created

updateValidatePassword()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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