mirror of
https://github.com/pierre42100/ComunicWeb
synced 2024-11-26 13:59:23 +00:00
Apply password policy on sign up screen
This commit is contained in:
parent
19cfb4760f
commit
0a6dd75a05
3
assets/css/components/passwordInput.css
Normal file
3
assets/css/components/passwordInput.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/**
|
||||||
|
* Password input
|
||||||
|
*/
|
@ -91,6 +91,9 @@ fieldset[disabled] .form-control {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.input-group .help-block {
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boxes
|
* Boxes
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* @author Pierre HUBERT
|
* @author Pierre HUBERT
|
||||||
*/
|
*/
|
||||||
ComunicWeb.common.formChecker = {
|
const FormChecker = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check an input
|
* Check an input
|
||||||
@ -74,3 +74,6 @@ ComunicWeb.common.formChecker = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ComunicWeb.common.formChecker = FormChecker;
|
@ -328,7 +328,15 @@ async function showInputTextDialog(title, message, defaultValue = "") {
|
|||||||
* Prepare for potential future translation system
|
* Prepare for potential future translation system
|
||||||
*
|
*
|
||||||
* @param {String} input Input string
|
* @param {String} input Input string
|
||||||
|
* @param {Object} arguments Arguments to apply to the string
|
||||||
*/
|
*/
|
||||||
function tr(input) {
|
function tr(input, values) {
|
||||||
|
|
||||||
|
// Apply arguments
|
||||||
|
for (const key in values) {
|
||||||
|
if (Object.hasOwnProperty.call(values, key))
|
||||||
|
input = input.replace("%"+key+"%", values[key]);
|
||||||
|
}
|
||||||
|
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
@ -7,7 +7,7 @@
|
|||||||
/**
|
/**
|
||||||
* Check if it is Manon's birthday
|
* Check if it is Manon's birthday
|
||||||
*/
|
*/
|
||||||
async function checkManonBirthday(force) {
|
/*async function checkManonBirthday(force) {
|
||||||
|
|
||||||
if(force !== true) {
|
if(force !== true) {
|
||||||
// Manon's feature only
|
// Manon's feature only
|
||||||
@ -69,4 +69,4 @@ document.addEventListener("wsOpen", () => {
|
|||||||
setTimeout(() => checkManonBirthday(), 1000);
|
setTimeout(() => checkManonBirthday(), 1000);
|
||||||
}, {
|
}, {
|
||||||
once: true
|
once: true
|
||||||
})
|
})*/
|
209
assets/js/components/passwordInput.js
Normal file
209
assets/js/components/passwordInput.js
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
/**
|
||||||
|
* Password input field
|
||||||
|
*
|
||||||
|
* @author Pierre Hubert
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PasswordInput {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create password input field
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} target The target for the password input
|
||||||
|
* @param {String} label The label for the input
|
||||||
|
* @param {String} placeholder The placeholder to use
|
||||||
|
*/
|
||||||
|
constructor(target, label, placeholder) {
|
||||||
|
this._input = createFormGroup({
|
||||||
|
target: target,
|
||||||
|
label: label,
|
||||||
|
placeholder: placeholder,
|
||||||
|
type: "password",
|
||||||
|
});
|
||||||
|
|
||||||
|
this._input.parentNode.parentNode.classList.add("password-input-group");
|
||||||
|
|
||||||
|
this._input.addEventListener("keyup", () => this._refreshArea());
|
||||||
|
this._input.addEventListener("change", () => this._refreshArea());
|
||||||
|
|
||||||
|
this.helpArea = createElem2({
|
||||||
|
appendTo: this._input.parentNode,
|
||||||
|
type: "span",
|
||||||
|
class: "help-block"
|
||||||
|
});
|
||||||
|
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
async _init() {
|
||||||
|
try {
|
||||||
|
await ServerConfig.ensureLoaded()
|
||||||
|
this._ready = true;
|
||||||
|
this._valid = false;
|
||||||
|
this._refreshArea();
|
||||||
|
} catch(e) {
|
||||||
|
console.error(e);
|
||||||
|
notify(tr("Failed to load server configuration! Please reload the page!"), "danger");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setFirstName(firstName) {
|
||||||
|
this._firstName = firstName;
|
||||||
|
this._refreshArea();
|
||||||
|
}
|
||||||
|
|
||||||
|
setLastName(lastName) {
|
||||||
|
this._lastName = lastName;
|
||||||
|
this._refreshArea();
|
||||||
|
}
|
||||||
|
|
||||||
|
setEmail(email) {
|
||||||
|
this._email = email.length > 2 ? email : null;
|
||||||
|
this._refreshArea();
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid() {
|
||||||
|
this._refreshArea();
|
||||||
|
return this._valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
_refreshArea() {
|
||||||
|
if (!this._ready)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.helpArea.innerHTML = "";
|
||||||
|
|
||||||
|
/** @type {String} */
|
||||||
|
const password = this._input.value.trim().toLowerCase();
|
||||||
|
const policy = ServerConfig.conf.password_policy;
|
||||||
|
|
||||||
|
if (password.length == 0) {
|
||||||
|
this._valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._good = [];
|
||||||
|
this._bad = [];
|
||||||
|
|
||||||
|
// Check email
|
||||||
|
this._performMandatoryCheck(
|
||||||
|
tr("Password must not contains part of email address"),
|
||||||
|
!policy.allow_email_in_password && this._email,
|
||||||
|
() => !password.includes(this._email.toLowerCase()) && !this._email.toLowerCase().includes(password)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check name
|
||||||
|
this._performMandatoryCheck(
|
||||||
|
tr("Password must not contains part of name"),
|
||||||
|
!policy.allow_name_in_password && this._firstName && this._lastName,
|
||||||
|
() => !password.includes(this._firstName.toLowerCase()) && !password.includes(this._lastName)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Check password length
|
||||||
|
this._performMandatoryCheck(
|
||||||
|
tr("Password must be composed of at least %num_chars% characters", {num_chars: policy.min_password_length}),
|
||||||
|
true,
|
||||||
|
() => password.length >= policy.min_password_length
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if mandatory arguments are respected
|
||||||
|
this._valid = this._bad.length == 0;
|
||||||
|
|
||||||
|
|
||||||
|
// Check categories presence
|
||||||
|
if(policy.min_categories_presence > 0) {
|
||||||
|
|
||||||
|
let count = 0
|
||||||
|
|
||||||
|
this._performCategoryCheck(
|
||||||
|
this._input.value,
|
||||||
|
tr("At least %num% upper case character", {num: policy.min_number_upper_case_letters}),
|
||||||
|
"[A-Z]",
|
||||||
|
policy.min_number_upper_case_letters
|
||||||
|
) && count++
|
||||||
|
|
||||||
|
this._performCategoryCheck(
|
||||||
|
this._input.value,
|
||||||
|
tr("At least %num% lower case character", {num: policy.min_number_lower_case_letters}),
|
||||||
|
"[a-z]",
|
||||||
|
policy.min_number_lower_case_letters
|
||||||
|
) && count++
|
||||||
|
|
||||||
|
|
||||||
|
this._performCategoryCheck(
|
||||||
|
password,
|
||||||
|
tr("At least %num% digit character", {num: policy.min_number_digits}),
|
||||||
|
"[0-9]",
|
||||||
|
policy.min_number_digits
|
||||||
|
) && count++
|
||||||
|
|
||||||
|
|
||||||
|
this._performCategoryCheck(
|
||||||
|
password,
|
||||||
|
tr("At least %num% special character", {num: policy.min_number_special_characters}),
|
||||||
|
"[^0-9a-zA-Z]",
|
||||||
|
policy.min_number_special_characters
|
||||||
|
) && count++
|
||||||
|
|
||||||
|
if (count < policy.min_categories_presence)
|
||||||
|
this._valid = false;
|
||||||
|
|
||||||
|
if (policy.min_categories_presence < 4)
|
||||||
|
this._performMandatoryCheck(
|
||||||
|
tr(
|
||||||
|
"At least %num% of the following : upper case letter, lower case letter, digit or special character",
|
||||||
|
{num: policy.min_categories_presence}
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
() => count >= policy.min_categories_presence
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (this._valid) {
|
||||||
|
this.helpArea.innerHTML = tr("You can use this password");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let bad of this._bad)
|
||||||
|
this._addTip(false, bad);
|
||||||
|
|
||||||
|
for(let good of this._good)
|
||||||
|
this._addTip(true, good);
|
||||||
|
}
|
||||||
|
|
||||||
|
_performMandatoryCheck(check_label, requisite, check) {
|
||||||
|
if (!requisite)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const pass = check();
|
||||||
|
if (!pass)
|
||||||
|
this._bad.push(check_label);
|
||||||
|
|
||||||
|
else
|
||||||
|
this._good.push(check_label);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
_performCategoryCheck(password, check_label, regex, numRequired) {
|
||||||
|
if (numRequired < 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const pass = [...password.matchAll(regex)].length >= numRequired;
|
||||||
|
|
||||||
|
if (!pass)
|
||||||
|
this._bad.push(check_label);
|
||||||
|
|
||||||
|
else
|
||||||
|
this._good.push(check_label);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_addTip(isGood, content) {
|
||||||
|
this.helpArea.innerHTML += "<i class='fa "+(isGood ? "fa-check": "fa-close ")+"'></i> " + content + "<br />";
|
||||||
|
}
|
||||||
|
}
|
@ -199,8 +199,6 @@ ComunicWeb.common.langs.en = {
|
|||||||
form_create_account_last_name_placeholder: "Your last name",
|
form_create_account_last_name_placeholder: "Your last name",
|
||||||
form_create_account_email_address_label: "Email address <small><i class='fa fa-warning'></i> Warning! You will not be able to change this later !</small>",
|
form_create_account_email_address_label: "Email address <small><i class='fa fa-warning'></i> Warning! You will not be able to change this later !</small>",
|
||||||
form_create_account_email_address_placeholder: "Your email address",
|
form_create_account_email_address_placeholder: "Your email address",
|
||||||
form_create_account_password_label: "Password",
|
|
||||||
form_create_account_password_placeholder: "Your password",
|
|
||||||
form_create_account_confirm_password_label: "Confirm your password",
|
form_create_account_confirm_password_label: "Confirm your password",
|
||||||
form_create_account_confirm_password_placeholder: "Your password",
|
form_create_account_confirm_password_placeholder: "Your password",
|
||||||
form_create_account_terms_label: "I have read and accepted the <a href='%p' target='_blank'>terms of use of the network</a>",
|
form_create_account_terms_label: "I have read and accepted the <a href='%p' target='_blank'>terms of use of the network</a>",
|
||||||
|
@ -197,8 +197,6 @@ ComunicWeb.common.langs.fr = {
|
|||||||
form_create_account_last_name_placeholder: "Votre nom",
|
form_create_account_last_name_placeholder: "Votre nom",
|
||||||
form_create_account_email_address_label: "Adresse mail <small><i class='fa fa-warning'></i> Attention ! Vous ne pourrez pas changer cette valeur plus tard !</small>",
|
form_create_account_email_address_label: "Adresse mail <small><i class='fa fa-warning'></i> Attention ! Vous ne pourrez pas changer cette valeur plus tard !</small>",
|
||||||
form_create_account_email_address_placeholder: "Votre adresse mail",
|
form_create_account_email_address_placeholder: "Votre adresse mail",
|
||||||
form_create_account_password_label: "Mot de passe",
|
|
||||||
form_create_account_password_placeholder: "Votre mot de passe",
|
|
||||||
form_create_account_confirm_password_label: "Confirmez votre mot de passe",
|
form_create_account_confirm_password_label: "Confirmez votre mot de passe",
|
||||||
form_create_account_confirm_password_placeholder: "Votre mot de passe",
|
form_create_account_confirm_password_placeholder: "Votre mot de passe",
|
||||||
form_create_account_terms_label: "J'ai lu et accepté les <a href='%p' target='_blank'>conditions d'utilisation du réseau</a>",
|
form_create_account_terms_label: "J'ai lu et accepté les <a href='%p' target='_blank'>conditions d'utilisation du réseau</a>",
|
||||||
|
@ -77,13 +77,16 @@ ComunicWeb.pages.createAccount = {
|
|||||||
type: "email"
|
type: "email"
|
||||||
});
|
});
|
||||||
|
|
||||||
//Input user password
|
// Input user password
|
||||||
var passwordInput = createFormGroup({
|
const passwordInput = new PasswordInput(formRoot, tr("Password"), tr("Your password"));
|
||||||
target: formRoot,
|
emailInput.addEventListener("keyup", () => passwordInput.setEmail(emailInput.value))
|
||||||
label: lang("form_create_account_password_label"),
|
emailInput.addEventListener("change", () => passwordInput.setEmail(emailInput.value))
|
||||||
placeholder: lang("form_create_account_password_placeholder"),
|
|
||||||
type: "password"
|
firstNameInput.addEventListener("keyup", () => passwordInput.setFirstName(firstNameInput.value))
|
||||||
});
|
firstNameInput.addEventListener("change", () => passwordInput.setFirstName(firstNameInput.value))
|
||||||
|
|
||||||
|
lastNameInput.addEventListener("keyup", () => passwordInput.setLastName(lastNameInput.value))
|
||||||
|
lastNameInput.addEventListener("change", () => passwordInput.setLastName(lastNameInput.value))
|
||||||
|
|
||||||
//Confirm user password
|
//Confirm user password
|
||||||
var confirmPasswordInput = createFormGroup({
|
var confirmPasswordInput = createFormGroup({
|
||||||
@ -142,19 +145,19 @@ ComunicWeb.pages.createAccount = {
|
|||||||
return notify(lang("form_create_account_err_need_accept_terms"), "danger");
|
return notify(lang("form_create_account_err_need_accept_terms"), "danger");
|
||||||
|
|
||||||
//Check the first name
|
//Check the first name
|
||||||
if(!ComunicWeb.common.formChecker.checkInput(firstNameInput, true))
|
if(!FormChecker.checkInput(firstNameInput, true))
|
||||||
return notify(lang("form_create_account_err_need_first_name"), "danger");
|
return notify(lang("form_create_account_err_need_first_name"), "danger");
|
||||||
|
|
||||||
//Check the last name
|
//Check the last name
|
||||||
if(!ComunicWeb.common.formChecker.checkInput(lastNameInput, true))
|
if(!FormChecker.checkInput(lastNameInput, true))
|
||||||
return notify(lang("form_create_account_err_check_last_name"), "danger");
|
return notify(lang("form_create_account_err_check_last_name"), "danger");
|
||||||
|
|
||||||
//Check the email address
|
//Check the email address
|
||||||
if(!ComunicWeb.common.formChecker.checkInput(emailInput, true))
|
if(!FormChecker.checkInput(emailInput, true))
|
||||||
return notify(lang("form_create_account_err_check_email_address"), "danger");
|
return notify(lang("form_create_account_err_check_email_address"), "danger");
|
||||||
|
|
||||||
//Check the password
|
//Check the password
|
||||||
if(!ComunicWeb.common.formChecker.checkInput(passwordInput, true))
|
if(!passwordInput._valid)
|
||||||
return notify(lang("form_create_account_err_check_password"), "danger");
|
return notify(lang("form_create_account_err_check_password"), "danger");
|
||||||
|
|
||||||
//Check the confirmation password
|
//Check the confirmation password
|
||||||
|
12
assets/js/typings/ServerConfig.d.ts
vendored
12
assets/js/typings/ServerConfig.d.ts
vendored
@ -4,6 +4,17 @@
|
|||||||
* @author Pierre Hubert
|
* @author Pierre Hubert
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
declare interface PasswordPolicy {
|
||||||
|
allow_email_in_password: boolean,
|
||||||
|
allow_name_in_password: boolean,
|
||||||
|
min_password_length: number,
|
||||||
|
min_number_upper_case_letters: number,
|
||||||
|
min_number_lower_case_letters: number,
|
||||||
|
min_number_digits: number,
|
||||||
|
min_number_special_characters: number,
|
||||||
|
min_categories_presence: number,
|
||||||
|
}
|
||||||
|
|
||||||
declare interface DataConservationPolicySettings {
|
declare interface DataConservationPolicySettings {
|
||||||
min_inactive_account_lifetime: number,
|
min_inactive_account_lifetime: number,
|
||||||
min_notification_lifetime: number,
|
min_notification_lifetime: number,
|
||||||
@ -14,5 +25,6 @@ declare interface DataConservationPolicySettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare interface StaticServerConfig {
|
declare interface StaticServerConfig {
|
||||||
|
password_policy: PasswordPolicy,
|
||||||
data_conservation_policy: DataConservationPolicySettings;
|
data_conservation_policy: DataConservationPolicySettings;
|
||||||
}
|
}
|
@ -237,6 +237,9 @@ class Dev {
|
|||||||
//Pacman (easter egg) stylesheet
|
//Pacman (easter egg) stylesheet
|
||||||
"css/components/pacman.css",
|
"css/components/pacman.css",
|
||||||
|
|
||||||
|
// Password input
|
||||||
|
"css/components/passwordInput.css",
|
||||||
|
|
||||||
//Pages stylesheets
|
//Pages stylesheets
|
||||||
//User Page
|
//User Page
|
||||||
"css/pages/userPage/main.css",
|
"css/pages/userPage/main.css",
|
||||||
@ -469,8 +472,13 @@ class Dev {
|
|||||||
|
|
||||||
//Pacman component (easter egg)
|
//Pacman component (easter egg)
|
||||||
"js/components/pacman.js",
|
"js/components/pacman.js",
|
||||||
|
|
||||||
|
// Manon
|
||||||
"js/components/manon.js",
|
"js/components/manon.js",
|
||||||
|
|
||||||
|
// Password input
|
||||||
|
"js/components/passwordInput.js",
|
||||||
|
|
||||||
//User scripts
|
//User scripts
|
||||||
"js/user/loginTokens.js",
|
"js/user/loginTokens.js",
|
||||||
"js/user/userLogin.js",
|
"js/user/userLogin.js",
|
||||||
|
Loading…
Reference in New Issue
Block a user