import crypto from 'crypto'; import { getRedisClient } from '../services/redis.js'; // Duración de la sesión en segundos (24 horas) const SESSION_DURATION = 24 * 60 * 60; // Generar token seguro function generateToken() { return crypto.randomBytes(32).toString('hex'); } // Autenticación por token Middleware export async function authMiddleware(req, res, next) { const redisClient = getRedisClient(); if (!redisClient) { return res.status(500).json({ error: 'Redis no está disponible. La autenticación requiere Redis.' }); } const authHeader = req.headers.authorization; if (!authHeader) { return res.status(401).json({ error: 'Authentication required', message: 'Se requiere autenticación para esta operación' }); } const [scheme, token] = authHeader.split(' '); if (scheme !== 'Bearer' || !token) { return res.status(400).json({ error: 'Bad request', message: 'Se requiere un token Bearer' }); } try { // Verificar token en Redis const sessionKey = `session:${token}`; const sessionData = await redisClient.get(sessionKey); if (!sessionData) { return res.status(401).json({ error: 'Invalid token', message: 'Token inválido o sesión expirada' }); } // Parsear datos de sesión const session = JSON.parse(sessionData); // Verificar que el usuario aún existe const userKey = `user:${session.username}`; const userExists = await redisClient.exists(userKey); if (!userExists) { // Eliminar sesión si el usuario ya no existe await redisClient.del(sessionKey); return res.status(401).json({ error: 'Invalid token', message: 'Usuario no encontrado' }); } // Actualizar TTL de la sesión (refresh) await redisClient.expire(sessionKey, SESSION_DURATION); // Autenticación exitosa req.user = { username: session.username }; req.token = token; next(); } catch (error) { console.error('Error en autenticación:', error); res.status(500).json({ error: 'Internal server error', message: 'Error procesando autenticación' }); } } // Alias para mantener compatibilidad export const basicAuthMiddleware = authMiddleware; // Función para crear sesión export async function createSession(username) { const redisClient = getRedisClient(); if (!redisClient) { throw new Error('Redis no está disponible'); } const token = generateToken(); const sessionKey = `session:${token}`; const sessionData = { username, createdAt: new Date().toISOString(), }; // Almacenar sesión en Redis con TTL await redisClient.setEx(sessionKey, SESSION_DURATION, JSON.stringify(sessionData)); return token; } // Función para invalidar sesión export async function invalidateSession(token) { const redisClient = getRedisClient(); if (!redisClient) { return false; } try { const sessionKey = `session:${token}`; await redisClient.del(sessionKey); return true; } catch (error) { console.error('Error invalidando sesión:', error); return false; } } // Función para invalidar todas las sesiones de un usuario export async function invalidateUserSessions(username) { const redisClient = getRedisClient(); if (!redisClient) { return false; } try { // Buscar todas las sesiones del usuario const keys = await redisClient.keys('session:*'); let count = 0; for (const key of keys) { const sessionData = await redisClient.get(key); if (sessionData) { const session = JSON.parse(sessionData); if (session.username === username) { await redisClient.del(key); count++; } } } return count; } catch (error) { console.error('Error invalidando sesiones del usuario:', error); return false; } }