feat(api): login web con sesiones, guard global y freno a fuerza bruta

- POST /api/auth/login (U_WEB_USER/U_WEB_PASS de EmployeesInfo), logout y me.
- Token opaco (32 bytes) en Authorization: Bearer; una sesión por usuario,
  timeout deslizante configurable (SESSION_TIMEOUT_MINUTES, 30 por defecto).
- AuthGuard global con @Public(); /health/sap ahora exige sesión.
- Usuario inexistente y contraseña errónea devuelven el mismo mensaje;
  comparación en tiempo constante; filtro OData escapado; se rechazan
  U_WEB_USER duplicados.
- LoginAttemptsService: 429 tras 5 fallos por usuario o 20 por IP (15 min).
- Tests unitarios y e2e con SAP simulado.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-13 18:38:11 -05:00
1 parent bb4acb5510
commit 079cedbaed
18 files changed
+673 -6

No files matched your search

+4 -2
View File
@@ -19,6 +19,8 @@ export const envSchema = z
.filter(Boolean),
),
LOG_LEVEL: z.enum(['error', 'warn', 'log', 'debug', 'verbose']).default('log'),
// Inactividad tras la cual caduca la sesión web (deslizante).
SESSION_TIMEOUT_MINUTES: z.coerce.number().int().positive().default(30),
// --- SAP Business One Service Layer ---
SAPB1_SL_URL: z
@@ -29,8 +31,8 @@ export const envSchema = z
SAPB1_SL_PASSWORD: z.string().min(1),
SAPB1_SL_TIMEOUT_MS: z.coerce.number().int().positive().default(15000),
// Peticiones simultáneas permitidas hacia el Service Layer; el resto se encola.
// Medido en SAP10: con más de ~2 en paralelo el Service Layer retrasa ~7 s cada
// petición extra, mientras que en serie cada una tarda ~60 ms. Default: 1.
// Medido en SAP10 (12 peticiones): con 1 -> 0.6 s en total; con 2 ya tarda 7.5 s y con
// 4, 22 s (el Service Layer retrasa ~7 s por cada petición paralela extra). Default: 1.
SAPB1_SL_MAX_CONCURRENCY: z.coerce.number().int().positive().default(1),
// CA adicional de confianza (PEM): certificado autofirmado del Service
// Layer o CA de un firewall que inspecciona SSL. Opcional.