// Servicio de autenticación para gestionar tokens import { getDeviceFingerprint } from './fingerprint.js'; const AUTH_STORAGE_KEY = 'wallabicher_token'; const USERNAME_STORAGE_KEY = 'wallabicher_username'; const ROLE_STORAGE_KEY = 'wallabicher_role'; class AuthService { constructor() { this.token = this.loadToken(); this.username = this.loadUsername(); this.role = this.loadRole(); } // Cargar token desde localStorage loadToken() { try { return localStorage.getItem(AUTH_STORAGE_KEY) || ''; } catch (error) { console.error('Error cargando token:', error); return ''; } } // Cargar username desde localStorage loadUsername() { try { return localStorage.getItem(USERNAME_STORAGE_KEY) || ''; } catch (error) { console.error('Error cargando username:', error); return ''; } } // Guardar token, username y role en localStorage saveSession(token, username, role = 'user') { try { this.token = token; this.username = username; this.role = role; localStorage.setItem(AUTH_STORAGE_KEY, token); localStorage.setItem(USERNAME_STORAGE_KEY, username); localStorage.setItem(ROLE_STORAGE_KEY, role); return true; } catch (error) { console.error('Error guardando sesión:', error); return false; } } // Cargar role desde localStorage loadRole() { try { return localStorage.getItem(ROLE_STORAGE_KEY) || 'user'; } catch (error) { console.error('Error cargando role:', error); return 'user'; } } // Eliminar token, username y role clearSession() { try { this.token = ''; this.username = ''; this.role = 'user'; localStorage.removeItem(AUTH_STORAGE_KEY); localStorage.removeItem(USERNAME_STORAGE_KEY); localStorage.removeItem(ROLE_STORAGE_KEY); return true; } catch (error) { console.error('Error eliminando sesión:', error); return false; } } // Obtener token actual getToken() { return this.token; } // Obtener username actual getUsername() { return this.username; } // Obtener role actual getRole() { return this.role; } // Verificar si es admin isAdmin() { return this.role === 'admin'; } // Verificar si hay sesión activa (token guardado) hasCredentials() { return !!this.token; } // Generar header de autenticación Bearer getAuthHeader() { if (!this.token) { return null; } return `Bearer ${this.token}`; } // Hacer login (llamar al endpoint de login) async login(username, password) { try { // Obtener fingerprint del dispositivo let fingerprintData = null; try { fingerprintData = await getDeviceFingerprint(); } catch (error) { console.warn('Error obteniendo fingerprint, continuando sin él:', error); } const requestBody = { username, password, }; // Agregar fingerprint si está disponible if (fingerprintData) { requestBody.fingerprint = fingerprintData.fingerprint; requestBody.deviceInfo = fingerprintData.deviceInfo; } const response = await fetch('/api/users/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(requestBody), }); const data = await response.json(); if (!response.ok) { throw new Error(data.error || 'Error en login'); } if (data.success && data.token) { const role = data.role || 'user'; this.saveSession(data.token, data.username, role); return { success: true, token: data.token, username: data.username, role }; } throw new Error('Respuesta inválida del servidor'); } catch (error) { console.error('Error en login:', error); throw error; } } // Hacer logout (llamar al endpoint de logout) async logout() { try { const token = this.token; if (token) { try { await fetch('/api/users/logout', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, }); } catch (error) { // Si falla el logout en el servidor, aún así limpiar localmente console.error('Error al cerrar sesión en el servidor:', error); } } this.clearSession(); return true; } catch (error) { console.error('Error en logout:', error); this.clearSession(); // Limpiar localmente de todas formas return false; } } // Verificar si el token sigue siendo válido async validateSession() { if (!this.token) { return false; } try { const response = await fetch('/api/users/me', { method: 'GET', headers: { 'Authorization': `Bearer ${this.token}`, }, }); if (response.ok) { const data = await response.json(); if (data.success && data.authenticated) { // Actualizar role si está disponible if (data.role) { this.role = data.role; localStorage.setItem(ROLE_STORAGE_KEY, data.role); } return true; } } // Si el token es inválido, limpiar sesión if (response.status === 401) { this.clearSession(); } return false; } catch (error) { console.error('Error validando sesión:', error); return false; } } } // Exportar instancia singleton const authService = new AuthService(); export default authService;