a6cc41666e
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
76 lines
2.8 KiB
JavaScript
76 lines
2.8 KiB
JavaScript
import jwt from 'jsonwebtoken';
|
|
import { env } from '../config/env.js';
|
|
import { pool } from '../config/db.js';
|
|
import { fail } from '../utils/http.js';
|
|
import { loadModules } from './modules.js';
|
|
import { validateSession } from '../modules/auth/sessions-service.js';
|
|
|
|
export async function requireAuth(req, res, next) {
|
|
const header = req.headers.authorization || '';
|
|
const token = header.startsWith('Bearer ') ? header.slice(7) : null;
|
|
if (!token) return fail(res, 401, 'No autenticado');
|
|
|
|
let payload;
|
|
try {
|
|
payload = jwt.verify(token, env.jwtSecret);
|
|
} catch {
|
|
return fail(res, 401, 'Token invalido o expirado');
|
|
}
|
|
|
|
// Revalidar en cada request que la cuenta siga activa (un JWT firmado no basta).
|
|
const [rows] = await pool.query(
|
|
`SELECT u.id, u.name, u.email, u.is_active, u.session_version, u.department_id, d.name AS department_name, r.code AS role_code, r.name AS role_name
|
|
FROM users u JOIN roles r ON r.id = u.role_id
|
|
LEFT JOIN departments d ON d.id = u.department_id
|
|
WHERE u.id = ? LIMIT 1`,
|
|
[payload.sub]
|
|
);
|
|
const user = rows[0];
|
|
if (!user || !user.is_active || payload.sv !== user.session_version) return fail(res, 401, 'Sesion invalida o revocada', 'SESSION_REVOKED');
|
|
// Token emitido antes de las sesiones registradas (sin sid): se trata como vencido, no como cerrado.
|
|
if (!payload.sid) return fail(res, 401, 'Sesion vencida');
|
|
const session = await validateSession(payload.sid, user.id);
|
|
if (!session) return fail(res, 401, 'Sesion cerrada o vencida', 'SESSION_REVOKED');
|
|
|
|
req.currentUser = {
|
|
id: user.id,
|
|
name: user.name,
|
|
email: user.email,
|
|
roleCode: user.role_code,
|
|
roleName: user.role_name,
|
|
departmentId: user.department_id,
|
|
departmentName: user.department_name,
|
|
modules: await loadModules(user.id, user.role_code),
|
|
sessionId: session.id,
|
|
sessionPublicId: payload.sid,
|
|
};
|
|
next();
|
|
}
|
|
|
|
export function requireRole(...roleCodes) {
|
|
return (req, res, next) => {
|
|
if (!req.currentUser) return fail(res, 401, 'No autenticado');
|
|
if (!roleCodes.includes(req.currentUser.roleCode)) {
|
|
return fail(res, 403, 'No tienes permisos para esta accion');
|
|
}
|
|
next();
|
|
};
|
|
}
|
|
|
|
export const ROLES = {
|
|
SUPERADMIN: 'superadmin',
|
|
ADMIN: 'admin',
|
|
IT_MANAGER: 'it_manager',
|
|
PROJECT_LEAD: 'project_lead',
|
|
COLLABORATOR: 'collaborator',
|
|
VIEWER: 'viewer',
|
|
};
|
|
|
|
export const CAN_MANAGE_CATALOGS = [ROLES.SUPERADMIN];
|
|
export const CAN_MANAGE_USERS = [ROLES.SUPERADMIN, ROLES.ADMIN];
|
|
export const CAN_MANAGE_SMTP = [ROLES.SUPERADMIN];
|
|
export const CAN_MANAGE_SETTINGS = [ROLES.SUPERADMIN];
|
|
export const CAN_WRITE = [ROLES.SUPERADMIN, ROLES.ADMIN, ROLES.IT_MANAGER, ROLES.PROJECT_LEAD, ROLES.COLLABORATOR];
|
|
export const CAN_EDIT_DEVICES = [ROLES.SUPERADMIN, ROLES.ADMIN, ROLES.IT_MANAGER];
|
|
export const CAN_MANAGE_DEVICES = [ROLES.SUPERADMIN, ROLES.ADMIN];
|