From 2bd7bb67fe1dadd5dfd4c8a7c8363da0663d3bcb Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Tue, 15 Sep 2026 15:28:19 -0700 Subject: [PATCH] Keep Log In working after a saved session expires --- system/public/aesthetic.computer/boot.mjs | 18 ++--- tests/boot-login.test.mjs | 90 +++++++++++++++++++++++ 2 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 tests/boot-login.test.mjs diff --git a/system/public/aesthetic.computer/boot.mjs b/system/public/aesthetic.computer/boot.mjs index dc34adcb92..eb49285a76 100644 --- a/system/public/aesthetic.computer/boot.mjs +++ b/system/public/aesthetic.computer/boot.mjs @@ -1466,8 +1466,9 @@ if (!sandboxed && !localStorageBlocked) { // If noauth mode OR no Auth0 cache found, skip auth entirely const skipAuth = window.acNOAUTH || (!likelyLoggedIn && !sandboxed && !location.search.includes('code=') && !location.search.includes('state=')); -// Define login/logout functions when skipping initial auth, for on-demand login -if (skipAuth && !sandboxed && !window.acNOAUTH) { +// Login must survive a failed or expired saved session, including early returns +// from the restore flow below. Install it before attempting authentication. +if (!sandboxed && !window.acNOAUTH) { window.acLOGIN = async (mode) => { // Lazy-load Auth0 if not already loaded if (!window.auth0Client) { @@ -1477,9 +1478,14 @@ if (skipAuth && !sandboxed && !window.acNOAUTH) { } const opts = { prompt: "login" }; if (mode === "signup") opts.screen_hint = mode; - window.auth0Client.loginWithRedirect({ authorizationParams: opts }); + // An explicit login replaces any session supplied by an embedding host. + // Otherwise an expired session-aesthetic masks the fresh Auth0 callback. + safeLocalStorageRemove("session-aesthetic"); + return window.auth0Client.loginWithRedirect({ authorizationParams: opts }); }; +} +if (skipAuth && !sandboxed && !window.acNOAUTH) { window.acLOGOUT = () => { console.log("⚠️ Not logged in, nothing to log out from."); }; @@ -1707,12 +1713,6 @@ if (!sandboxed && !skipAuth) { } } - window.acLOGIN = async (mode) => { - const opts = { prompt: "login" }; // Never skip the login screen. - if (mode === "signup") opts.screen_hint = mode; - auth0Client.loginWithRedirect({ authorizationParams: opts }); - }; - if (location.pathname === "/hi") window.acLOGIN(); // Redirect to signup with a query parameter. diff --git a/tests/boot-login.test.mjs b/tests/boot-login.test.mjs new file mode 100644 index 0000000000..53078cad49 --- /dev/null +++ b/tests/boot-login.test.mjs @@ -0,0 +1,90 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import test from "node:test"; +import vm from "node:vm"; + +// Exercise the boot authentication flow without starting the canvas runtime. +const source = readFileSync(new URL("../system/public/aesthetic.computer/boot.mjs", import.meta.url), "utf8"); +const auth = source.slice(source.indexOf("// noauth mode should skip"), source.indexOf("// Incoming window-message responder")); +const tick = () => new Promise(resolve => setImmediate(resolve)); + +async function boot({ cached = false, session, scriptFails = false, noauth = false } = {}) { + const storage = new Map(); + if (cached) storage.set("@@auth0spajs@@::test", "{}"); + if (session) storage.set("session-aesthetic", session); + const messages = [], redirects = []; + let failScript = scriptFails; + const client = { + isAuthenticated: async () => false, + loginWithRedirect: async options => { redirects.push(options); return "redirected"; }, + }; + const window = { + origin: "https://aesthetic.computer", acNOAUTH: noauth, + location: { origin: "https://aesthetic.computer", href: "https://aesthetic.computer/" }, + acAuthTiming: { durations: {}, computeDurations() {}, summary() {} }, + acDISK_SEND: message => messages.push(message), + postMessage() {}, + }; + window.top = window; + window.parent = window; + const context = vm.createContext({ + window, console: { log() {}, error() {} }, performance, + localStorageBlocked: false, sessionStorageBlocked: false, previewOrIcon: false, + localStorage: { get length() { return storage.size; }, key: i => [...storage.keys()][i] }, + safeLocalStorageGet: key => storage.get(key), + safeLocalStorageSet: (key, value) => storage.set(key, value), + safeLocalStorageRemove: key => storage.delete(key), + location: { search: "", pathname: "/" }, + document: { + createElement: () => ({}), + head: { appendChild(script) { + queueMicrotask(() => { + if (failScript) { failScript = false; script.onerror(); } + else { window.auth0 = { createAuth0Client: async () => client }; script.onload(); } + }); + } }, + }, + bootLog() {}, extractLegitimateParams: () => new URLSearchParams(), + atob, fetch: async () => ({ ok: false }), + }); + vm.runInContext(auth, context); + await tick(); + return { window, storage, messages, redirects }; +} + +const expiredSession = btoa(JSON.stringify({ accessToken: "expired-test-token", account: { id: "test" } })); + +test("expired embedded session still lets the visitor log in", async () => { + const state = await boot({ cached: true, session: expiredSession }); + assert.equal(state.messages.at(-1).content.user, null); + assert.equal(await state.window.acLOGIN(), "redirected"); + assert.equal(state.redirects[0].authorizationParams.prompt, "login"); + assert.equal(state.storage.has("session-aesthetic"), false); +}); + +test("malformed saved session can be replaced by signup", async () => { + const state = await boot({ cached: true, session: "not base64!" }); + assert.equal(state.messages.at(-1).content.user, null); + await state.window.acLOGIN("signup"); + assert.equal(state.redirects[0].authorizationParams.screen_hint, "signup"); + assert.equal(state.storage.has("session-aesthetic"), false); +}); + +test("login retries a failed Auth0 script load", async () => { + const state = await boot({ cached: true, scriptFails: true }); + assert.equal(state.messages.at(-1).content.user, null); + await state.window.acLOGIN(); + assert.equal(state.redirects.length, 1); +}); + +test("anonymous boot keeps Auth0 lazy until login", async () => { + const state = await boot(); + assert.equal(state.window.auth0Client, undefined); + await state.window.acLOGIN(); + assert.equal(state.redirects.length, 1); +}); + +test("noauth embeds do not enable login", async () => { + const state = await boot({ noauth: true }); + assert.equal(state.window.acLOGIN, undefined); +}); -- 2.51.2