fix(auth): a tab acts only as the account it was built for, and the review's other findings
A tab names the account it was claimed for on every request, beacon and upload (X-Siftlode-Expect-Account); current_user and /auth/logout refuse a mismatch with 401 account_changed and keep the session, so a tab left showing the account signed in before reloads instead of writing to the new one. /auth/login clears a connect marker left by an abandoned connect, and a link completes only on a session that still holds. The prefs merge reads the row under a lock. A tab's sessionStorage records its own owner. A page the account loses is given up, address bar and remembered page included. The panel layouts are preferences; the storage contract also refuses a key handed to the Storage API or to usePref outside its kind. A refused sign-in as someone else and a failed sign-out say so. The chromium-only e2e specs are in the gate register, the member walk waits for its requests, and devices.spec checks the save itself.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
// The request layer, the notification store and the error boundary all log through lib/log.ts, so
|
||||
// log.ts must not reach any of them at runtime: the import would be a cycle, and the module that
|
||||
// logs a failure would load the one that failed. A type-only import is erased, so it does not count.
|
||||
// The comment in log.ts said this for a long time while nothing checked it.
|
||||
|
||||
const LIB = new URL("./", import.meta.url);
|
||||
const ALLOWED = ["log.ts", "storage.ts", "version.ts"];
|
||||
|
||||
/** The app modules `file` imports at runtime (relative, not `import type`), as lib/ file names. */
|
||||
function runtimeImports(file: string): string[] {
|
||||
const text = readFileSync(new URL(file, LIB), "utf-8");
|
||||
return [...text.matchAll(/^import\s+(?!type\b)[^;]*?from\s+"(\.[^"]+)";/gms)].map(
|
||||
(m) => `${m[1]!.replace(/^\.\//, "")}.ts`,
|
||||
);
|
||||
}
|
||||
|
||||
describe("lib/log.ts", () => {
|
||||
it("reaches only the build stamp and the key registry at runtime", () => {
|
||||
const seen = new Set<string>();
|
||||
const queue = ["log.ts"];
|
||||
while (queue.length) {
|
||||
const file = queue.pop()!;
|
||||
if (seen.has(file)) continue;
|
||||
seen.add(file);
|
||||
if (ALLOWED.includes(file)) queue.push(...runtimeImports(file));
|
||||
}
|
||||
expect([...seen].sort()).toEqual([...ALLOWED].sort());
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user