88 lines
3.4 KiB
TypeScript
88 lines
3.4 KiB
TypeScript
import { expect, it } from "vitest";
|
|
|
|
import { analyzeJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
|
|
|
|
const windowPrefix =
|
|
"import {BrowserWindow} from 'electron'; import {fileURLToPath} from 'node:url';";
|
|
|
|
it.each([
|
|
'class URL {constructor(input, base) {return new globalThis.URL("./actual.js", base);}}',
|
|
"globalThis.URL = class {};",
|
|
'import.meta.url = "file:///another/main.js";',
|
|
])(
|
|
"retains a dynamic preload when source URL identity is unavailable: %s",
|
|
(prefix) => {
|
|
const analysis = analyzeJavaScriptStaticSource(`${windowPrefix}${prefix}
|
|
new BrowserWindow({webPreferences:{preload:fileURLToPath(new URL("./decoy.js", import.meta.url))}});`);
|
|
expect(analysis.electron.browser_windows).toMatchObject([
|
|
{ preload_path: null },
|
|
]);
|
|
expect(analysis.role_paths).toEqual([]);
|
|
},
|
|
);
|
|
|
|
it.each([
|
|
'["a", "b"].join("/")',
|
|
'settings.join("/app", "preload.js")',
|
|
'settings.fileURLToPath("file:///decoy.js")',
|
|
])("does not assign native path semantics to %s", (expression) => {
|
|
const analysis =
|
|
analyzeJavaScriptStaticSource(`import {BrowserWindow} from 'electron';
|
|
const settings = {join() {}, fileURLToPath() {}};
|
|
new BrowserWindow({webPreferences:{preload:${expression}}});`);
|
|
expect(analysis.electron.browser_windows).toMatchObject([
|
|
{ preload_path: null },
|
|
]);
|
|
expect(analysis.role_paths).toEqual([]);
|
|
});
|
|
|
|
it("recovers native aliases and emits preload roles only for their Electron owner", () => {
|
|
const analysis = analyzeJavaScriptStaticSource(`${windowPrefix}
|
|
import {join as append} from 'node:path';
|
|
const unrelated = {preload: "./unrelated.js"};
|
|
new BrowserWindow({webPreferences:{preload:append(__dirname, "preload.js")}});
|
|
new BrowserWindow({webPreferences:{preload:fileURLToPath(new URL("./native.js", import.meta.url))}});`);
|
|
expect(
|
|
analysis.electron.browser_windows.map(({ preload_path }) => preload_path),
|
|
).toEqual(["preload.js", "./native.js"]);
|
|
expect(analysis.role_paths.map(({ path }) => path)).toEqual([
|
|
"preload.js",
|
|
"./native.js",
|
|
]);
|
|
});
|
|
|
|
it.each(["localStorage", "sessionStorage"])(
|
|
"requires browser identity for %s",
|
|
(name) => {
|
|
const local = analyzeJavaScriptStaticSource(
|
|
`const ${name} = {setItem(key, value) {return value;}}; ${name}.setItem("ghost", "value");`,
|
|
);
|
|
expect(local.storage).toEqual([]);
|
|
const global = analyzeJavaScriptStaticSource(
|
|
`globalThis.${name}.setItem("real", "value");`,
|
|
);
|
|
expect(global.storage).toMatchObject([{ name: "real" }]);
|
|
const overwritten = analyzeJavaScriptStaticSource(
|
|
`globalThis.${name}.setItem = () => {}; ${name}.setItem("ghost", "value");`,
|
|
);
|
|
expect(overwritten.storage).toEqual([]);
|
|
},
|
|
);
|
|
|
|
it("requires an intact Electron instance for renderer roles", () => {
|
|
const local = analyzeJavaScriptStaticSource(
|
|
`const cache = {loadFile(value) {return value;}};cache.loadFile("data.json");`,
|
|
);
|
|
expect(local.role_paths).toEqual([]);
|
|
const native = analyzeJavaScriptStaticSource(
|
|
`import {BrowserWindow as Win} from 'electron';const window = new Win(); window.loadFile("index.html");`,
|
|
);
|
|
expect(native.role_paths).toMatchObject([
|
|
{ role: "renderer", path: "index.html" },
|
|
]);
|
|
const replaced = analyzeJavaScriptStaticSource(
|
|
`import {BrowserWindow as Win} from 'electron';const window = new Win(); window.loadFile = () => {};window.loadFile("data.json");`,
|
|
);
|
|
expect(replaced.role_paths).toEqual([]);
|
|
});
|