// A FIREFOX COOKIE STORE FOR TESTS — `cookies.sqlite` with Firefox's // `moz_cookies` table, written through node:sqlite. Used by // social/xBrowserLogin.test.ts and the editor's x-session e2e, so neither // reads a real browser profile. Test-only: nothing outside a test imports it. import { mkdir } from "node:fs/promises"; import path from "node:path"; import { loadSqlite, type SqliteDb } from "../nodeSqlite"; export type FixtureCookie = { host: string; name: string; value: string; path?: string; // Seconds since the epoch, as Firefox has stored it. expiry?: number; // PRTime: microseconds since the epoch. lastAccessed?: number; isSecure?: 0 | 1; isHttpOnly?: 0 | 1; sameSite?: number; originAttributes?: string; }; // Firefox's table as recent releases create it. const SCHEMA = `CREATE TABLE moz_cookies ( id INTEGER PRIMARY KEY, originAttributes TEXT NOT NULL DEFAULT '', name TEXT, value TEXT, host TEXT, path TEXT, expiry INTEGER, lastAccessed INTEGER, creationTime INTEGER, isSecure INTEGER, isHttpOnly INTEGER, inBrowserElement INTEGER DEFAULT 0, sameSite INTEGER DEFAULT 0, schemeMap INTEGER DEFAULT 0, isPartitionedAttributeSet INTEGER DEFAULT 0, CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes) )`; export function insertFixtureCookies(db: SqliteDb, cookies: ReadonlyArray): void { const insert = db.prepare( "INSERT INTO moz_cookies (originAttributes, name, value, host, path, expiry, " + "lastAccessed, creationTime, isSecure, isHttpOnly, sameSite) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ); const nowUs = Date.now() * 1000; for (const c of cookies) { insert.run( c.originAttributes ?? "", c.name, c.value, c.host, c.path ?? "/", c.expiry ?? Math.floor(Date.now() / 1000) + 86_400 * 365, c.lastAccessed ?? nowUs, c.lastAccessed ?? nowUs, c.isSecure ?? 1, c.isHttpOnly ?? 1, c.sameSite ?? 0, ); } } // Write `/cookies.sqlite` holding `cookies`. With `keepOpen`, the // store is left open in WAL mode with the rows still in `cookies.sqlite-wal` // — what a running Firefox looks like — and the caller closes it. export async function writeFirefoxCookieStore( profileDir: string, cookies: ReadonlyArray, opts: { keepOpen?: boolean } = {}, ): Promise<{ file: string; db?: SqliteDb }> { await mkdir(profileDir, { recursive: true }); const file = path.join(profileDir, "cookies.sqlite"); const { DatabaseSync } = await loadSqlite(); const db = new DatabaseSync(file); db.exec(SCHEMA); if (opts.keepOpen) { db.exec("PRAGMA journal_mode=WAL"); db.exec("PRAGMA wal_autocheckpoint=0"); } insertFixtureCookies(db, cookies); if (opts.keepOpen) return { file, db }; db.close(); return { file }; }