Skip to content

Commit b7e8c84

Browse files
committed
Fix password medium validation
1 parent 195e7e2 commit b7e8c84

8 files changed

Lines changed: 106 additions & 17 deletions

File tree

admin-dev/themes/new-theme/js/components/change-password-handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export default class ChangePasswordHandler {
6262
const self = this;
6363

6464
$input.each((index, element) => {
65-
$(element).on('keyup', function checkPasswordStrength() {
65+
$(element).on('keyup input', function checkPasswordStrength() {
6666
const passwordValue = <string>$(this).val();
6767
let $feedbackContainer = $(this).parent().find(self.feedbackSelector);
6868

admin-dev/themes/new-theme/js/components/form/change-password-control.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/**
1+
/**
22
* For the full copyright and license information, please view the
33
* docs/licenses/LICENSE.txt file that was distributed with this source code.
44
*/
@@ -147,21 +147,21 @@ export default class ChangePasswordControl {
147147
},
148148
);
149149

150-
// Prevent submitting the form if new password is not valid
151-
$(document).on(
152-
'submit',
153-
$(this.oldPasswordInputSelector).closest('form'),
154-
(event) => {
150+
// Prevent submitting the form if new password is not valid (length, confirmation, and strength score)
151+
const $form = this.$inputsBlock.closest('form');
152+
153+
if ($form.length) {
154+
$form.on('submit', (event: JQuery.TriggeredEvent) => {
155155
// If password input is disabled - we don't need to validate it.
156156
if ($(this.oldPasswordInputSelector).is(':disabled')) {
157157
return;
158158
}
159159

160-
if (!this.passwordValidator.isPasswordValid()) {
160+
if (!this.passwordValidator.isPasswordValid() || !this.passwordHandler.isPasswordValid()) {
161161
event.preventDefault();
162162
}
163-
},
164-
);
163+
});
164+
}
165165
}
166166

167167
/**

admin-dev/themes/new-theme/js/pages/customer/CustomerForm.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export default class CustomerForm {
1717
);
1818
passwordHandler.watchPasswordStrength($(customerFormMap.passwordInput));
1919

20+
this.preventSubmitWhenPasswordWeak(passwordHandler);
21+
2022
// Watch customer group checkbox change and if it was unchecked,
2123
// update default group below if it's no longer in the list.
2224
$(customerFormMap.customerGroupCheckboxes).on('change', (event) => {
@@ -33,6 +35,31 @@ export default class CustomerForm {
3335
});
3436
}
3537

38+
/**
39+
* Prevent form submit when password field has value but does not meet strength requirement.
40+
*
41+
* @param passwordHandler
42+
* @private
43+
*/
44+
private preventSubmitWhenPasswordWeak(passwordHandler: ChangePasswordHandler): void {
45+
const $form = $(customerFormMap.passwordInput).closest('form');
46+
47+
if ($form.length) {
48+
$form.on('submit', (event: JQuery.TriggeredEvent) => {
49+
const $passwordInput = $(customerFormMap.passwordInput);
50+
const hasInvalidPassword =
51+
$passwordInput.length
52+
&& $passwordInput.val()
53+
&& !$passwordInput.prop('disabled')
54+
&& !passwordHandler.isPasswordValid();
55+
56+
if (hasInvalidPassword) {
57+
event.preventDefault();
58+
}
59+
});
60+
}
61+
}
62+
3663
private checkOrUpdateDefaultGroup(wasChecked: boolean): void {
3764
// Get currently selected group ID
3865
const currentDefaultGroup = Number(<string> $(customerFormMap.defaultGroupSelectedOption).val());

admin-dev/themes/new-theme/js/pages/employee/EmployeeForm.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,37 @@ export default class EmployeeForm {
5151
);
5252
passwordHandler.watchPasswordStrength($(employeeFormMap.passwordInput));
5353

54+
this.preventSubmitWhenPasswordWeak(passwordHandler);
55+
5456
this.initEvents();
5557
this.toggleShopTree();
5658
}
5759

60+
/**
61+
* Prevent form submit when initial password field has value but does not meet strength requirement.
62+
*
63+
* @param passwordHandler
64+
* @private
65+
*/
66+
private preventSubmitWhenPasswordWeak(passwordHandler: ChangePasswordHandler): void {
67+
const $form = $(employeeFormMap.passwordInput).closest('form');
68+
69+
if ($form.length) {
70+
$form.on('submit', (event: JQuery.TriggeredEvent) => {
71+
const $passwordInput = $(employeeFormMap.passwordInput);
72+
const hasInvalidPassword =
73+
$passwordInput.length
74+
&& $passwordInput.val()
75+
&& !$passwordInput.prop('disabled')
76+
&& !passwordHandler.isPasswordValid();
77+
78+
if (hasInvalidPassword) {
79+
event.preventDefault();
80+
}
81+
});
82+
}
83+
}
84+
5885
/**
5986
* Initialize page's events.
6087
*

classes/Validate.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -531,9 +531,15 @@ public static function isAcceptablePasswordScore(string $password): bool
531531
{
532532
$zxcvbn = new Zxcvbn();
533533
$result = $zxcvbn->passwordStrength($password);
534-
$minScore = Configuration::hasKey(PasswordPolicyConfiguration::CONFIGURATION_MINIMUM_SCORE) ?
535-
Configuration::get(PasswordPolicyConfiguration::CONFIGURATION_MINIMUM_SCORE) :
536-
PasswordPolicyConfiguration::PASSWORD_SAFELY_UNGUESSABLE;
534+
535+
// During install, Configuration is not available; require strong password (score 3) without relying on DB
536+
if (defined('PS_INSTALLATION_IN_PROGRESS')) {
537+
$minScore = PasswordPolicyConfiguration::PASSWORD_SAFELY_UNGUESSABLE;
538+
} else {
539+
$minScore = Configuration::hasKey(PasswordPolicyConfiguration::CONFIGURATION_MINIMUM_SCORE) ?
540+
Configuration::get(PasswordPolicyConfiguration::CONFIGURATION_MINIMUM_SCORE) :
541+
PasswordPolicyConfiguration::PASSWORD_SAFELY_UNGUESSABLE;
542+
}
537543

538544
return isset($result['score']) && $result['score'] >= $minScore;
539545
}

install-dev/theme/js/configure.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,34 @@ $(function() {
3131
});
3232

3333
watchPasswordStrength($('#infosPassword'));
34+
35+
// Prevent form submit when password does not meet minimum strength (score) or length
36+
$('#mainForm').on('submit', function(e) {
37+
const $passwordInput = $('#infosPassword');
38+
if ($passwordInput.length === 0) {
39+
return;
40+
}
41+
const passwordValue = $passwordInput.val();
42+
if (!passwordValue) {
43+
return;
44+
}
45+
const minScore = $passwordInput.data('minscore');
46+
const minLength = $passwordInput.data('minlength');
47+
const maxLength = $passwordInput.data('maxlength');
48+
const result = zxcvbn(passwordValue);
49+
const scoreValid = result.score >= minScore;
50+
const lengthValid = passwordValue.length >= minLength && passwordValue.length <= maxLength;
51+
if (!scoreValid || !lengthValid) {
52+
e.preventDefault();
53+
e.stopImmediatePropagation();
54+
const errorMessage = $passwordInput.closest('.field-password').data('passwordMustBeStrong')
55+
|| 'The password must be strong (see requirements above).';
56+
$passwordInput.closest('.field-password').find('.js-password-client-error').show().text(errorMessage);
57+
$passwordInput.closest('.field-password').find('.password-strength-feedback').removeClass('d-none');
58+
$('#btNext').show();
59+
return false;
60+
}
61+
});
3462
});
3563

3664
function checkTimeZone(elt)
@@ -79,7 +107,7 @@ function in_array(needle, haystack) {
79107
*/
80108
function watchPasswordStrength(element) {
81109
element.on('keyup', function checkPasswordStrength() {
82-
$('.field-password .errorTxt').hide();
110+
$('.field-password .js-password-client-error').hide();
83111
const passwordValue = $(this).val();
84112
const popoverElement = $('.field-password .popover');
85113
let $feedbackContainer = $(this).parent().find('.password-strength-feedback');

install-dev/theme/views/configure.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
<?php echo $this->displayError('admin_email'); ?>
9999
</div>
100100

101-
<div class="field field-password clearfix">
101+
<div class="field field-password clearfix" data-password-must-be-strong="<?php echo htmlspecialchars($this->translator->trans('The password is incorrect (must be Strong)', [], 'Install')); ?>">
102102
<label for="infosPassword" class="aligned">
103103
<?php echo $this->translator->trans('Shop password', [], 'Install'); ?><sup class="required">*</sup>
104104
</label>
@@ -117,6 +117,7 @@
117117
<?php } else { ?>
118118
<p class="userInfos aligned"><?php echo $this->translator->trans('Must be at least 8 characters', [], 'Install'); ?></p>
119119
<?php } ?>
120+
<span class="result aligned errorTxt js-password-client-error" style="display:none;"></span>
120121
</div>
121122

122123
<div class="field clearfix">

tests/UI/.env.ci

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ URL_BO="https://localhost:8002/admin-dev/"
55
URL_API="https://localhost:8002/admin-api/"
66
URL_INSTALL="https://localhost:8002/install-dev/"
77

8-
# BO account
8+
# BO account (password must meet install strength: zxcvbn score >= 3, see Validate::isAcceptablePasswordScore)
99
LOGIN="demo@prestashop.com"
10-
PASSWD="Correct Horse Battery Staple"
10+
PASSWD="Pr3st@Sh0p-T3st-P@ssw0rd!"
1111
FIRSTNAME="Marc"
1212
LASTNAME="Beier"
1313

0 commit comments

Comments
 (0)