refactor(frontend): one account per browser, its local state under plain keys
The per-tab account pin, the X-Siftlode-Account header and ?account= go: the session cookie alone says who is asking. localStorage keys lose their account suffix; the browser records whose state it holds (siftlode.owner), BootGate hands it to the account the server answered as, and a different account starts from a clean slate (the public /watch keys stay). The first boot moves the account's old per-account copies onto the plain keys and drops other accounts' copies. Until the claim, and after another tab claimed the browser for someone else, the account helpers read and write nothing. The account panel lists no other accounts: "Add another account" becomes "Sign in as someone else" (Google's account chooser; the pick replaces this account, a cancel keeps it), shown where Google sign-in is configured.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// The Files library: a user's done files, the folders they sit in, and the file itself
|
||||
// (backend `routes/files.py`). A library file is a done download job, so it is typed as one.
|
||||
import { getActiveAccount, req, uploadReq } from "./core";
|
||||
import { req, uploadReq } from "./core";
|
||||
import type { DownloadJob } from "./downloads";
|
||||
|
||||
// "source": filled by where a file came from (YouTube, Plex, a site, uploads); "own": made by the user;
|
||||
@@ -144,19 +144,10 @@ export const filesApi = {
|
||||
headers,
|
||||
});
|
||||
},
|
||||
// A plain <a> navigation can't send the X-Siftlode-Account header, so pass the active account via
|
||||
// ?account= (the server honours it only for an account in this browser's wallet) — otherwise the
|
||||
// file resolves to the session-default account and 404s for a per-tab account's file.
|
||||
fileUrl: (id: number): string => {
|
||||
const a = getActiveAccount();
|
||||
return a != null ? `/api/files/${id}/file?account=${a}` : `/api/files/${id}/file`;
|
||||
},
|
||||
// The viewer's copy of an image or a PDF (`/preview`, sandboxed): an <img> / <iframe> source, so it
|
||||
// carries the account the same way.
|
||||
previewUrl: (id: number): string => {
|
||||
const a = getActiveAccount();
|
||||
return a != null ? `/api/files/${id}/preview?account=${a}` : `/api/files/${id}/preview`;
|
||||
},
|
||||
// The file itself, for a plain <a> navigation.
|
||||
fileUrl: (id: number): string => `/api/files/${id}/file`,
|
||||
// The viewer's copy of an image or a PDF (`/preview`, sandboxed): an <img> / <iframe> source.
|
||||
previewUrl: (id: number): string => `/api/files/${id}/preview`,
|
||||
// A text file's head as text, and whether the server cut it there. Quiet: the viewer says why.
|
||||
previewText: async (id: number): Promise<FilePreviewText> => {
|
||||
const r = await req<Response>(`/api/files/${id}/preview`, {}, { raw: true, quiet: true });
|
||||
|
||||
Reference in New Issue
Block a user