153 lines
No EOL
4.8 KiB
JavaScript
153 lines
No EOL
4.8 KiB
JavaScript
// 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();
|
|
}
|
|
})(); |