Persist biometric access
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
const bcrypt = require('bcrypt');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const crypto = require('crypto');
|
||||
const authRepository = require('./auth.repository');
|
||||
const passwordChangeRepository = require('./password-change.repository');
|
||||
const auditService = require('../audit/audit.service');
|
||||
@@ -15,6 +16,7 @@ const env = require('../../config/env');
|
||||
|
||||
const SALT_ROUNDS = 12;
|
||||
const MAX_FAILED_LOGIN_ATTEMPTS = 3;
|
||||
const createBiometricToken = () => crypto.randomBytes(48).toString('hex');
|
||||
|
||||
const buildDisplayNameFromEmail = (email) => {
|
||||
const localPart = String(email).split('@')[0] || 'Usuario';
|
||||
@@ -300,11 +302,80 @@ const refresh = async (token) => {
|
||||
return { accessToken, refreshToken: newRefreshToken };
|
||||
};
|
||||
|
||||
const issueBiometricToken = async (userId) => {
|
||||
const user = await authRepository.findAuthUserById(userId);
|
||||
if (!user || !user.is_active) {
|
||||
const err = new Error('User not found.');
|
||||
err.statusCode = 404;
|
||||
throw err;
|
||||
}
|
||||
|
||||
const biometricToken = createBiometricToken();
|
||||
const expiresAt = new Date(Date.now() + env.jwt.biometricExpiresMs);
|
||||
await authRepository.saveBiometricToken(userId, biometricToken, expiresAt);
|
||||
return { biometricToken };
|
||||
};
|
||||
|
||||
const biometricLogin = async (token) => {
|
||||
if (!token) {
|
||||
const err = new Error('La sesión biométrica expiró. Inicia sesión con correo y contraseña.');
|
||||
err.statusCode = 401;
|
||||
err.code = 'BIOMETRIC_EXPIRED';
|
||||
throw err;
|
||||
}
|
||||
|
||||
const record = await authRepository.findBiometricToken(token);
|
||||
if (!record) {
|
||||
await authRepository.deleteBiometricToken(token);
|
||||
const err = new Error('La sesión biométrica expiró. Inicia sesión con correo y contraseña.');
|
||||
err.statusCode = 401;
|
||||
err.code = 'BIOMETRIC_EXPIRED';
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (!record.is_active) {
|
||||
await authRepository.deleteUserBiometricTokens(record.user_id);
|
||||
const err = new Error('La sesión biométrica fue invalidada. Inicia sesión con correo y contraseña.');
|
||||
err.statusCode = 401;
|
||||
err.code = 'BIOMETRIC_INVALIDATED';
|
||||
throw err;
|
||||
}
|
||||
|
||||
await authRepository.deleteBiometricToken(token);
|
||||
|
||||
const payload = { sub: record.uid, email: record.email, role: record.role, name: record.name };
|
||||
const accessToken = signAccess(payload);
|
||||
const refreshToken = signRefresh(payload);
|
||||
const biometricToken = createBiometricToken();
|
||||
|
||||
await authRepository.saveRefreshToken(record.uid, refreshToken, new Date(Date.now() + env.jwt.refreshExpiresMs));
|
||||
await authRepository.saveBiometricToken(record.uid, biometricToken, new Date(Date.now() + env.jwt.biometricExpiresMs));
|
||||
|
||||
const signaturePreferences = await usersService.getSignaturePreferences(record.uid);
|
||||
|
||||
return {
|
||||
accessToken,
|
||||
refreshToken,
|
||||
biometricToken,
|
||||
user: {
|
||||
id: record.uid,
|
||||
name: record.name,
|
||||
email: record.email,
|
||||
role: record.role,
|
||||
signaturePreferences,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const logout = async (token) => {
|
||||
if (!token) return;
|
||||
await authRepository.deleteRefreshToken(token);
|
||||
};
|
||||
|
||||
const revokeBiometricToken = async (userId) => {
|
||||
await authRepository.deleteUserBiometricTokens(userId);
|
||||
};
|
||||
|
||||
const changePassword = async (userId, { currentPassword, newPassword }, context = {}) => {
|
||||
const user = await authRepository.findAuthUserById(userId);
|
||||
if (!user || !user.is_active) {
|
||||
@@ -449,6 +520,8 @@ const confirmPasswordChange = async (token) => {
|
||||
}
|
||||
|
||||
await authRepository.updatePassword(request.userId, request.passwordHash);
|
||||
await authRepository.deleteUserRefreshTokens(request.userId);
|
||||
await authRepository.deleteUserBiometricTokens(request.userId);
|
||||
if (request.source === 'account_unlock') {
|
||||
await authRepository.clearAccountLock(request.userId);
|
||||
}
|
||||
@@ -485,7 +558,10 @@ module.exports = {
|
||||
register,
|
||||
login,
|
||||
refresh,
|
||||
issueBiometricToken,
|
||||
biometricLogin,
|
||||
logout,
|
||||
revokeBiometricToken,
|
||||
verifyEmail,
|
||||
changePassword,
|
||||
confirmPasswordChange,
|
||||
|
||||
Reference in New Issue
Block a user