mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-08-11 05:30:29 +02:00
refactor: profile imports
This commit is contained in:
@@ -68,6 +68,7 @@ export class AppSession {
|
||||
extraEnv = {},
|
||||
args = [],
|
||||
seedVersionCache = true,
|
||||
seedDownloadedBrowser = false,
|
||||
onboardingCompleted = true,
|
||||
wayfernTermsAccepted = true,
|
||||
}) {
|
||||
@@ -80,6 +81,7 @@ export class AppSession {
|
||||
this.extraEnv = extraEnv;
|
||||
this.args = args;
|
||||
this.seedVersionCache = seedVersionCache;
|
||||
this.seedDownloadedBrowser = seedDownloadedBrowser;
|
||||
this.onboardingCompleted = onboardingCompleted;
|
||||
this.wayfernTermsAccepted = wayfernTermsAccepted;
|
||||
this.session = null;
|
||||
@@ -184,6 +186,54 @@ export class AppSession {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.seedDownloadedBrowser) {
|
||||
// Registers a Wayfern version as "downloaded" without installing a
|
||||
// binary. Profile import derives its version from this registry and
|
||||
// fails with BROWSER_NOT_DOWNLOADED otherwise, so suites that exercise
|
||||
// import but never launch a browser need the entry and nothing else.
|
||||
const seededVersion =
|
||||
typeof this.seedDownloadedBrowser === "string"
|
||||
? this.seedDownloadedBrowser
|
||||
: "150.0.7871.100";
|
||||
const installDir = path.join(
|
||||
this.dataRoot,
|
||||
"data",
|
||||
"binaries",
|
||||
"wayfern",
|
||||
seededVersion,
|
||||
);
|
||||
await mkdir(installDir, { recursive: true });
|
||||
const registryPath = path.join(
|
||||
this.dataRoot,
|
||||
"data",
|
||||
"data",
|
||||
"downloaded_browsers.json",
|
||||
);
|
||||
await mkdir(path.dirname(registryPath), { recursive: true });
|
||||
await writeFile(
|
||||
registryPath,
|
||||
`${JSON.stringify(
|
||||
{
|
||||
browsers: {
|
||||
wayfern: {
|
||||
[seededVersion]: {
|
||||
browser: "wayfern",
|
||||
version: seededVersion,
|
||||
file_path: installDir,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
)}\n`,
|
||||
{ flag: "wx" },
|
||||
).catch((error) => {
|
||||
if (error.code !== "EEXIST") {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
const env = isolatedEnvironment(this.root, {
|
||||
DONUT_E2E_DISABLE_STARTUP_NETWORK: "1",
|
||||
...(process.env.DONUT_E2E_FIXTURE_URL
|
||||
@@ -525,6 +575,7 @@ export function appFromEnvironment(name, options = {}) {
|
||||
extraEnv: options.extraEnv,
|
||||
args: options.args,
|
||||
seedVersionCache: options.seedVersionCache,
|
||||
seedDownloadedBrowser: options.seedDownloadedBrowser,
|
||||
onboardingCompleted: options.onboardingCompleted,
|
||||
wayfernTermsAccepted: options.wayfernTermsAccepted,
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { DatabaseSync } from "node:sqlite";
|
||||
|
||||
export const TEST_BROWSER_VERSION = "150.0.7871.100";
|
||||
|
||||
@@ -220,3 +221,101 @@ export function currentHostOs() {
|
||||
? "windows"
|
||||
: "linux";
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a Chromium cookie store at schema version 24 with plaintext values.
|
||||
*
|
||||
* Plaintext is deliberate: it is what a store looks like when the source
|
||||
* browser could not reach its keyring, and it lets the suite assert that
|
||||
* import seals every row with the target profile's key. Chromium reads a row
|
||||
* whose `encrypted_value` is empty, and drops any row where both columns are
|
||||
* set, so "value cleared and encrypted_value populated" is the only shape that
|
||||
* actually loads.
|
||||
*/
|
||||
export function writeChromiumCookies(dbPath, cookies) {
|
||||
const db = new DatabaseSync(dbPath);
|
||||
db.exec(`
|
||||
CREATE TABLE cookies(
|
||||
creation_utc INTEGER NOT NULL,
|
||||
host_key TEXT NOT NULL,
|
||||
top_frame_site_key TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
encrypted_value BLOB NOT NULL DEFAULT '',
|
||||
path TEXT NOT NULL,
|
||||
expires_utc INTEGER NOT NULL,
|
||||
is_secure INTEGER NOT NULL,
|
||||
is_httponly INTEGER NOT NULL,
|
||||
last_access_utc INTEGER NOT NULL,
|
||||
has_expires INTEGER NOT NULL DEFAULT 1,
|
||||
is_persistent INTEGER NOT NULL DEFAULT 1,
|
||||
priority INTEGER NOT NULL DEFAULT 1,
|
||||
samesite INTEGER NOT NULL DEFAULT -1,
|
||||
source_scheme INTEGER NOT NULL DEFAULT 0,
|
||||
source_port INTEGER NOT NULL DEFAULT -1,
|
||||
last_update_utc INTEGER NOT NULL DEFAULT 0,
|
||||
source_type INTEGER NOT NULL DEFAULT 0,
|
||||
has_cross_site_ancestor INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
CREATE UNIQUE INDEX cookies_unique_index
|
||||
ON cookies(host_key, top_frame_site_key, name, path);
|
||||
CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
|
||||
INSERT INTO meta VALUES('version', '24');
|
||||
INSERT INTO meta VALUES('last_compatible_version', '24');
|
||||
`);
|
||||
const insert = db.prepare(
|
||||
`INSERT INTO cookies(creation_utc, host_key, top_frame_site_key, name, value,
|
||||
encrypted_value, path, expires_utc, is_secure, is_httponly, last_access_utc)
|
||||
VALUES(?, ?, '', ?, ?, ?, '/', 0, 0, 0, 0)`,
|
||||
);
|
||||
// `encrypted` cookies are written the way Chromium's v23->v24 migration
|
||||
// does: BindString into a BLOB column, which leaves the storage class as
|
||||
// TEXT. Reading that as a strict blob returns empty and silently blanks the
|
||||
// cookie, so the suite has to reproduce it rather than only binding blobs.
|
||||
const insertAsText = db.prepare(
|
||||
`INSERT INTO cookies(creation_utc, host_key, top_frame_site_key, name, value,
|
||||
encrypted_value, path, expires_utc, is_secure, is_httponly, last_access_utc)
|
||||
VALUES(?, ?, '', ?, '', CAST(? AS TEXT), '/', 0, 0, 0, 0)`,
|
||||
);
|
||||
let creation = 13000000000000000;
|
||||
for (const cookie of cookies) {
|
||||
if (cookie.encryptedValueText === undefined) {
|
||||
insert.run(creation++, cookie.host, cookie.name, cookie.value, "");
|
||||
} else {
|
||||
insertAsText.run(
|
||||
creation++,
|
||||
cookie.host,
|
||||
cookie.name,
|
||||
cookie.encryptedValueText,
|
||||
);
|
||||
}
|
||||
}
|
||||
db.close();
|
||||
}
|
||||
|
||||
/** Write a Chromium History database holding the given URLs. */
|
||||
export function writeChromiumHistory(dbPath, urls) {
|
||||
const db = new DatabaseSync(dbPath);
|
||||
db.exec(`
|
||||
CREATE TABLE urls(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
url LONGVARCHAR,
|
||||
title LONGVARCHAR,
|
||||
visit_count INTEGER DEFAULT 0 NOT NULL,
|
||||
typed_count INTEGER DEFAULT 0 NOT NULL,
|
||||
last_visit_time INTEGER NOT NULL,
|
||||
hidden INTEGER DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
|
||||
INSERT INTO meta VALUES('version', '69');
|
||||
INSERT INTO meta VALUES('last_compatible_version', '16');
|
||||
`);
|
||||
const insert = db.prepare(
|
||||
"INSERT INTO urls(url, title, visit_count, typed_count, last_visit_time, hidden) VALUES(?, ?, 1, 0, ?, 0)",
|
||||
);
|
||||
let visit = 13000000000000000;
|
||||
for (const url of urls) {
|
||||
insert.run(url, url, visit++);
|
||||
}
|
||||
db.close();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user