added client side check for trivial password policies (#32846)
* added client side check for trivial password policies fixes: #32845 Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * changed to make use of template Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * nicer active policy structure Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> --------- Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
This commit is contained in:
parent
0f97e4cb39
commit
22f9d2077e
3 changed files with 99 additions and 1 deletions
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
<#nested>
|
<#nested>
|
||||||
|
|
||||||
|
<div id="input-error-client-${name}"></div>
|
||||||
<#if error?has_content>
|
<#if error?has_content>
|
||||||
<div class="${properties.kcFormHelperTextClass}" aria-live="polite">
|
<div class="${properties.kcFormHelperTextClass}" aria-live="polite">
|
||||||
<div class="${properties.kcInputHelperTextClass}">
|
<div class="${properties.kcInputHelperTextClass}">
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
</#if>
|
</#if>
|
||||||
<#elseif section = "form">
|
<#elseif section = "form">
|
||||||
<form id="kc-register-form" class="${properties.kcFormClass!}" action="${url.registrationAction}" method="post" novalidate="novalidate">
|
<form id="kc-register-form" class="${properties.kcFormClass!}" action="${url.registrationAction}" method="post" novalidate="novalidate">
|
||||||
|
|
||||||
<@userProfileCommons.userProfileFormFields; callback, attribute>
|
<@userProfileCommons.userProfileFormFields; callback, attribute>
|
||||||
<#if callback = "afterField">
|
<#if callback = "afterField">
|
||||||
<#-- render password fields just under the username or email (if used as username) -->
|
<#-- render password fields just under the username or email (if used as username) -->
|
||||||
|
@ -46,5 +45,50 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<template id="errorTemplate">
|
||||||
|
<div class="${properties.kcFormHelperTextClass}" aria-live="polite">
|
||||||
|
<div class="${properties.kcInputHelperTextClass}">
|
||||||
|
<div class="${properties.kcInputHelperTextItemClass} ${properties.kcError}">
|
||||||
|
<ul class="${properties.kcInputErrorMessageClass}">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template id="errorItemTemplate">
|
||||||
|
<li></li>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
import { validatePassword } from "${url.resourcesPath}/js/password-policy.js";
|
||||||
|
|
||||||
|
const template = document.querySelector("#errorTemplate").content.cloneNode(true);
|
||||||
|
|
||||||
|
const activePolicies = [
|
||||||
|
{ name: "length", policy: { value: ${passwordPolicies.length!-1}, error: "${msg('invalidPasswordMinLengthMessage')}"} },
|
||||||
|
{ name: "maxLength", policy: { value: ${passwordPolicies.maxLength!-1}, error: "${msg('invalidPasswordMaxLengthMessage')}"} },
|
||||||
|
{ name: "lowerCase", policy: { value: ${passwordPolicies.lowerCase!-1}, error: "${msg('invalidPasswordMinLowerCaseCharsMessage')}"} },
|
||||||
|
{ name: "upperCase", policy: { value: ${passwordPolicies.upperCase!-1}, error: "${msg('invalidPasswordMinUpperCaseCharsMessage')}"} },
|
||||||
|
{ name: "digits", policy: { value: ${passwordPolicies.digits!-1}, error: "${msg('invalidPasswordMinDigitsMessage')}"} },
|
||||||
|
{ name: "specialChars", policy: { value: ${passwordPolicies.specialChars!-1}, error: "${msg('invalidPasswordMinSpecialCharsMessage')}"} }
|
||||||
|
].filter(p => p.policy.value !== -1);
|
||||||
|
|
||||||
|
document.getElementById("password").addEventListener("change", (event) => {
|
||||||
|
const serverErrors = document.getElementById("input-error-password");
|
||||||
|
if (serverErrors) {
|
||||||
|
serverErrors.remove();
|
||||||
|
}
|
||||||
|
const errors = validatePassword(event.target.value, activePolicies);
|
||||||
|
const errorList = template.querySelector("ul");
|
||||||
|
const htmlErrors = errors.forEach((e) => {
|
||||||
|
const row = document.querySelector("#errorItemTemplate").content.cloneNode(true);
|
||||||
|
const li = row.querySelector("li");
|
||||||
|
li.textContent = e;
|
||||||
|
errorList.appendChild(li);
|
||||||
|
});
|
||||||
|
document.getElementById("input-error-client-password").appendChild(template);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</#if>
|
</#if>
|
||||||
</@layout.registrationLayout>
|
</@layout.registrationLayout>
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
const policies = {
|
||||||
|
length: (policy, value) => {
|
||||||
|
if (value.length < policy.value) {
|
||||||
|
return templateError(policy);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxLength: (policy, value) => {
|
||||||
|
if (value.length > policy.value) {
|
||||||
|
return templateError(policy);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
upperCase: (policy, value) => {
|
||||||
|
if (
|
||||||
|
value.split("").filter((char) => char !== char.toUpperCase()).length >
|
||||||
|
policy.value
|
||||||
|
) {
|
||||||
|
return templateError(policy);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
lowerCase: (policy, value) => {
|
||||||
|
if (
|
||||||
|
value.split("").filter((char) => char !== char.toLowerCase()).length >
|
||||||
|
policy.value
|
||||||
|
) {
|
||||||
|
return templateError(policy);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
digits: (policy, value) => {
|
||||||
|
const digits = value.split("").filter((char) => char.match(/\d/));
|
||||||
|
if (digits.length < policy.value) {
|
||||||
|
return templateError(policy);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
specialChars: (policy, value) => {
|
||||||
|
let specialChars = value.split("").filter((char) => char.match(/\W/));
|
||||||
|
if (specialChars.length < policy.value) {
|
||||||
|
return templateError(policy);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const templateError = (policy) => policy.error.replace("{0}", policy.value);
|
||||||
|
|
||||||
|
export function validatePassword(password, activePolicies) {
|
||||||
|
const errors = [];
|
||||||
|
for (const p of activePolicies) {
|
||||||
|
const validationError = policies[p.name](p.policy, password);
|
||||||
|
if (validationError) {
|
||||||
|
errors.push(validationError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
Loading…
Reference in a new issue