export function accessTokenKey(resourceKind, resourceSlug) { return `rustpad:access:${resourceKind}:${resourceSlug}`; } export function getAccessToken(resourceKind, resourceSlug) { return localStorage.getItem(accessTokenKey(resourceKind, resourceSlug)) || ""; } export function setAccessToken(resourceKind, resourceSlug, token) { const key = accessTokenKey(resourceKind, resourceSlug); if (token) localStorage.setItem(key, token); else localStorage.removeItem(key); } // Remove plaintext passwords saved by the previous frontend version. for (let i = localStorage.length - 1; i >= 0; i--) { const key = localStorage.key(i); if (key?.startsWith("rustpad:workspace:") && key.endsWith(":password")) localStorage.removeItem(key); } const NICKNAME_KEY = "rustpad:nickname"; const NICKNAME_COOKIE = "rustpad_nickname"; // A session cookie is shared by tabs, but disappears when the browser session // ends. The nickname is not an authentication secret. function getCookie(name) { const prefix = `${name}=`; const item = document.cookie.split("; ").find(value => value.startsWith(prefix)); if (!item) return ""; try { return decodeURIComponent(item.slice(prefix.length)); } catch { return ""; } } function setNicknameCookie(value) { if (value) document.cookie = `${NICKNAME_COOKIE}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`; else document.cookie = `${NICKNAME_COOKIE}=; Path=/; SameSite=Lax; Max-Age=0`; } localStorage.removeItem(NICKNAME_KEY); export function getNickname() { const nickname = sessionStorage.getItem(NICKNAME_KEY) || getCookie(NICKNAME_COOKIE); if (nickname) sessionStorage.setItem(NICKNAME_KEY, nickname); return nickname; } export function setNickname(value) { const nickname = value.trim(); if (nickname) sessionStorage.setItem(NICKNAME_KEY, nickname); else sessionStorage.removeItem(NICKNAME_KEY); setNicknameCookie(nickname); } const AUTH_TOKEN_KEY = "rustpad:auth-token"; // Account sessions must be shared by every tab on this origin. Keep a // compatibility fallback for sessions created by older frontend versions. const legacySessionToken = sessionStorage.getItem(AUTH_TOKEN_KEY); if (legacySessionToken && !localStorage.getItem(AUTH_TOKEN_KEY)) { localStorage.setItem(AUTH_TOKEN_KEY, legacySessionToken); } sessionStorage.removeItem(AUTH_TOKEN_KEY); export function getAuthToken() { return localStorage.getItem(AUTH_TOKEN_KEY) || ""; } export function setAuthSession(session) { localStorage.setItem(AUTH_TOKEN_KEY, session.token); sessionStorage.removeItem(AUTH_TOKEN_KEY); setNickname(session.nickname); } export function clearAuthSession() { localStorage.removeItem(AUTH_TOKEN_KEY); sessionStorage.removeItem(AUTH_TOKEN_KEY); localStorage.removeItem(NICKNAME_KEY); sessionStorage.removeItem(NICKNAME_KEY); setNicknameCookie(""); } export async function resolveIdentity(api, nickname) { const result = await api("/api/auth/identity", { method: "POST", body: JSON.stringify({ nickname, session_token: getAuthToken() || null }) }); setNickname(result.nickname); return result; }