Files
rustpad/static/js/session.js
T

93 lines
3.8 KiB
JavaScript

/*
* Copyright (C) 2026 Mateusz Gruszczyński @linuxiarz.pl
* Source-Available Code / Dual-Licensed.
*
* Free for non-commercial and evaluation use under terms of BSL/GPLv3.
* Commercial or production use requires a valid paid license.
* See LICENSE file in repository root for details.
*/
const ACCESS_STORAGE_VERSION_KEY = "rustpad:access-storage-version";
const ACCESS_STORAGE_VERSION = "http-only-cookie-v1";
export function accessTokenKey(resourceKind, resourceSlug) { return `rustpad:access:${resourceKind}:${resourceSlug}`; }
if (localStorage.getItem(ACCESS_STORAGE_VERSION_KEY) !== ACCESS_STORAGE_VERSION) {
for (let i = localStorage.length - 1; i >= 0; i--) {
const key = localStorage.key(i);
if (key?.startsWith("rustpad:access:")) localStorage.removeItem(key);
}
localStorage.setItem(ACCESS_STORAGE_VERSION_KEY, ACCESS_STORAGE_VERSION);
}
export function getAccessToken(resourceKind, resourceSlug) {
return localStorage.getItem(accessTokenKey(resourceKind, resourceSlug)) ? "cookie" : "";
}
export function setAccessToken(resourceKind, resourceSlug, granted) {
const key = accessTokenKey(resourceKind, resourceSlug);
if (granted) localStorage.setItem(key, "1");
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 GUEST_ID_COOKIE = "rustpad_guest_id";
export function getGuestId() {
let guestId = getCookie(GUEST_ID_COOKIE);
if (!/^[a-zA-Z0-9_-]{16,64}$/.test(guestId)) {
guestId = crypto.randomUUID().replaceAll("-", "");
document.cookie = `${GUEST_ID_COOKIE}=${guestId}; Path=/; SameSite=Lax`;
}
return guestId;
}
const AUTH_STATE_KEY = "rustpad:auth-state";
// Remove browser-readable account tokens created by older frontend versions.
localStorage.removeItem("rustpad:auth-token");
sessionStorage.removeItem("rustpad:auth-token");
export function getAuthToken() { return localStorage.getItem(AUTH_STATE_KEY) ? "cookie" : ""; }
export function setAuthSession(session) {
localStorage.setItem(AUTH_STATE_KEY, "1");
setNickname(session.nickname);
}
export function clearAuthSession() {
localStorage.removeItem(AUTH_STATE_KEY);
localStorage.removeItem("rustpad:auth-token");
sessionStorage.removeItem("rustpad:auth-token");
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 }) });
setNickname(result.nickname); return result;
}