Files
linkedsign/backend/src/modules/auth/auth.validator.js
T

104 lines
3.1 KiB
JavaScript

const Joi = require('joi');
const isStrongPassword = (value, helpers) => {
const rules = [
{ test: value.length >= 8, message: 'at least 8 characters' },
{ test: /[A-Z]/.test(value), message: 'one uppercase letter' },
{ test: /[a-z]/.test(value), message: 'one lowercase letter' },
{ test: /\d/.test(value), message: 'one number' },
{ test: /[^A-Za-z0-9]/.test(value), message: 'one special character' },
];
const missing = rules.filter((rule) => !rule.test).map((rule) => rule.message);
if (missing.length > 0) {
return helpers.message(`Password must include ${missing.join(', ')}.`);
}
return value;
};
const passwordRuleCheckers = [
{ test: (value) => value.length >= 8, label: 'al menos 8 caracteres' },
{ test: (value) => /[A-Z]/.test(value), label: 'una mayúscula' },
{ test: (value) => /[a-z]/.test(value), label: 'una minúscula' },
{ test: (value) => /\d/.test(value), label: 'un número' },
{ test: (value) => /[^A-Za-z0-9]/.test(value), label: 'un carácter especial' },
];
const getPasswordIssues = (value = '') => passwordRuleCheckers
.filter((rule) => !rule.test(value))
.map((rule) => rule.label);
const loginSchema = Joi.object({
email: Joi.string().email().required(),
password: Joi.string().required(),
});
const refreshSchema = Joi.object({
refreshToken: Joi.string().optional(),
});
const changePasswordSchema = Joi.object({
currentPassword: Joi.string().required(),
newPassword: Joi.string().max(100).required().custom(isStrongPassword),
});
const unlockAccountSchema = Joi.object({
certPassword: Joi.string().required(),
newPassword: Joi.string().max(100).required().custom(isStrongPassword),
});
const validateRegisterMultipart = (req, res, next) => {
const { email, password, certPassword, consentAccepted } = req.body;
const issues = [];
if (!email || Joi.string().email().validate(email).error) {
issues.push('Correo electrónico inválido');
}
if (!password) {
issues.push('La contraseña es obligatoria');
} else {
const passwordIssues = getPasswordIssues(password);
if (passwordIssues.length > 0) {
issues.push(`La contraseña debe incluir ${passwordIssues.join(', ')}`);
}
}
if (!certPassword) {
issues.push('La contraseña del certificado es obligatoria para firmar los documentos legales');
}
if (!req.file) {
issues.push('Debes cargar un certificado P12 o PFX');
}
if (!['true', true, 'on', '1', 1].includes(consentAccepted)) {
issues.push('Debes aceptar los documentos legales para completar el registro');
}
if (issues.length > 0) {
return res.status(400).json({ success: false, data: null, error: issues.join('; ') });
}
return next();
};
const validate = (schema) => (req, res, next) => {
const { error } = schema.validate(req.body, { abortEarly: false });
if (error) {
const messages = error.details.map((d) => d.message);
return res.status(400).json({ success: false, data: null, error: messages.join('; ') });
}
next();
};
module.exports = {
validate,
validateRegisterMultipart,
loginSchema,
refreshSchema,
changePasswordSchema,
unlockAccountSchema,
};