Fix: share web login session across browser tabs

The login token and role were stored in sessionStorage, which is
isolated per tab, so opening a second tab forced a fresh password
login. Switch every token/role read and write to localStorage so all
tabs on the same origin share the session and a new tab auto-resumes
it on load. Expiry (device_list ok:false) and explicit logout still
clear it as before.

Co-Authored-By: deepseek-v4-pro
This commit is contained in:
yuanyuanxianganddeepseek-v4-pro committed 2026-10-17 22:44:50 +02:00
1 parent 5cea1167be
commit 04f4eb9947
1 file changed
+9 -9
+9 -9
View File
@@ -1743,8 +1743,8 @@
if (!data || !data.token) return false; if (!data || !data.token) return false;
token = data.token; token = data.token;
currentUserRole = data.role || 'viewer'; currentUserRole = data.role || 'viewer';
sessionStorage.setItem('token', token); localStorage.setItem('token', token);
sessionStorage.setItem('role', currentUserRole); localStorage.setItem('role', currentUserRole);
return true; return true;
} catch (e) { } catch (e) {
return false; return false;
@@ -1818,8 +1818,8 @@
if (msg.ok) { if (msg.ok) {
token = msg.token; token = msg.token;
currentUserRole = msg.role || 'viewer'; currentUserRole = msg.role || 'viewer';
sessionStorage.setItem('token', token); localStorage.setItem('token', token);
sessionStorage.setItem('role', currentUserRole); localStorage.setItem('role', currentUserRole);
document.getElementById('login-error').textContent = ''; document.getElementById('login-error').textContent = '';
// Show Users button for admin only // Show Users button for admin only
const usersBtn = document.getElementById('users-btn'); const usersBtn = document.getElementById('users-btn');
@@ -1838,7 +1838,7 @@
if (msg.ok === false) { if (msg.ok === false) {
// Token invalid (e.g., server restarted), go back to login // Token invalid (e.g., server restarted), go back to login
token = null; token = null;
sessionStorage.removeItem('token'); localStorage.removeItem('token');
showPage('login-page'); showPage('login-page');
break; break;
} }
@@ -2691,7 +2691,7 @@
challengeNonce = ''; challengeNonce = '';
connectWebSocket(); // Reconnect immediately connectWebSocket(); // Reconnect immediately
token = null; token = null;
sessionStorage.removeItem('token'); localStorage.removeItem('token');
devices = []; devices = [];
showPage('login-page'); showPage('login-page');
// Hide users button // Hide users button
@@ -4791,9 +4791,9 @@
bindKeyboardBtnEvents(document.getElementById('qc-keyboard')); bindKeyboardBtnEvents(document.getElementById('qc-keyboard'));
bindKeyboardBtnEvents(document.getElementById('btn-keyboard')); bindKeyboardBtnEvents(document.getElementById('btn-keyboard'));
bindKeyboardBtnEvents(document.getElementById('btn-keyboard-bar')); bindKeyboardBtnEvents(document.getElementById('btn-keyboard-bar'));
// Restore token and role from sessionStorage (local-login fallback). // Restore token and role from localStorage (local-login fallback).
token = sessionStorage.getItem('token'); token = localStorage.getItem('token');
currentUserRole = sessionStorage.getItem('role') || 'viewer'; currentUserRole = localStorage.getItem('role') || 'viewer';
// Attempt portal SSO first: if the user is already logged into the // Attempt portal SSO first: if the user is already logged into the
// parent domain, the server bridges the portal session cookie into // parent domain, the server bridges the portal session cookie into
// a YAMA session token so the login form is skipped. On failure // a YAMA session token so the login form is skipped. On failure