Skip to content

Commit 838451e

Browse files
navidshadclaude
andcommitted
fix: #86exgqfpu skip token writes to host LS on dashboard origins
The extension's content scripts (nibble, console-crane) inject @modular-rest/client into every page. Because content scripts share localStorage with the host, modular-rest's saveSession (and our explicit cache write) was overwriting the dashboard's own `token` localStorage key on subturtle.app and localhost:3000 — wiping the user's session and forcing them back to /auth/login on the next reload or new tab. Patch Storage.prototype.setItem/removeItem at module load (before @modular-rest/client is imported) to no-op on `token` writes when the host is the dashboard. Extension auth still works via chrome.storage.sync; we only lose the per-page LS cache on dashboard origins (one extra /user/loginAnonymous call per content-script mount, which is negligible). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6a6cb72 commit 838451e

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

src/plugins/modular-rest.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,43 @@
1+
// IMPORTANT: must precede any import that may touch localStorage at module load.
2+
// Content scripts run in an "isolated world" that shares localStorage with the
3+
// host page. The dashboard at *.subturtle.app and localhost:3000 (dev) uses
4+
// `token` as its own localStorage key for the user's session — when the
5+
// extension's modular-rest client (or our explicit cache write below) writes
6+
// the extension's anonymous token there, it clobbers the dashboard user's
7+
// session and bounces them to /auth/login on the next reload or new tab.
8+
//
9+
// Block 'token' writes/removes from the content-script side on those origins.
10+
// The extension already persists tokens to chrome.storage.sync via the
11+
// background script, so losing the per-page localStorage cache only costs
12+
// one extra /user/loginAnonymous call per content-script mount on dashboard
13+
// origins — it does NOT break extension auth.
14+
function isDashboardOrigin(): boolean {
15+
if (typeof window === "undefined") return false;
16+
const host = window.location.hostname;
17+
const port = window.location.port;
18+
return (
19+
(host === "localhost" && port === "3000") ||
20+
host === "subturtle.app" ||
21+
host === "www.subturtle.app" ||
22+
host === "dashboard.subturtle.app" ||
23+
host === "www.dashboard.subturtle.app"
24+
);
25+
}
26+
27+
if (typeof Storage !== "undefined" && isDashboardOrigin()) {
28+
const origSet = Storage.prototype.setItem;
29+
const origRm = Storage.prototype.removeItem;
30+
Storage.prototype.setItem = function (k: string, v: string) {
31+
// Only suppress writes to localStorage on the dashboard, never sessionStorage.
32+
if (this === window.localStorage && k === "token") return;
33+
return origSet.call(this, k, v);
34+
};
35+
Storage.prototype.removeItem = function (k: string) {
36+
if (this === window.localStorage && k === "token") return;
37+
return origRm.call(this, k);
38+
};
39+
}
40+
141
import { GlobalOptions, authentication } from "@modular-rest/client";
242

343
import { sendMessage, sendMessageToTabs } from "../common/helper/massage";

0 commit comments

Comments
 (0)