import bcrypt from 'bcrypt'; import jwt from 'jsonwebtoken'; import { env } from '$env/dynamic/private'; const JWT_SECRET = env.JWT_SECRET || 'change-this-secret-in-production-please'; const JWT_EXPIRES_IN = '7d'; // 7 días export interface Usuario { id: number; username: string; email: string; nombre_completo: string; activo: boolean; es_admin: boolean; } export interface SessionPayload { userId: number; username: string; es_admin: boolean; } /** * Hash de contraseña usando bcrypt */ export async function hashPassword(password: string): Promise { const saltRounds = 10; return bcrypt.hash(password, saltRounds); } /** * Verificar contraseña */ export async function verifyPassword(password: string, hash: string): Promise { try { return await bcrypt.compare(password, hash); } catch (error) { console.error('Error verificando contraseña:', error); return false; } } /** * Crear token JWT */ export function createToken(payload: SessionPayload): string { return jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN }); } /** * Verificar y decodificar token JWT */ export function verifyToken(token: string): SessionPayload | null { try { return jwt.verify(token, JWT_SECRET) as SessionPayload; } catch (error) { console.error('Error verificando token:', error); return null; } } /** * Validar fuerza de contraseña */ export function validatePassword(password: string): { valid: boolean; message?: string } { if (password.length < 8) { return { valid: false, message: 'La contraseña debe tener al menos 8 caracteres' }; } if (!/[A-Z]/.test(password)) { return { valid: false, message: 'La contraseña debe contener al menos una mayúscula' }; } if (!/[a-z]/.test(password)) { return { valid: false, message: 'La contraseña debe contener al menos una minúscula' }; } if (!/[0-9]/.test(password)) { return { valid: false, message: 'La contraseña debe contener al menos un número' }; } if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) { return { valid: false, message: 'La contraseña debe contener al menos un carácter especial' }; } return { valid: true }; }