photo_server_json_flutter_c.../public/js/logout.js
2026-03-05 17:07:30 +01:00

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();
}
})();