Completed
Push — master ( e332d4...504537 )
by Torben
02:37
created

ChangePasswordValidator::isValid()   C

Complexity

Conditions 13
Paths 50

Size

Total Lines 49
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 25
c 1
b 0
f 0
dl 0
loc 49
rs 6.6166
cc 13
nc 50
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
namespace Derhansen\FeChangePwd\Validation\Validator;
4
5
/*
6
 * This file is part of the Extension "fe_change_pwd" for TYPO3 CMS.
7
 *
8
 * For the full copyright and license information, please read the
9
 * LICENSE.txt file that was distributed with this source code.
10
 */
11
12
use Derhansen\FeChangePwd\Domain\Model\Dto\ChangePassword;
13
use Derhansen\FeChangePwd\Service\LocalizationService;
14
use Derhansen\FeChangePwd\Service\OldPasswordService;
15
use Derhansen\FeChangePwd\Service\PwnedPasswordsService;
16
use Derhansen\FeChangePwd\Service\SettingsService;
17
18
/**
19
 * Class RegistrationValidator
20
 */
21
class ChangePasswordValidator extends \TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator
22
{
23
    /**
24
     * Available password checks
25
     *
26
     * @var array
27
     */
28
    protected $checks = [
29
        'capitalCharCheck',
30
        'lowerCaseCharCheck',
31
        'digitCheck',
32
        'specialCharCheck',
33
    ];
34
35
    /**
36
     * @var SettingsService
37
     */
38
    protected $settingsService = null;
39
40
    /**
41
     * @var LocalizationService
42
     */
43
    protected $localizationService = null;
44
45
    /**
46
     * @var PwnedPasswordsService
47
     */
48
    protected $pwnedPasswordsService = null;
49
50
    /**
51
     * @var OldPasswordService
52
     */
53
    protected $oldPasswordService = null;
54
55
    /**
56
     * @param SettingsService $settingsService
57
     */
58
    public function injectSettingsService(\Derhansen\FeChangePwd\Service\SettingsService $settingsService)
59
    {
60
        $this->settingsService = $settingsService;
61
    }
62
63
    /**
64
     * @param LocalizationService $localizationService
65
     */
66
    public function injectLocalizationService(
67
        \Derhansen\FeChangePwd\Service\LocalizationService $localizationService
68
    ) {
69
        $this->localizationService = $localizationService;
70
    }
71
72
    /**
73
     * @param OldPasswordService $oldPasswordService
74
     */
75
    public function injectOldPasswordService(\Derhansen\FeChangePwd\Service\OldPasswordService $oldPasswordService)
76
    {
77
        $this->oldPasswordService = $oldPasswordService;
78
    }
79
80
    /**
81
     * @param PwnedPasswordsService $PwnedPasswordsService
82
     */
83
    public function injectPwnedPasswordsService(
84
        \Derhansen\FeChangePwd\Service\PwnedPasswordsService $PwnedPasswordsService
85
    ) {
86
        $this->pwnedPasswordsService = $PwnedPasswordsService;
87
    }
88
89
    /**
90
     * Validates the password of the given ChangePassword object against the configured password complexity
91
     *
92
     * @param ChangePassword $value
93
     *
94
     * @return bool
95
     */
96
    protected function isValid($value)
97
    {
98
        $result = true;
99
        $settings = $this->settingsService->getSettings();
100
101
        // Early return if no passwords are given
102
        if ($value->getPassword1() === '' || $value->getPassword2() === '') {
103
            $this->addError(
104
                $this->localizationService->translate('passwordFieldsEmptyOrNotBothFilledOut'),
105
                1537701950
106
            );
107
108
            return false;
109
        }
110
111
        if ($value->getPassword1() !== $value->getPassword2()) {
112
            $this->addError(
113
                $this->localizationService->translate('passwordsDoNotMatch'),
114
                1537701950
115
            );
116
            // Early return, no other checks need to be done if passwords do not match
117
            return false;
118
        }
119
120
        if (isset($settings['passwordComplexity']['minLength'])) {
121
            $this->evaluateMinLengthCheck($value, (int)$settings['passwordComplexity']['minLength']);
122
        }
123
124
        foreach ($this->checks as $check) {
125
            if (isset($settings['passwordComplexity'][$check]) &&
126
                (bool)$settings['passwordComplexity'][$check]
127
            ) {
128
                $this->evaluatePasswordCheck($value, $check);
129
            }
130
        }
131
132
        if (isset($settings['pwnedpasswordsCheck']['enabled']) && (bool)$settings['pwnedpasswordsCheck']['enabled']) {
133
            $this->evaluatePwnedPasswordCheck($value);
134
        }
135
136
        if (isset($settings['oldPasswordCheck']['enabled']) && (bool)$settings['oldPasswordCheck']['enabled']) {
137
            $this->evaluateOldPasswordCheck($value);
138
        }
139
140
        if ($this->result->hasErrors()) {
141
            $result = false;
142
        }
143
144
        return $result;
145
    }
146
147
    /**
148
     * Checks if the password complexity in regards to minimum password length in met
149
     *
150
     * @param ChangePassword $changePassword
151
     * @param int $minLength
152
     * @return void
153
     */
154
    protected function evaluateMinLengthCheck(ChangePassword $changePassword, int $minLength)
155
    {
156
        if (strlen($changePassword->getPassword1()) < $minLength) {
157
            $this->addError(
158
                $this->localizationService->translate('passwordComplexity.failure.minLength', [$minLength]),
159
                1537898028
160
            );
161
        };
162
    }
163
164
    /**
165
     * Evaluates the password complexity in regards to the given check
166
     *
167
     * @param ChangePassword $changePassword
168
     * @param string $check
169
     * @return void
170
     */
171
    protected function evaluatePasswordCheck(ChangePassword $changePassword, $check)
172
    {
173
        $patterns = [
174
            'capitalCharCheck' => '/[A-Z]/',
175
            'lowerCaseCharCheck' => '/[a-z]/',
176
            'digitCheck' => '/[0-9]/',
177
            'specialCharCheck' => '/[^0-9a-z]/i'
178
        ];
179
180
        if (isset($patterns[$check])) {
181
            if (!preg_match($patterns[$check], $changePassword->getPassword1()) > 0) {
182
                $this->addError(
183
                    $this->localizationService->translate('passwordComplexity.failure.' . $check),
184
                    1537898029
185
                );
186
            }
187
        }
188
    }
189
190
    /**
191
     * Evaluates the password using the pwnedpasswords API
192
     *
193
     * @param ChangePassword $changePassword
194
     * @return void
195
     */
196
    protected function evaluatePwnedPasswordCheck(ChangePassword $changePassword)
197
    {
198
        $foundCount = $this->pwnedPasswordsService->checkPassword($changePassword->getPassword1());
199
        if ($foundCount > 0) {
200
            $this->addError(
201
                $this->localizationService->translate('pwnedPasswordFailure', [$foundCount]),
202
                1537898030
203
            );
204
        }
205
    }
206
207
    /**
208
     * Evaluates the password against the current password
209
     *
210
     * @param ChangePassword $changePassword
211
     * @return void
212
     */
213
    protected function evaluateOldPasswordCheck(ChangePassword $changePassword)
214
    {
215
        if ($this->oldPasswordService->checkNewEqualsOldPassword($changePassword->getPassword1())) {
216
            $this->addError(
217
                $this->localizationService->translate('oldPasswordFailure'),
218
                1537898030
219
            );
220
        }
221
    }
222
}
223