feat: autorregistro con verificacion de correo + aprobacion, superadmin y SMTP
- POST /api/auth/register: primer usuario del sistema -> superadmin con sesion directa (bootstrap, sin correo ni aprobacion); los siguientes quedan pending_verification y reciben un correo con enlace de un solo uso (24h). - GET /api/auth/verify-email: pasa a pending_approval y notifica in-app a los admin/superadmin activos. - admin/superadmin aprueban (POST /api/users/:id/approve, eligen rol y departamento) o rechazan (POST /api/users/:id/reject, borra y audita el email) desde Organizacion -> Usuarios (nuevo badge de estado + acciones). - login() da mensaje especifico segun el status de la cuenta en vez del generico "credenciales invalidas". - Recuperacion de clave (forgot/reset-password): respuesta siempre generica, token de 1 hora de un solo uso. - Nuevo modulo settings: SMTP configurable SOLO por superadmin desde Configuracion -> Correo (SMTP); clave cifrada AES-256-GCM (ENCRYPTION_KEY) en la tabla system_settings, nunca expuesta por la API. sendMail() degrada a modo dev (loguea en vez de enviar) si no hay SMTP configurado, y nunca deja que un fallo de envio tumbe al que lo llama. - Migracion 002_registration_and_smtp.sql: rol superadmin, columnas de ciclo de vida en users (status, tokens), tabla system_settings, y promueve al usuario mas antiguo del sistema a superadmin. - Fix: React.StrictMode disparaba el efecto de VerifyEmailPage dos veces; la segunda llamada (token ya consumido) mostraba "enlace invalido" pese a que la verificacion ya habia funcionado. Se agrega una guarda por token. - Fix (deuda tecnica v1.0.0): se reordena el montaje de rutas en app.js — subtasksRoutes (mount generico en /api) va al final, para no interceptar con su requireAuth interno una request sin token dirigida a un router mas especifico registrado despues. - Documentacion actualizada: AGENTS.md, SPEC.md, API.md, BASE_DE_DATOS.md, CONFIGURACION.md, ESTADO.md, CHANGELOG.md. Version 1.1.0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -106,14 +106,27 @@ Adaptación web (no es una app empaquetada, corre en pestaña de navegador):
|
||||
## Seguridad (proyecto con auth/usuarios)
|
||||
|
||||
- Permisos validados SIEMPRE en el backend, nunca solo en el frontend.
|
||||
- Sin autosuscripción: el administrador crea los usuarios.
|
||||
- Autorregistro con doble candado (decisión posterior al MVP inicial, ver `SPEC.md`): el usuario
|
||||
se crea a sí mismo pero queda `pending_verification` → confirma su correo (token de un solo uso,
|
||||
24h) → `pending_approval` → un `admin`/`superadmin` aprueba (elige rol/departamento) o rechaza
|
||||
(se borra). Solo el usuario más antiguo del sistema es `superadmin` automático (bootstrap, sin
|
||||
correo ni aprobación — no hay quién lo apruebe). El admin sigue pudiendo crear usuarios
|
||||
directamente (ya activos, sin pasar por este flujo) desde Organización → Usuarios.
|
||||
- `401` → el frontend limpia sesión, redirige a login y muestra aviso (ContentDialog).
|
||||
- Cierre de sesión por expiración de JWT.
|
||||
- Auditoría en BD (`audit_log`): usuario, acción, entidad, fecha/hora, detalle.
|
||||
- Credenciales/secretos solo en `.env` (nunca en código); `.env.example` sí se versiona.
|
||||
- Cifrado: bcrypt para contraseñas.
|
||||
- Revalidar `is_active` del usuario en cada request (un JWT firmado no basta).
|
||||
- Credenciales/secretos solo en `.env` (nunca en código); `.env.example` sí se versiona. Excepción:
|
||||
el SMTP del sistema NO vive en `.env` — lo carga el `superadmin` desde Configuración → Correo
|
||||
(SMTP), queda en `system_settings` con la clave cifrada (AES-256-GCM, `ENCRYPTION_KEY`).
|
||||
- Cifrado: bcrypt para contraseñas; AES-256-GCM (`backend/src/utils/crypto.js`) para secretos de
|
||||
terceros guardados en BD (hoy: la clave SMTP).
|
||||
- Revalidar `is_active` del usuario en cada request (un JWT firmado no basta); el login además
|
||||
revisa `status` (`pending_verification`/`pending_approval` dan un mensaje especifico, no login).
|
||||
- SQL siempre parametrizado. Uploads: validar MIME/tamaño, ruta de archivo generada por el servidor.
|
||||
- `forgot-password` responde SIEMPRE genérico (exista o no el correo); el envío de correo nunca
|
||||
debe poder tumbar ni cambiar la respuesta de un endpoint (`sendMail` atrapa sus propios errores).
|
||||
- Sin SMTP configurado, el sistema degrada a modo dev: los correos de verificación/recuperación se
|
||||
loguean en la consola del backend en vez de enviarse (nunca rompe el flujo).
|
||||
|
||||
## Regla de UX para pantallas
|
||||
|
||||
|
||||
Reference in New Issue
Block a user