- Increased all sidebar navigation icons from text-sm to text-xl for better visibility - Moved user information and logout button from header to sidebar footer - Added user avatar with name and email in expanded sidebar state - Collapsed sidebar shows avatar icon and logout icon button stacked vertically - Simplified header by removing user badge and logout button - Added version info (v1.0.0) in sidebar footer - Improved responsive design for both collapsed and expanded states
88 lines
2.3 KiB
TypeScript
88 lines
2.3 KiB
TypeScript
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<string> {
|
|
const saltRounds = 10;
|
|
return bcrypt.hash(password, saltRounds);
|
|
}
|
|
|
|
/**
|
|
* Verificar contraseña
|
|
*/
|
|
export async function verifyPassword(password: string, hash: string): Promise<boolean> {
|
|
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 };
|
|
}
|