@open-tender/utils
Version:
A library of utils for use with Open Tender applications that utilize our cloud-based Order API.
97 lines (96 loc) • 3.31 kB
JavaScript
/**
* Password validation utility matching backend password policy
*
* Requirements:
* - Minimum 10 characters
* - At least one uppercase letter
* - At least one lowercase letter
* - At least one number
* - At least one special character from allowed set: !@#$%^&_-+=<>
*
* Backend regex: ^[A-Za-z0-9\!\@\#\$\%\^\&\_\-\+\=\<\>]*$
*/
// Constants
const MIN_LENGTH = 10;
const ALLOWED_SPECIAL_CHARS = '!@#$%^&_-+=<>';
// Regex patterns - DRY principle
const REGEX = {
ALLOWED_CHARS: /^[A-Za-z0-9!@#$%^&_\-+=<>]*$/,
UPPERCASE: /[A-Z]/,
LOWERCASE: /[a-z]/,
NUMBER: /[0-9]/,
SPECIAL_CHAR: /[!@#$%^&_\-+=<>]/,
};
// Error messages - DRY principle
const ERROR_MESSAGES = {
MIN_LENGTH: `Password must be at least ${MIN_LENGTH} characters long`,
INVALID_CHARS: `Password contains invalid characters. Only letters, numbers, and (${ALLOWED_SPECIAL_CHARS}) are allowed`,
UPPERCASE: 'Password must include at least one uppercase letter',
LOWERCASE: 'Password must include at least one lowercase letter',
NUMBER: 'Password must include at least one number',
SPECIAL_CHAR: `Password must include at least one special character (${ALLOWED_SPECIAL_CHARS})`,
};
// SRP: Individual validation functions
const hasMinLength = (password) => password.length >= MIN_LENGTH;
const hasOnlyAllowedChars = (password) => REGEX.ALLOWED_CHARS.test(password);
const hasUppercase = (password) => REGEX.UPPERCASE.test(password);
const hasLowercase = (password) => REGEX.LOWERCASE.test(password);
const hasNumber = (password) => REGEX.NUMBER.test(password);
const hasSpecialChar = (password) => REGEX.SPECIAL_CHAR.test(password);
export const validatePassword = (password) => {
const errors = [];
if (!password || !hasMinLength(password)) {
errors.push(ERROR_MESSAGES.MIN_LENGTH);
}
if (!hasOnlyAllowedChars(password)) {
errors.push(ERROR_MESSAGES.INVALID_CHARS);
}
if (!hasUppercase(password)) {
errors.push(ERROR_MESSAGES.UPPERCASE);
}
if (!hasLowercase(password)) {
errors.push(ERROR_MESSAGES.LOWERCASE);
}
if (!hasNumber(password)) {
errors.push(ERROR_MESSAGES.NUMBER);
}
if (!hasSpecialChar(password)) {
errors.push(ERROR_MESSAGES.SPECIAL_CHAR);
}
return {
isValid: errors.length === 0,
errors,
};
};
export const getPasswordRequirements = (password) => {
const requirements = [
{
met: hasMinLength(password),
message: `At least ${MIN_LENGTH} characters`,
},
{
met: hasUppercase(password),
message: 'One uppercase letter',
},
{
met: hasLowercase(password),
message: 'One lowercase letter',
},
{
met: hasNumber(password),
message: 'One number',
},
{
met: hasOnlyAllowedChars(password) && hasSpecialChar(password),
message: `One special character from: ${ALLOWED_SPECIAL_CHARS}`,
},
];
return requirements;
};
export const getPasswordErrorMessage = (password) => {
const validation = validatePassword(password);
if (validation.isValid)
return '';
// Return all errors as a single message
return validation.errors.join('. ');
};