// public/js/logout.js // Gestione logout: chiama /auth/logout, pulisce i token, redirige e programma l'auto-logout a scadenza JWT. // Espone: window.AppAuth.logout({redirect: true|false}) e window.AppAuth.isLoggedIn(). (() => { const AUTH_LOGOUT_ENDPOINT = '/auth/logout'; const KEYS = ['access_token', 'token', 'refresh_token']; // intercetta sia 'token' che 'access_token' // --- Helpers token -------------------------------------------------------- function getAccessToken() { try { return ( localStorage.getItem('access_token') || localStorage.getItem('token') || '' ); } catch { return ''; } } function clearTokens() { try { KEYS.forEach(k => localStorage.removeItem(k)); // Se usi sessionStorage per altro, rimuovi solo chiavi auth (non fare clear totale) // sessionStorage.removeItem('my_auth_state'); // esempio } catch {} } // --- Chiamata server ------------------------------------------------------ async function serverLogout(token) { try { const headers = token ? { 'Authorization': `Bearer ${token}` } : {}; await fetch(AUTH_LOGOUT_ENDPOINT, { method: 'POST', headers }); } catch (err) { // In caso di errore rete, lato client puliamo comunque. console.warn('Logout server fallito (ignoro):', err); } } // --- Redirect ------------------------------------------------------------- function getRedirectFromBtn() { const btn = document.querySelector('[data-logout]'); return btn?.getAttribute('data-redirect') || '/'; } function redirectAfterLogout(redirectUrl) { const target = redirectUrl || '/'; window.location.assign(target); } // --- Auto-logout alla scadenza JWT --------------------------------------- function decodeJwt(token) { try { const base64Url = token.split('.')[1]; if (!base64Url) return null; const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); const jsonPayload = decodeURIComponent( atob(base64).split('').map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join('') ); return JSON.parse(jsonPayload); } catch { return null; } } let autoLogoutTimer = null; function scheduleAutoLogout() { clearTimeout(autoLogoutTimer); const token = getAccessToken(); if (!token) return; const payload = decodeJwt(token); const expSec = payload?.exp; if (!expSec) return; const msToExp = expSec * 1000 - Date.now(); if (msToExp <= 0) { // già scaduto → logout immediato doLogout({ redirect: true }); return; } autoLogoutTimer = setTimeout(() => { doLogout({ redirect: true }); }, msToExp); } // --- UI helpers ----------------------------------------------------------- function setButtonsDisabled(disabled) { document.querySelectorAll('[data-logout]').forEach(btn => { btn.disabled = disabled; btn.setAttribute('aria-busy', disabled ? 'true' : 'false'); }); } // --- Azione principale ---------------------------------------------------- async function doLogout({ redirect = true } = {}) { const token = getAccessToken(); setButtonsDisabled(true); // 1) Revoca lato server (denylist) se possibile await serverLogout(token); // 2) Pulizia lato client clearTokens(); // 3) Chiudi eventuali media globali try { window.player?.pause?.(); } catch {} // 4) Notifica globale (se vuoi ascoltarla altrove) try { window.dispatchEvent(new CustomEvent('logout:success')); } catch {} // 5) Redirect if (redirect) redirectAfterLogout(getRedirectFromBtn()); setButtonsDisabled(false); } // --- Click handler -------------------------------------------------------- function bindLogoutButtons() { document.querySelectorAll('[data-logout]').forEach(btn => { btn.addEventListener('click', async (e) => { e.preventDefault(); if (btn.disabled) return; // evita doppi click await doLogout({ redirect: true }); }); }); } // --- Public API ----------------------------------------------------------- window.AppAuth = Object.freeze({ logout: (opts) => doLogout(opts), isLoggedIn: () => !!getAccessToken() }); // --- Init ----------------------------------------------------------------- function init() { bindLogoutButtons(); scheduleAutoLogout(); // Opzionale: nascondi il bottone se non loggato document.querySelectorAll('[data-logout]').forEach(btn => { if (!window.AppAuth.isLoggedIn()) btn.style.display = 'none'; }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();