Files
reverse-engineering-anything/src/domain/javascript/electronWrappedCallPaths.test.ts
T
morluto 89006609f1 fix(javascript): separate erased types from runtime semantics
Record erasure during definition indexing and reuse it across runtime references, captures, effects, module links, routes, Electron and Vite. Preserve source type links and emitted decorator and computed-key effects; keep actual runtime reads and escapes conservative.

Validation: 1,647 focused tests and 9 documentation tests passed, with build, static and documentation gates. The inherited reference-lifetimes stress file exhausts a 512 MiB worker on both unmodified 18451e479 and this change; that file remains unverified. TypeScript 7.0.2 emit was inspected for ES2022 and ES2018 without executing emitted code.
2026-10-24 18:00:43 +08:00

1946 lines
67 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { analyzeJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
const bundle = (entry: string) => `(() => {
const modules = {
2(module) { module.exports = require("electron"); },
5(module,exports,load) {
const electron=load(2);
Object.defineProperty(exports,"__esModule",{value:true});
exports.sender = function(channel) {return (...args)=>send(channel,...args)};
function send(channel,...args) {electron.ipcRenderer.send(channel,...args)}
exports.events = {addListener(channel,handler) {
const guarded = (event,...args) => {if (allowed(event)) handler(event,...args)};
return electron.ipcMain.addListener(channel,guarded);
}};
},
9(module,exports,load) {const electron=load(2), helper=load(5); ${entry}}
};
function load(id) {const m={exports:{}};modules[id].call(m.exports,m,m.exports,load);return m.exports;}
load(9);
})();`;
describe("wrapped Electron control-flow alternatives", () => {
it.each(["flag ? copy : cut", "flag ? copy : unknownHandler", "choose()"])(
"does not select one IPC handler from %s",
(handler) => {
const result = analyzeJavaScriptStaticSource(`
const e = require("electron");
const copy = event => event.sender.copy();
const cut = event => event.sender.cut();
function choose() { if (flag) return copy; }
function register(channel, handler) { e.ipcMain.on(channel, handler); }
register("test:copy", ${handler});
`);
expect(result.electron.ipc).toContainEqual(
expect.objectContaining({
channel: "test:copy",
side: "main",
handler_kind: "dynamic-expression",
resolution_basis: "wrapper-substitution",
}),
);
expect(result.electron.call_paths ?? []).toEqual([]);
expect(result.parse_status).toBe("partial");
},
);
it.each(["'ready'", "false", "0", "''", "({})", "(()=>{})"])(
"short-circuits nullish fallback for %s in callbacks and seed calls",
(left) => {
for (const source of [
`e.ipcMain.on("test:copy", event => { ${left} ?? event.sender.copy(); });`,
`${left} ?? e.ipcMain.on("test:copy", event => event.sender.copy());`,
`e.ipcMain.on("test:copy", event => { const selected = ${left} ?? (()=>event.sender.copy()); selected(); });`,
])
expect(
analyzeJavaScriptStaticSource(`const e=require("electron");${source}`)
.electron.call_paths ?? [],
).toEqual([]);
},
);
it.each(["null", "undefined", "void 0"])(
"follows nullish fallback for %s",
(left) => {
const result = analyzeJavaScriptStaticSource(`const e=require("electron");
${left} ?? e.ipcMain.on("test:copy", event => { ${left} ?? event.sender.copy(); });`);
expect(result.electron.call_paths).toContainEqual(
expect.objectContaining({
terminal: "ipc-event.sender.copy",
conditions: [],
}),
);
},
);
it("retains a nullish guard for unknown fallback rather than a falsy guard", () => {
for (const source of [
`e.ipcMain.on("test:copy", event => { value ?? event.sender.copy(); });`,
`value ?? e.ipcMain.on("test:copy", event => event.sender.copy());`,
]) {
const result = analyzeJavaScriptStaticSource(
`const e=require("electron");${source}`,
);
expect(result.electron.call_paths).toContainEqual(
expect.objectContaining({
terminal: "ipc-event.sender.copy",
conditions: [
expect.objectContaining({
expression: "(value) === null || (value) === undefined",
}),
],
}),
);
}
});
it.each([
"if (flag) return copy; else return cut; return dead;",
"if (flag) { return copy; } return cut;",
"if (flag) { if (other) return copy; else return cut; } else return cut; return dead;",
])("retains every possible factory return: %s", (body) => {
const result = analyzeJavaScriptStaticSource(`const e=require("electron");
const copy=()=>e.ipcRenderer.send("test:copy"), cut=()=>e.ipcRenderer.send("test:cut"), dead=()=>e.ipcRenderer.send("test:dead");
function choose(){${body}}
e.contextBridge.exposeInMainWorld("desktop", {copy:choose()});`);
expect(
[
...new Set(result.electron.call_paths?.map((path) => path.channel)),
].sort(),
).toEqual(["test:copy", "test:cut"]);
const paths = result.electron.call_paths ?? [];
expect(
paths
.find(({ channel }) => channel === "test:copy")
?.conditions.map(({ expression }) => expression),
).toContain("flag");
expect(
paths
.filter(({ channel }) => channel === "test:cut")
.some((path) =>
path.conditions.some(({ expression }) => expression === "!(flag)"),
),
).toBe(true);
});
});
it("preserves an observed empty contextBridge API object", () => {
const result = analyzeJavaScriptStaticSource(`
const electron = require("electron");
electron.contextBridge.exposeInMainWorld("desktop", {});
`);
expect(result.electron.context_bridge_apis).toContainEqual(
expect.objectContaining({
api_key: "desktop",
api_status: "object-literal",
members: [],
unknown_members: 0,
}),
);
expect(result.electron.context_bridge_apis?.[0]).not.toHaveProperty(
"resolution_basis",
);
expect(result.parse_status).toBe("complete");
});
it.each([
[
"explicit nested paths after an unknown spread",
`{ ...extra, a: { b: 1 }, c: 2 }`,
["a", "a.b", "c"],
1,
"dynamic",
],
[
"a direct object literal",
`{ a: { b: 1 }, c: 2 }`,
["a", "a.b", "c"],
0,
"object-literal",
],
["a dynamic API argument", "getApi()", [], 1, "dynamic"],
] as const)(
"preserves directly observed nested bridge members for %s",
(_name, api, members, unknownMembers, apiStatus) => {
const result = analyzeJavaScriptStaticSource(`
const { contextBridge } = require("electron");
contextBridge.exposeInMainWorld("api", ${api});
`);
expect(result.electron.context_bridge_apis).toContainEqual(
expect.objectContaining({
api_key: "api",
api_status: apiStatus,
members,
unknown_members: unknownMembers,
}),
);
},
);
describe("wrapped contextBridge exposure methods", () => {
it("retains the original expression for a dynamic isolated world id", () => {
const result = analyzeJavaScriptStaticSource(
bundle(
`const worldId = selectWorld(); electron.contextBridge.exposeInIsolatedWorld(worldId, "isolatedApi", {ping: true});`,
),
);
// The proven Webpack bootstrap resolves `load(2)` directly, so the complete
// direct observation is retained instead of a wrapper substitution.
expect(result.electron.context_bridge_apis).toEqual([
expect.objectContaining({
world: "isolated",
world_id: {
status: "dynamic",
value: null,
expression: "worldId",
},
api_key: "isolatedApi",
api_status: "object-literal",
members: ["ping"],
unknown_members: 0,
module_key: "9",
module_runtime: "webpack-bootstrap@0",
}),
]);
expect(result.electron.context_bridge_apis[0]).not.toHaveProperty(
"resolution_basis",
);
expect(result.parse_status).toBe("partial");
});
it("does not report a conditionally selected world as unconditional", () => {
const result = analyzeJavaScriptStaticSource(
bundle(
`if (useIsolated) electron.contextBridge.exposeInIsolatedWorld(1001, "isolatedApi", {ping: true});`,
),
);
expect(result.electron.context_bridge_apis).not.toContainEqual(
expect.objectContaining({
api_key: "isolatedApi",
resolution_basis: "wrapper-substitution",
}),
);
expect(result.parse_status).toBe("partial");
});
it("does not report conditionally resolved world ids as unconditional", () => {
const result = analyzeJavaScriptStaticSource(
bundle(
`const worldId = useFirstWorld ? 1001 : 1002; electron.contextBridge.exposeInIsolatedWorld(worldId, "isolatedApi", {ping: true});`,
),
);
expect(result.electron.context_bridge_apis).not.toContainEqual(
expect.objectContaining({
api_key: "isolatedApi",
resolution_basis: "wrapper-substitution",
}),
);
expect(result.parse_status).toBe("partial");
});
});
describe("contextBridge helper invocations", () => {
const exposures = (source: string) => {
const result = analyzeJavaScriptStaticSource(`
const { contextBridge, ipcRenderer } = require("electron");
${source}`);
return {
result,
apis: result.electron.context_bridge_apis.map(
({
api_key,
api_key_expression,
world_id,
members,
unknown_members,
}) => ({
api_key,
api_key_expression,
world_id,
members,
unknown_members,
}),
),
};
};
const literalKey = { api_key_expression: null, world_id: null };
it("binds a site-literal object to each invocation's key", () => {
const { apis } = exposures(`
function expose(key) { contextBridge.exposeInMainWorld(key, { ping() {} }); }
expose("one"); expose("two");`);
expect(apis).toEqual([
{ api_key: "one", ...literalKey, members: ["ping"], unknown_members: 0 },
{ api_key: "two", ...literalKey, members: ["ping"], unknown_members: 0 },
]);
});
it("counts a repeated identical invocation once", () => {
const { apis } = exposures(`
function expose(key, api) { contextBridge.exposeInMainWorld(key, api); }
const api = { ping() {} };
expose("one", api); expose("one", api);`);
expect(apis).toEqual([
{ api_key: "one", ...literalKey, members: ["ping"], unknown_members: 0 },
]);
});
it("describes one key's alternative objects as one exposure", () => {
const { apis } = exposures(`
function expose(key, api) { contextBridge.exposeInMainWorld(key, api); }
expose("api", { a() {} });
expose("api", { ...globalThis.extra, b: { c() {} } });`);
expect(apis).toEqual([
{
api_key: "api",
...literalKey,
members: ["a", "b", "b.c"],
unknown_members: 1,
},
]);
});
it("keeps one key's differing world ids unknown", () => {
const { apis, result } = exposures(`
function expose(key, id, api) { contextBridge.exposeInIsolatedWorld(id, key, api); }
expose("api", 1, { a() {} }); expose("api", 2, { b() {} });`);
expect(apis).toEqual([
{
api_key: "api",
api_key_expression: null,
world_id: { status: "dynamic", value: null, expression: "id" },
members: ["a", "b"],
unknown_members: 0,
},
]);
expect(result.parse_status).toBe("partial");
});
it("bounds nested member paths at the direct syntax depth", () => {
const deep = `{ a: { b: { c: { d: { e: { f: { g: { h: { i: {} } } } } } } } } }`;
const { apis } = exposures(`
function expose(key, api) { contextBridge.exposeInMainWorld(key, api); }
expose("helper", ${deep});
contextBridge.exposeInMainWorld("direct", ${deep});`);
const paths = ["a", "a.b", "a.b.c", "a.b.c.d", "a.b.c.d.e"];
const members = [
...paths,
"a.b.c.d.e.f",
"a.b.c.d.e.f.g",
"a.b.c.d.e.f.g.h",
];
expect(apis).toEqual([
{ api_key: "helper", ...literalKey, members, unknown_members: 1 },
{ api_key: "direct", ...literalKey, members, unknown_members: 1 },
]);
});
it("keeps the site observation for a guarded invocation", () => {
const { apis } = exposures(`
function expose(key, api) { contextBridge.exposeInMainWorld(key, api); }
expose("one", { ping() {} });
if (globalThis.flag) expose("two", { pong() {} });`);
expect(apis).toEqual([
{
api_key: null,
api_key_expression: "key",
world_id: null,
members: [],
unknown_members: 1,
},
{ api_key: "one", ...literalKey, members: ["ping"], unknown_members: 0 },
]);
});
it("keeps a site-literal key singular beside a guarded invocation", () => {
const { apis } = exposures(`
function expose(api) { contextBridge.exposeInMainWorld("fixed", api); }
function relay(label, api) { expose(api); }
relay("label", { ping() {} });
if (globalThis.flag) relay("label", { pong() {} });`);
// The site's own scope leaves the API unknown; the guarded object is not
// recorded as an unconditional member.
expect(apis).toEqual([
{
api_key: "fixed",
...literalKey,
members: ["ping"],
unknown_members: 1,
},
]);
});
});
it("connects exposed closures to IPC sends and text clipboard calls", () => {
const result = analyzeJavaScriptStaticSource(
bundle(`
const text = value => navigator.clipboard.writeText(value);
const api={copy:helper.sender("example:copy"),copyText:text};
electron.contextBridge.exposeInMainWorld("desktop",api);
`),
);
expect(result.electron.context_bridge_apis).toMatchObject([
{ api_key: "desktop", members: ["copy", "copyText"] },
]);
expect(result.electron.ipc).toContainEqual(
expect.objectContaining({
side: "renderer",
channel: "example:copy",
operation: "send",
}),
);
expect(result.electron.call_paths).toEqual(
expect.arrayContaining([
expect.objectContaining({
entry: "desktop.copy",
channel: "example:copy",
terminal: "electron.ipcRenderer.send",
}),
expect.objectContaining({
entry: "desktop.copyText",
terminal: "navigator.clipboard.writeText",
}),
]),
);
const ipcFinding = result.electron.ipc.find(
({ channel }) => channel === "example:copy",
);
const ipcPath = result.electron.call_paths?.find(
({ entry }) => entry === "desktop.copy",
);
expect(ipcFinding).toBeDefined();
expect(ipcPath?.steps.at(-1)).toBeDefined();
expect(ipcFinding?.location).toEqual(ipcPath?.steps.at(-1)?.location);
});
it("resolves a helper factory listed after its bundle consumer", () => {
const result = analyzeJavaScriptStaticSource(`(() => {
const modules = {
2(module) { module.exports = require("electron"); },
9(module,exports,load) {
const electron=load(2),helper=load(5);
electron.contextBridge.exposeInMainWorld("desktop", {copy:helper.sender("after:copy")});
},
5(module,exports,load) {
const electron=load(2);
exports.sender=channel=>()=>electron.ipcRenderer.send(channel);
}
};
function load(id) { const m={exports:{}}; modules[id].call(m.exports,m,m.exports,load); return m.exports; }
load(9);
})();`);
expect(result.electron.call_paths).toContainEqual(
expect.objectContaining({
entry: "desktop.copy",
channel: "after:copy",
terminal: "electron.ipcRenderer.send",
}),
);
});
it("substitutes guarded listener callbacks and preserves guard evidence", () => {
const result = analyzeJavaScriptStaticSource(
bundle(
`helper.events.addListener("example:copy",event=>event.sender.copy());`,
),
);
expect(result.electron.ipc).toContainEqual(
expect.objectContaining({
side: "main",
channel: "example:copy",
operation: "on",
}),
);
expect(result.electron.call_paths).toContainEqual(
expect.objectContaining({
entry_kind: "ipc-handler",
channel: "example:copy",
terminal: "ipc-event.sender.copy",
conditions: [expect.objectContaining({ expression: "allowed(event)" })],
}),
);
const ipcFinding = result.electron.ipc.find(
({ channel, operation }) =>
channel === "example:copy" && operation === "on",
);
const ipcStep = result.electron.call_paths
?.find(({ entry_kind }) => entry_kind === "ipc-handler")
?.steps.find(({ kind }) => kind === "ipc");
expect(ipcFinding).toBeDefined();
expect(ipcStep).toBeDefined();
expect(ipcFinding?.location).toEqual(ipcStep?.location);
});
it("retains distinct wrapper invocation ranges for one IPC API source", () => {
const result = analyzeJavaScriptStaticSource(`
const e=require("electron");
const copy=event=>event.sender.copy();
function register(channel,handler){e.ipcMain.on(channel,handler);}
register("same:channel",copy);
register("same:channel",copy);
`);
const findings = result.electron.ipc.filter(
({ resolution_basis, channel }) =>
resolution_basis === "wrapper-substitution" && channel === "same:channel",
);
expect(findings).toHaveLength(2);
expect(findings[0]?.location).toEqual(findings[1]?.location);
expect(findings[0]?.invocation_location).toBeDefined();
expect(findings[1]?.invocation_location).toBeDefined();
expect(findings[0]?.invocation_location).not.toEqual(
findings[1]?.invocation_location,
);
});
it("keeps one wrapper registration when one invocation reaches it twice", () => {
const result = analyzeJavaScriptStaticSource(`
const e=require("electron");
const copy=event=>event.sender.copy();
function register(channel,handler){e.ipcMain.on(channel,handler);}
function twice(channel){register(channel,copy);register(channel,copy);}
twice("same:invocation");
`);
expect(
result.electron.ipc.filter(
({ resolution_basis, channel }) =>
resolution_basis === "wrapper-substitution" &&
channel === "same:invocation",
),
).toHaveLength(1);
});
it("keeps a directly observed renderer operation singular when tracing its exposed callback", () => {
const result = analyzeJavaScriptStaticSource(`
const {contextBridge,ipcRenderer}=require("electron");
contextBridge.exposeInMainWorld("desktop",{ping:()=>ipcRenderer.invoke("ping")});
`);
expect(result.electron.ipc).toHaveLength(1);
expect(result.electron.ipc[0]).toMatchObject({
channel: "ping",
operation: "invoke",
});
expect(result.electron.ipc[0]).not.toHaveProperty("resolution_basis");
expect(result.electron.call_paths).toContainEqual(
expect.objectContaining({ entry: "desktop.ping", channel: "ping" }),
);
});
it("resolves a site-determined constant channel in place of its dynamic observation", () => {
const result = analyzeJavaScriptStaticSource(`
const {contextBridge,ipcRenderer}=require("electron");
const PING = "ping";
contextBridge.exposeInMainWorld("desktop",{ping:()=>ipcRenderer.send(PING)});
`);
expect(result.electron.ipc).toEqual([
expect.objectContaining({
side: "renderer",
operation: "send",
channel: "ping",
resolution_basis: "wrapper-substitution",
}),
]);
expect(result.electron.call_paths).toContainEqual(
expect.objectContaining({ entry: "desktop.ping", channel: "ping" }),
);
// The syntax pass's unknown channel is resolved, not left as partial.
expect(result.parse_status).toBe("complete");
});
it("resolves a site-determined registration whose handler is a named local", () => {
const result = analyzeJavaScriptStaticSource(`
const {contextBridge,ipcRenderer}=require("electron");
const CH = "ch";
const handler = () => {};
contextBridge.exposeInMainWorld("desktop",{on:()=>ipcRenderer.on(CH, handler)});
`);
expect(result.electron.ipc).toEqual([
expect.objectContaining({
side: "renderer",
mode: "listen",
channel: "ch",
handler_kind: "inline-function",
}),
]);
expect(result.parse_status).toBe("complete");
});
it("keeps an argument-supplied channel unresolved beside its resolved candidates", () => {
const result = analyzeJavaScriptStaticSource(`
const {contextBridge,ipcRenderer}=require("electron");
const forward = channel => ipcRenderer.send(channel);
contextBridge.exposeInMainWorld("desktop",{
a:()=>forward("a"),
b:()=>forward("b"),
any:name=>forward(name),
});
`);
const sends = result.electron.ipc.filter(
({ side, operation }) => side === "renderer" && operation === "send",
);
expect(sends.map(({ channel }) => channel).sort()).toEqual(["a", "b", null]);
expect(
new Set(sends.map(({ location }) => JSON.stringify(location))).size,
).toBe(1);
});
it.each([
[
"an exposed member",
`const forward = (channel, callback) => ipcRenderer.on(channel, callback);
contextBridge.exposeInMainWorld("desktop",{on:()=>forward("pong",()=>{})});`,
],
[
"an enclosing local call",
`const forward = (channel, callback) => ipcRenderer.on(channel, callback);
const notify = kind => forward("pong", () => {});
notify("ready");`,
],
])(
"keeps one invocation of a wrapper call also reached through %s",
(_, entry) => {
const result = analyzeJavaScriptStaticSource(`
const {contextBridge,ipcRenderer}=require("electron");
${entry}
`);
expect(
result.electron.ipc.filter(({ channel }) => channel === "pong"),
).toHaveLength(1);
},
);
it("keeps distinct handlers that separate outer calls pass through one wrapper call", () => {
const result = analyzeJavaScriptStaticSource(`
const e = require("electron");
function register(channel, handler) { e.ipcMain.on(channel, handler); }
function setup(tag, handler) { register("same", handler); }
setup("first", () => 1);
setup("second", () => 2);
`);
const registrations = result.electron.ipc.filter(
({ channel }) => channel === "same",
);
// The wrapper call traced alone has an unresolved handler; each outer call
// supplies its own concrete handler.
expect(registrations.map(({ handler_kind }) => handler_kind).sort()).toEqual([
"dynamic-expression",
"inline-function",
"inline-function",
]);
expect(
new Set(
registrations.map(({ handler_location }) =>
JSON.stringify(handler_location),
),
).size,
).toBe(3);
});
it("keeps the source registration when only its channel is site-determined", () => {
const result = analyzeJavaScriptStaticSource(`
const { ipcMain } = require("electron");
const CH = "ch";
function register(seed, handler) { ipcMain.on(CH, handler); }
register("seed", () => 1);
`);
expect(
result.electron.ipc.map(({ channel, handler_kind, resolution_basis }) => [
channel,
handler_kind,
resolution_basis ?? "direct",
]),
).toEqual([
[null, "identifier", "direct"],
["ch", "inline-function", "wrapper-substitution"],
]);
});
it.each([
[
"a closure over a wrapper parameter",
`function register(seed) {
const handler = () => ipcRenderer.send(seed);
ipcRenderer.on(CH, handler);
}`,
],
[
"an arrow function reading its wrapper's arguments",
`function register(seed) {
const handler = () => arguments[0];
ipcRenderer.on(CH, handler);
}`,
],
[
"an arrow function reading its wrapper's new.target",
`function register(seed) {
const handler = () => new.target;
ipcRenderer.on(CH, handler);
}`,
],
[
"a closure returned from a factory of a wrapper parameter",
`const make = value => () => value;
function register(seed) {
const handler = make(seed);
ipcRenderer.on(CH, handler);
}`,
],
])("keeps distinct listeners when one handler node is %s", (_, wrapper) => {
const result = analyzeJavaScriptStaticSource(`
const { contextBridge, ipcRenderer } = require("electron");
const CH = "ch", A = "a", B = "b";
${wrapper}
contextBridge.exposeInMainWorld("first", { on: () => register(A) });
contextBridge.exposeInMainWorld("second", { on: () => register(B) });
`);
// Each invocation installs its own closure; the direct source observation
// stays for callers this pass does not trace.
expect(
result.electron.ipc
.filter(({ mode }) => mode === "listen")
.map(({ channel, resolution_basis }) => [
channel,
resolution_basis ?? "direct",
]),
).toEqual([
[null, "direct"],
["ch", "wrapper-substitution"],
["ch", "wrapper-substitution"],
]);
expect(
(result.electron.call_paths ?? [])
.filter(({ channel }) => channel === "ch")
.map(({ entry }) => entry)
.sort(),
).toEqual(["first.on", "second.on"]);
});
it("resolves a bundle module's handler in place as one shared listener", () => {
const result = analyzeJavaScriptStaticSource(
bundle(`const CH = "ch";
const handler = () => electron.ipcRenderer.send("reply");
electron.contextBridge.exposeInMainWorld("api", {
on: () => electron.ipcRenderer.on(CH, handler),
});`),
);
expect(
result.electron.ipc
.filter(({ mode, module_key }) => mode === "listen" && module_key === "9")
.map(({ channel, resolution_basis }) => [
channel,
resolution_basis ?? "direct",
]),
).toEqual([["ch", "wrapper-substitution"]]);
});
it("resolves an arrow handler in place when its inherited this is module scope", () => {
const result = analyzeJavaScriptStaticSource(`
const { contextBridge, ipcRenderer } = require("electron");
const CH = "ch";
const register = () => {
const handler = () => this;
ipcRenderer.on(CH, handler);
};
contextBridge.exposeInMainWorld("api", { on: () => register() });
`);
expect(
result.electron.ipc
.filter(({ mode }) => mode === "listen")
.map(({ channel, resolution_basis }) => [
channel,
resolution_basis ?? "direct",
]),
).toEqual([["ch", "wrapper-substitution"]]);
});
it.each(["interface Shape { marker(): void }", "type Shape = typeof marker;"])(
"does not give a handler invocation identity through erased syntax: %s",
(declaration) => {
const result = analyzeJavaScriptStaticSource(`
const { contextBridge, ipcRenderer } = require("electron");
const CH = "ch";
function register(marker) {
const handler = () => { ${declaration} };
ipcRenderer.on(CH, handler);
}
contextBridge.exposeInMainWorld("api", { on: () => register("unused") });
`);
expect(
result.electron.ipc
.filter(({ mode }) => mode === "listen")
.map(({ channel, resolution_basis }) => [
channel,
resolution_basis ?? "direct",
]),
).toEqual([["ch", "wrapper-substitution"]]);
expect(result.parse_status).toBe("complete");
},
);
it("resolves a handler a module-level factory call created once in place", () => {
const result = analyzeJavaScriptStaticSource(`
const { ipcMain } = require("electron");
const CH = "ch";
const make = () => { const value = Math.random(); return () => value; };
const handler = make();
function register(seed) { ipcMain.on(CH, handler); }
register("x");
`);
expect(
result.electron.ipc.map(({ channel, resolution_basis }) => [
channel,
resolution_basis ?? "direct",
]),
).toEqual([["ch", "wrapper-substitution"]]);
expect(result.parse_status).toBe("complete");
});
it("keeps separate outer calls that pass one shared handler through a wrapper", () => {
const result = analyzeJavaScriptStaticSource(`
const { ipcMain } = require("electron");
const copy = () => {};
function register(ch, handler) { ipcMain.on(ch, handler); }
function setup(tag) { register("same", copy); }
setup("first");
setup("second");
`);
const registrations = result.electron.ipc.filter(
({ channel }) => channel === "same",
);
// The shorter entry traced the same wrapper call alone; both outer calls
// supersede it as distinct invocations.
expect(registrations).toHaveLength(2);
expect(
new Set(
registrations.map(({ invocation_location }) =>
JSON.stringify(invocation_location),
),
).size,
).toBe(2);
});
it("keeps a parameterless factory's closure as a per-invocation handler", () => {
const result = analyzeJavaScriptStaticSource(`
const { contextBridge, ipcRenderer } = require("electron");
const CH = "ch";
const make = () => { const value = Math.random(); return () => value; };
function register() {
const handler = make();
ipcRenderer.on(CH, handler);
}
contextBridge.exposeInMainWorld("api", { on: () => register() });
`);
expect(
result.electron.ipc
.filter(({ mode }) => mode === "listen")
.map(({ resolution_basis }) => resolution_basis ?? "direct"),
).toEqual(["direct", "wrapper-substitution"]);
});
it("resolves a module-level handler in place when the entry binds an unused parameter", () => {
const result = analyzeJavaScriptStaticSource(`
const { contextBridge, ipcRenderer } = require("electron");
const CH = "ch";
const handler = () => {};
contextBridge.exposeInMainWorld("api", {
on: unused => ipcRenderer.on(CH, handler),
});
`);
expect(result.electron.ipc).toEqual([
expect.objectContaining({
mode: "listen",
channel: "ch",
resolution_basis: "wrapper-substitution",
}),
]);
expect(result.parse_status).toBe("complete");
});
it.each([
["a named local", 'const handler = () => tag; register("same", handler);'],
["an inline argument", 'register("same", () => tag);'],
[
"a nested helper",
'const inner = () => register("same", () => tag); inner();',
],
])("keeps closures that separate outer calls create through %s", (_, body) => {
const result = analyzeJavaScriptStaticSource(`
const { ipcMain } = require("electron");
function register(ch, handler) { ipcMain.on(ch, handler); }
function setup(tag) { ${body} }
setup("first");
setup("second");
`);
const invocations = result.electron.ipc
.filter(
({ channel, resolution_basis }) =>
channel === "same" && resolution_basis === "wrapper-substitution",
)
.map(({ invocation_location }) => JSON.stringify(invocation_location));
// Both outer calls stay, beside the shorter entry that traced the same
// wrapper call without either caller's value.
expect(new Set(invocations).size).toBe(3);
});
it("counts one exposed renderer listener callsite once and retains its bridge path", () => {
const result = analyzeJavaScriptStaticSource(`
const {contextBridge,ipcRenderer}=require("electron");
contextBridge.exposeInMainWorld("desktop", {
onPong: callback => ipcRenderer.on("pong", callback),
});
`);
expect(
result.electron.ipc.filter(
({ side, mode, channel }) =>
side === "renderer" && mode === "listen" && channel === "pong",
),
).toHaveLength(1);
expect(result.electron.call_paths).toContainEqual(
expect.objectContaining({
entry: "desktop.onPong",
channel: "pong",
terminal: "electron.ipcRenderer.on",
}),
);
});
it("keeps separate bridge callers while counting their shared listener callsite once", () => {
const result = analyzeJavaScriptStaticSource(`
const {contextBridge,ipcRenderer}=require("electron");
const subscribe = callback => ipcRenderer.once("pong", callback);
contextBridge.exposeInMainWorld("desktop", {
onPong: subscribe,
onPongAgain: subscribe,
});
`);
const listeners = result.electron.ipc.filter(
({ side, mode, channel }) =>
side === "renderer" && mode === "listen" && channel === "pong",
);
expect(listeners).toHaveLength(1);
expect(listeners[0]?.operation).toBe("once");
expect(
result.electron.call_paths
?.filter(({ channel }) => channel === "pong")
.map(({ entry }) => entry),
).toEqual(["desktop.onPong", "desktop.onPongAgain"]);
});
it("keeps distinct exposed renderer listener callsites distinct", () => {
const result = analyzeJavaScriptStaticSource(`
const {contextBridge,ipcRenderer}=require("electron");
contextBridge.exposeInMainWorld("desktop", {
onPong: callback => ipcRenderer.on("pong", callback),
onPongAgain: callback => ipcRenderer.on("pong", callback),
});
`);
expect(
result.electron.ipc.filter(
({ side, mode, channel }) =>
side === "renderer" && mode === "listen" && channel === "pong",
),
).toHaveLength(2);
expect(
result.electron.call_paths?.filter(({ channel }) => channel === "pong"),
).toHaveLength(2);
});
it("does not identify overwritten Electron namespaces or shadowed require", () => {
for (const source of [
`const e=require("electron");e.ipcMain={on(){}};e.ipcMain.on("bad",event=>event.sender.copy());`,
`function require(){return {ipcMain:{on(){}}}};const e=require("electron");e.ipcMain.on("bad",event=>event.sender.copy());`,
])
expect(
analyzeJavaScriptStaticSource(source).electron.call_paths ?? [],
).toEqual([]);
});
it("preserves guarded alternatives in direct exposed object literals", () => {
const result = analyzeJavaScriptStaticSource(`
const e=require("electron");
const copy=()=>e.ipcRenderer.send("copy");
const cut=()=>e.ipcRenderer.send("cut");
e.contextBridge.exposeInMainWorld("desktop", {action: flag ? copy : cut});
`);
expect(result.electron.call_paths).toEqual(
expect.arrayContaining([
expect.objectContaining({
entry: "desktop.action",
channel: "copy",
conditions: [expect.objectContaining({ expression: "flag" })],
}),
expect.objectContaining({
entry: "desktop.action",
channel: "cut",
conditions: [expect.objectContaining({ expression: "!(flag)" })],
}),
]),
);
});
it("preserves bridge member segments and excludes prototype setters", () => {
const result = analyzeJavaScriptStaticSource(`
const e=require("electron");
const write=()=>e.ipcRenderer.send("write");
e.contextBridge.exposeInMainWorld("desktop", {
"nested.write": write,
nested: { write },
__proto__: { inherited: write },
["__proto__"]: { own: write },
});
`);
expect(result.electron.call_paths).toEqual(
expect.arrayContaining([
expect.objectContaining({
entry: "desktop.nested.write",
entry_path: ["desktop", "nested.write"],
}),
expect.objectContaining({
entry: "desktop.nested.write",
entry_path: ["desktop", "nested", "write"],
}),
expect.objectContaining({
entry: "desktop.__proto__.own",
entry_path: ["desktop", "__proto__", "own"],
}),
]),
);
expect(result.electron.call_paths).not.toEqual(
expect.arrayContaining([
expect.objectContaining({
entry_path: ["desktop", "__proto__", "inherited"],
}),
]),
);
});
it("follows an explicit object-literal prototype lookup in a bridge wrapper", () => {
const result = analyzeJavaScriptStaticSource(`
const e=require("electron");
const prototype={send:()=>e.ipcRenderer.send("through-prototype")};
const object={__proto__:prototype};
e.contextBridge.exposeInMainWorld("desktop", {
action:()=>object.__proto__.send(),
});
`);
expect(result.electron.call_paths).toEqual(
expect.arrayContaining([
expect.objectContaining({
entry_path: ["desktop", "action"],
channel: "through-prototype",
}),
]),
);
});
it("does not spread a large nested bridge member list into function arguments", () => {
const members = Array.from(
{ length: 125_000 },
(_, index) => `m${index}(){}`,
).join(",");
const source = `const e=require("electron");e.contextBridge.exposeInMainWorld("desktop",{nested:{${members}}});`;
expect(() => analyzeJavaScriptStaticSource(source)).not.toThrow();
});
it("reports nested bridge depth truncation while retaining shallow paths", () => {
const nested =
Array.from({ length: 130 }, (_, index) => `level${index}:{`).join("") +
`deep:()=>e.ipcRenderer.send("deep")` +
"}".repeat(130);
const result = analyzeJavaScriptStaticSource(`
const e=require("electron");
e.contextBridge.exposeInMainWorld("desktop", {
shallow:()=>e.ipcRenderer.send("shallow"), ${nested}
});
`);
expect(result.electron.call_paths).toContainEqual(
expect.objectContaining({ entry: "desktop.shallow", channel: "shallow" }),
);
expect(result.limitations.join(" ")).toContain("depth 128");
});
it("preserves conditions when a wrapper dispatches through conditional external methods", () => {
const result = analyzeJavaScriptStaticSource(`
const e=require("electron");
const send=flag ? e.ipcRenderer.send : e.ipcRenderer.invoke;
e.contextBridge.exposeInMainWorld("desktop", {action:()=>send("channel")});
`);
expect(result.electron.call_paths).toEqual(
expect.arrayContaining([
expect.objectContaining({
entry: "desktop.action",
channel: "channel",
terminal: "electron.ipcRenderer.send",
conditions: [expect.objectContaining({ expression: "flag" })],
}),
expect.objectContaining({
entry: "desktop.action",
channel: "channel",
terminal: "electron.ipcRenderer.invoke",
conditions: [expect.objectContaining({ expression: "!(flag)" })],
}),
]),
);
expect(
result.electron.ipc.filter(
({ resolution_basis, channel }) =>
resolution_basis === "wrapper-substitution" && channel === "channel",
),
).toEqual([]);
expect(result.parse_status).toBe("partial");
});
it("keeps conditional IPC channels unknown instead of reporting them unconditionally", () => {
const result = analyzeJavaScriptStaticSource(`
const e=require("electron");
const channel=flag ? "copy" : "cut";
e.contextBridge.exposeInMainWorld("desktop", {action:()=>e.ipcRenderer.send(channel)});
`);
expect(result.electron.call_paths ?? []).toEqual([]);
expect(result.parse_status).toBe("partial");
});
it("retains enclosing branch predicates without emitting unconditional wrapper findings", () => {
const result = analyzeJavaScriptStaticSource(`
const e=require("electron");
function expose(key,api){e.contextBridge.exposeInMainWorld(key,api);}
function register(channel,handler){e.ipcMain.on(channel,handler);}
if(flag){
expose("conditional",{copy:()=>navigator.clipboard.writeText("copy")});
register("only:flag",event=>event.sender.copy());
}
`);
expect(result.electron.context_bridge_apis).not.toContainEqual(
expect.objectContaining({
api_key: "conditional",
resolution_basis: "wrapper-substitution",
}),
);
expect(result.electron.ipc).not.toContainEqual(
expect.objectContaining({
channel: "only:flag",
resolution_basis: "wrapper-substitution",
}),
);
for (const entry of ["conditional.copy", "only:flag"])
expect(result.electron.call_paths).toContainEqual(
expect.objectContaining({
entry,
conditions: [expect.objectContaining({ expression: "flag" })],
}),
);
expect(result.parse_status).toBe("partial");
});
it("preserves the raw bridge observation for a guarded object value", () => {
const result = analyzeJavaScriptStaticSource(`
const e=require("electron");
const api=flag ? {copy:()=>e.ipcRenderer.send("copy")} : {};
e.contextBridge.exposeInMainWorld("desktop", api);
`);
expect(result.electron.context_bridge_apis).toContainEqual(
expect.objectContaining({
api_key: "desktop",
api_status: "dynamic",
}),
);
expect(result.parse_status).toBe("partial");
});
it("preserves the source expression for a guarded bridge world key", () => {
const result = analyzeJavaScriptStaticSource(`
const e=require("electron");
const world=flag ? "desktop" : "shell";
e.contextBridge.exposeInMainWorld(world, {copy:()=>e.ipcRenderer.send("copy")});
`);
expect(result.electron.context_bridge_apis).toContainEqual(
expect.objectContaining({ api_key: null, api_key_expression: "world" }),
);
expect(result.parse_status).toBe("partial");
});
it.each(["const", "var"])(
"does not use a %s callback initializer before exposure",
(declaration) => {
const result = analyzeJavaScriptStaticSource(
bundle(`
const electron=load(2);
electron.contextBridge.exposeInMainWorld("desktop", {copy: callback});
${declaration} callback=()=>electron.ipcRenderer.send("late");
`),
);
expect(result.electron.call_paths ?? []).toEqual([]);
expect(result.parse_status).toBe("partial");
},
);
it("does not use an original Electron module factory after its slot is replaced", () => {
const result = analyzeJavaScriptStaticSource(
bundle(`
modules[2] = function(module) {
module.exports = {contextBridge:{exposeInMainWorld(){}},ipcRenderer:{send(){}}};
};
const electron=load(2);
electron.contextBridge.exposeInMainWorld("desktop", {copy:()=>electron.ipcRenderer.send("fake")});
`),
);
expect(result.electron.call_paths ?? []).toEqual([]);
});
it.each(["({})", "load(2)"])(
"does not emit the impossible logical-RHS terminal after %s",
(left) => {
const result = analyzeJavaScriptStaticSource(
bundle(`
electron.ipcMain.on("guard", event => { ${left} || event.sender.copy(); });
`),
);
expect(result.electron.call_paths ?? []).toEqual([]);
},
);
it.each([
["flag -= 1", true],
["flag = 0", false],
["flag -= step", true],
["flag += 0", true],
["flag &= 2", true],
["flag &&= 0", true],
["flag ||= 0", true],
["flag ??= 0", true],
] as const)(
"preserves contextual IPC candidates for assignment test %s",
(test, uncertain) => {
const result = analyzeJavaScriptStaticSource(`
const {contextBridge, ipcRenderer} = require("electron");
function action(step) {
let flag = 1;
if ((${test})) ipcRenderer.send("channel-then");
else ipcRenderer.send("channel-else");
}
contextBridge.exposeInMainWorld("desktop", {action});
`);
expect(result.electron.ipc.map(({ channel }) => channel).sort()).toEqual([
"channel-else",
"channel-then",
]);
const paths = result.electron.call_paths
?.filter(({ entry }) => entry === "desktop.action")
.map(({ channel, conditions, resolution }) => ({
channel,
conditions: conditions.map(({ expression }) => expression),
resolution,
}))
.sort((a, b) => String(a.channel).localeCompare(String(b.channel)));
expect(paths).toEqual([
{
channel: "channel-else",
conditions: uncertain ? [`!(${test})`] : [],
resolution: "candidate",
},
...(uncertain
? [
{
channel: "channel-then",
conditions: [test],
resolution: "candidate",
},
]
: []),
]);
},
);
it.each([
["exports.flag = 1; exports.flag -= 1", "helper.flag", true],
["exports.flag = 0", "helper.flag", false],
[
"module.exports = {flag: 1}; module.exports += {flag: 0}",
"helper.flag",
true,
],
["module.exports = {flag: 0}", "helper.flag", false],
] as const)(
"preserves assignment semantics through module writes: %s",
(writes, test, uncertain) => {
const source = bundle(`
electron.contextBridge.exposeInMainWorld("desktop", {action() {
if (${test}) electron.ipcRenderer.send("channel-then");
else electron.ipcRenderer.send("channel-else");
}});
`).replace("exports.sender =", `${writes}; exports.sender =`);
const result = analyzeJavaScriptStaticSource(source);
const paths = result.electron.call_paths
?.filter(({ entry }) => entry === "desktop.action")
.map(({ channel, conditions }) => ({
channel,
conditions: conditions.map(({ expression }) => expression),
}))
.sort((a, b) => String(a.channel).localeCompare(String(b.channel)));
expect(paths).toEqual([
{ channel: "channel-else", conditions: uncertain ? [`!(${test})`] : [] },
...(uncertain ? [{ channel: "channel-then", conditions: [test] }] : []),
]);
},
);
it.each([
["cb ||=", ["!(cb)"]],
["cb &&=", ["cb"]],
["cb ??=", ["(cb) === null || (cb) === undefined"]],
["({cb: false}).cb ||=", []],
["({cb: true}).cb &&=", []],
["({cb: null}).cb ??=", []],
] as const)(
"retains the reachable callable RHS of %s",
(assignment, conditions) => {
const result = analyzeJavaScriptStaticSource(`
const {contextBridge, ipcRenderer} = require("electron");
contextBridge.exposeInMainWorld("desktop", {action(cb) {
(${assignment} () => ipcRenderer.send("rhs"))();
}});
`);
expect(
result.electron.call_paths?.map(
({ channel, conditions, resolution }) => ({
channel,
conditions: conditions.map(({ expression }) => expression),
resolution,
}),
),
).toEqual([{ channel: "rhs", conditions, resolution: "candidate" }]);
},
);
it.each([
"({cb: true}).cb ||=",
"({cb: false}).cb &&=",
"({cb: false}).cb ??=",
])("does not invoke the skipped callable RHS of %s", (assignment) => {
const result = analyzeJavaScriptStaticSource(`
const {contextBridge, ipcRenderer} = require("electron");
contextBridge.exposeInMainWorld("desktop", {action() {
(${assignment} () => ipcRenderer.send("skipped"))();
}});
`);
expect(result.electron.call_paths ?? []).toEqual([]);
expect(result.electron.ipc).toContainEqual(
expect.objectContaining({ channel: "skipped" }),
);
});
it.each(["||=", "??="])(
"retains the selected left callable of %s",
(operator) => {
const result = analyzeJavaScriptStaticSource(`
const {contextBridge, ipcRenderer} = require("electron");
contextBridge.exposeInMainWorld("desktop", {action() {
(({cb: () => ipcRenderer.send("left")}).cb ${operator} () => ipcRenderer.send("right"))();
}});
`);
expect(
result.electron.call_paths?.map(({ channel, conditions }) => ({
channel,
conditions,
})),
).toEqual([{ channel: "left", conditions: [] }]);
},
);
it.each([
["||=", "!(exports.action)"],
["&&=", "exports.action"],
["??=", "(exports.action) === null || (exports.action) === undefined"],
])(
"retains a guarded namespace callable assigned with %s",
(operator, condition) => {
const source = bundle(`
electron.contextBridge.exposeInMainWorld("desktop", {action: helper.action});
`).replace(
"exports.sender =",
`exports.action ${operator} () => electron.ipcRenderer.send("rhs"); exports.sender =`,
);
const result = analyzeJavaScriptStaticSource(source);
expect(
result.electron.call_paths?.map(({ channel, conditions }) => ({
channel,
conditions: conditions.map(({ expression }) => expression),
})),
).toEqual([{ channel: "rhs", conditions: [condition] }]);
},
);
// A synthetic module record establishes identity, not the value of its mutable
// exports slot. These are guarded candidates, including when runtime evaluation
// might skip the RHS; they must not claim execution or select a stale value.
const expectGuardedRoot = (
source: string,
operator: string,
target = "module.exports",
channel = "rhs",
) => {
const result = analyzeJavaScriptStaticSource(source);
const condition =
operator === "&&="
? target
: operator === "||="
? `!(${target})`
: `(${target}) === null || (${target}) === undefined`;
expect(
result.electron.call_paths
?.filter(({ entry }) => entry === "desktop.action")
.map(({ channel, conditions, resolution }) => ({
channel,
conditions: conditions.map(({ expression }) => expression),
resolution,
})) ?? [],
).toEqual([{ channel, conditions: [condition], resolution: "candidate" }]);
expect(result.electron.ipc).toContainEqual(
expect.objectContaining({ channel }),
);
};
const rootFixture = (body: string, expose = true) =>
bundle(
expose
? `electron.contextBridge.exposeInMainWorld("desktop", helper);`
: "",
).replace("exports.sender =", `${body}; exports.sender =`);
it.each([
["null", "||="],
["0", "||="],
["false", "??="],
["null", "??="],
["void 0", "??="],
["true", "&&="],
["null", "&&="],
["({action: () => electron.ipcRenderer.send('prior')})", "||="],
["({action: () => electron.ipcRenderer.send('prior')})", "??="],
["({action: () => electron.ipcRenderer.send('prior')})", "&&="],
])(
"keeps mutable root result uncertain after %s with %s",
(prior, operator) => {
expectGuardedRoot(
rootFixture(
`module.exports = ${prior}; module.exports ${operator} {action: () => electron.ipcRenderer.send("rhs")}`,
),
operator,
);
},
);
it.each(["||=", "??=", "&&="])(
"keeps a guarded candidate without a prior root write for %s",
(operator) => {
expectGuardedRoot(
rootFixture(
`module.exports ${operator} {action: () => electron.ipcRenderer.send("rhs")}`,
),
operator,
);
},
);
it.each(["||=", "??=", "&&="])(
"keeps unknown prior root replacement guarded for %s",
(operator) => {
expectGuardedRoot(
rootFixture(
`module.exports = unknownValue; module.exports ${operator} {action: () => electron.ipcRenderer.send("rhs")}`,
),
operator,
);
},
);
it.each(["||=", "??="])(
"does not claim a known prior root callable for %s",
(operator) => {
expectGuardedRoot(
rootFixture(
`module.exports = () => electron.ipcRenderer.send("prior");
const selected = (module.exports ${operator} () => electron.ipcRenderer.send("rhs"));
electron.contextBridge.exposeInMainWorld("desktop", {action: selected});`,
false,
),
operator,
);
},
);
it.each(["||=", "??="])(
"does not borrow a later root write when evaluating %s",
(operator) => {
expectGuardedRoot(
rootFixture(
`module.exports = null;
const selected = (module.exports ${operator} {action: () => electron.ipcRenderer.send("selected")});
module.exports = {action: () => electron.ipcRenderer.send("later")};
electron.contextBridge.exposeInMainWorld("desktop", selected);`,
false,
),
operator,
"module.exports",
"selected",
);
},
);
it.each(["if (flag) module.exports = null;", "module[key] = null;"])(
"keeps ambiguous earlier root writes uncertain: %s",
(prior) => {
expectGuardedRoot(
rootFixture(
`${prior}
const selected = (module.exports ||= () => electron.ipcRenderer.send("rhs"));
electron.contextBridge.exposeInMainWorld("desktop", {action: selected});`,
false,
),
"||=",
);
},
);
it.each([
["null", "const alias = module; alias.exports = {};", "&&="],
["{}", "const alias = module; alias.exports = null;", "||="],
["{}", "const alias = module; alias.exports = null;", "??="],
["null", "Object.assign(module, {exports: {}});", "&&="],
["null", "replaceExports(module);", "&&="],
["null", "const box = {holder: module}; box.holder.exports = {};", "&&="],
[
"null",
"const {holder: alias} = {holder: module}; alias.exports = {};",
"&&=",
],
])(
"keeps guarded root candidates after escape: %s; %s; %s",
(prior, escape, operator) => {
expectGuardedRoot(
rootFixture(
`module.exports = ${prior}; ${escape} module.exports ${operator} {action: () => electron.ipcRenderer.send("rhs")}`,
),
operator,
);
},
);
it("keeps root candidates guarded in the presence of a shadowed module parameter", () => {
expectGuardedRoot(
rootFixture(`function unrelated(module) {replaceExports(module);}
module.exports = null; module.exports ||= {action: () => electron.ipcRenderer.send("rhs")}`),
"||=",
);
});
it.each([
"module.exports()",
"module.exports?.()",
"module.exports``",
"(module.exports)()",
"(module.exports as Function)()",
"(module.exports!)()",
"const fn = module.exports; fn()",
"(0, module.exports)()",
])(
"keeps mutable root candidates guarded across invocation: %s",
(invocation) => {
expectGuardedRoot(
rootFixture(`module.exports = function() {this.exports = null;};
${invocation}; module.exports ||= {action: () => electron.ipcRenderer.send("rhs")}`),
"||=",
);
},
);
it.each([
"module.exports = null; exports = {};",
"module.exports = null; module.exports = module.exports;",
])(
"does not infer a root value from detached or self-referential writes: %s",
(prior) => {
expectGuardedRoot(
rootFixture(
`${prior} module.exports ||= {action: () => electron.ipcRenderer.send("rhs")}`,
),
"||=",
);
},
);
it.each(["||=", "??=", "&&="])(
"keeps aliased logical assignment targets guarded for %s",
(operator) => {
expectGuardedRoot(
rootFixture(
`const alias = module;
const selected = (alias.exports ${operator} {action: () => electron.ipcRenderer.send("rhs")});
electron.contextBridge.exposeInMainWorld("desktop", selected);`,
false,
),
operator,
"alias.exports",
);
},
);
it.each(["||=", "??=", "&&="])(
"keeps conditional synthetic receivers guarded for %s",
(operator) => {
for (const receiver of [
"(flag ? module : module)",
"(flag ? {exports: true} : module)",
"(flag ? module : {exports: true})",
]) {
expectGuardedRoot(
rootFixture(
`module.exports = null;
const selected = (${receiver}.exports ${operator} {action: () => electron.ipcRenderer.send("rhs")});
electron.contextBridge.exposeInMainWorld("desktop", selected);`,
false,
),
operator,
`${receiver}.exports`,
);
}
},
);
it.each(["||=", "??=", "&&="])(
"preserves ordinary values beside synthetic receivers for %s",
(operator) => {
for (const moduleFirst of [false, true]) {
const ordinary =
operator === "&&="
? "{exports: false}"
: "{exports: () => electron.ipcRenderer.send('left')}";
const receiver = moduleFirst
? `(flag ? module : ${ordinary})`
: `(flag ? ${ordinary} : module)`;
const target = `${receiver}.exports`;
const result = analyzeJavaScriptStaticSource(
rootFixture(
`const selected = (${target} ${operator} () => electron.ipcRenderer.send("right"));
electron.contextBridge.exposeInMainWorld("desktop", {action: selected});`,
false,
),
);
const paths = result.electron.call_paths
?.map(({ channel, conditions, resolution }) => ({
channel,
conditions: conditions.map(({ expression }) => expression),
resolution,
}))
.sort((a, b) => String(a.channel).localeCompare(String(b.channel)));
expect(paths).toEqual([
...(operator === "&&="
? []
: [
{
channel: "left",
conditions: [
moduleFirst ? "!(flag)" : "flag",
operator === "||="
? target
: `(${target}) !== null && (${target}) !== undefined`,
],
resolution: "candidate",
},
]),
{
channel: "right",
conditions: [
operator === "&&="
? target
: operator === "||="
? `!(${target})`
: `(${target}) === null || (${target}) === undefined`,
],
resolution: "candidate",
},
]);
expect(result.electron.ipc).toContainEqual(
expect.objectContaining({ channel: "right" }),
);
if (operator !== "&&=")
expect(result.electron.ipc).toContainEqual(
expect.objectContaining({ channel: "left" }),
);
}
},
);
it.each(["(module)", "(module as any)", "(module!)"])(
"recognizes wrapped synthetic receivers: %s",
(receiver) => {
expectGuardedRoot(
rootFixture(
`const selected = (${receiver}.exports ||= {action: () => electron.ipcRenderer.send("rhs")});
electron.contextBridge.exposeInMainWorld("desktop", selected);`,
false,
),
"||=",
`${receiver}.exports`,
);
},
);
it.each(["||=", "??=", "&&="])(
"preserves uncertainty through module exports snapshots for %s",
(operator) => {
for (const [setup, target] of [
["", "({exports: module.exports}).exports"],
["const snapshot = module.exports;", "({exports: snapshot}).exports"],
["", "[module.exports][0]"],
]) {
expectGuardedRoot(
rootFixture(
`module.exports = null; ${setup}
const selected = (${target} ${operator} {action: () => electron.ipcRenderer.send("rhs")});
electron.contextBridge.exposeInMainWorld("desktop", selected);`,
false,
),
operator,
target,
);
}
},
);
it.each(["saved", "!saved"])(
"keeps primitive root snapshot branch uncertainty for %s",
(test) => {
const result = analyzeJavaScriptStaticSource(
rootFixture(
`module.exports = null; const saved = module.exports;
electron.contextBridge.exposeInMainWorld("desktop", {action() {
if (${test}) electron.ipcRenderer.send("then");
else electron.ipcRenderer.send("else");
}});`,
false,
),
);
expect(
result.electron.call_paths
?.map(({ channel, conditions }) => ({
channel,
conditions: conditions.map((c) => c.expression),
}))
.sort((a, b) => String(a.channel).localeCompare(String(b.channel))),
).toEqual([
{ channel: "else", conditions: [`!(${test})`] },
{ channel: "then", conditions: [test] },
]);
},
);
it.each(["||", "??", "&&"])(
"keeps primitive root logical snapshots uncertain for %s",
(operator) => {
expectGuardedRoot(
rootFixture(
`module.exports = null; const saved = module.exports;
const selected = saved ${operator} {action: () => electron.ipcRenderer.send("rhs")};
electron.contextBridge.exposeInMainWorld("desktop", selected);`,
false,
),
`${operator}=`,
"saved",
);
},
);
it.each(["module.exports", "({saved: module.exports}).saved"])(
"preserves namespace members through plain logical selection of %s",
(target) => {
for (const operator of ["||", "??"]) {
const result = analyzeJavaScriptStaticSource(
rootFixture(
`exports.action = () => electron.ipcRenderer.send("left");
const selected = ${target} ${operator} {};
electron.contextBridge.exposeInMainWorld("desktop", selected);`,
false,
),
);
expect(
result.electron.call_paths?.map(({ channel, conditions }) => ({
channel,
conditions: conditions.map((c) => c.expression),
})),
).toEqual([
{
channel: "left",
conditions: [
operator === "||"
? target
: `(${target}) !== null && (${target}) !== undefined`,
],
},
]);
}
},
);
it("preserves later member writes through a saved module exports reference", () => {
const result = analyzeJavaScriptStaticSource(
rootFixture(
`const saved = module.exports;
exports.action = () => electron.ipcRenderer.send("later-member");
electron.contextBridge.exposeInMainWorld("desktop", saved);`,
false,
),
);
expect(
result.electron.call_paths?.map(({ channel, conditions }) => ({
channel,
conditions,
})),
).toEqual([{ channel: "later-member", conditions: [] }]);
});
it.each(["||=", "??=", "&&="])(
"recognizes whole-target wrappers for %s",
(operator) => {
for (const target of [
"(module.exports as any)",
"(module.exports!)",
"(module.exports satisfies any)",
"(module.exports)",
]) {
expectGuardedRoot(
rootFixture(
`module.exports = null;
const selected = (${target} ${operator} {action: () => electron.ipcRenderer.send("rhs")});
electron.contextBridge.exposeInMainWorld("desktop", selected);`,
false,
),
operator,
target.slice(1, -1),
);
const ordinary = target.replace(
"module.exports",
`({exports: ${operator === "&&=" ? "false" : "true"}}).exports`,
);
const result =
analyzeJavaScriptStaticSource(`const e = require("electron");
e.contextBridge.exposeInMainWorld("desktop", {action() {
(${ordinary} ${operator} () => e.ipcRenderer.send("skipped"))();
}});`);
expect(result.electron.call_paths ?? []).toEqual([]);
expect(result.electron.ipc).toContainEqual(
expect.objectContaining({ channel: "skipped" }),
);
}
},
);
it.each(["||=", "??="])(
"keeps an ordinary object's exports slot precise for %s",
(operator) => {
const result = analyzeJavaScriptStaticSource(`const e=require("electron");
function action(){(({exports: true}).exports ${operator} () => e.ipcRenderer.send("skipped"))();}
e.contextBridge.exposeInMainWorld("desktop",{action});`);
expect(result.electron.call_paths ?? []).toEqual([]);
},
);
it("does not follow a statically false callback branch", () => {
const result = analyzeJavaScriptStaticSource(
bundle(
`helper.events.addListener("example:copy",event=>{if(false)event.sender.copy()});`,
),
);
expect(result.electron.call_paths ?? []).toEqual([]);
});
it("retains early rejection guards and excludes calls after definite returns", () => {
const guarded = analyzeJavaScriptStaticSource(
`const e=require("electron");e.ipcMain.on("guard",event=>{if(!allowed(event))return;event.sender.copy()});`,
);
expect(guarded.electron.call_paths).toContainEqual(
expect.objectContaining({
conditions: [
expect.objectContaining({ expression: "!(!allowed(event))" }),
],
}),
);
for (const body of [
"return;event.sender.copy()",
"if(true)return;event.sender.copy()",
"if(false)event.sender.copy()",
])
expect(
analyzeJavaScriptStaticSource(
`const e=require("electron");e.ipcMain.on("dead",event=>{${body}});`,
).electron.call_paths ?? [],
).toEqual([]);
expect(
analyzeJavaScriptStaticSource(
`const e=require("electron");if(false)e.ipcMain.on("dead",event=>event.sender.copy());`,
).electron.call_paths ?? [],
).toEqual([]);
});
it("rejects dynamic channels, computed overwrites, unknown spreads and reassigned callback parameters", () => {
for (const entry of [
`helper.events.addListener(runtimeChannel,event=>event.sender.copy());`,
`electron[runtimeKey]={};electron.ipcMain.on("bad",event=>event.sender.copy());`,
`const api={copy:helper.sender("bad"),...unknownApi};electron.contextBridge.exposeInMainWorld("desktop",api);`,
`helper.events.addListener("bad",event=>{event=other;event.sender.copy()});`,
])
expect(
analyzeJavaScriptStaticSource(bundle(entry)).electron.call_paths ?? [],
).toEqual([]);
});
it("resolves renamed default and namespace import helpers from their syntax", () => {
const result = analyzeJavaScriptStaticSource(
bundle(`
const defaultImport=x=>x&&x.__esModule?x:{default:x};
function namespaceImport(x){if(x&&x.__esModule)return x;return unknownWrap(x)}
const E=defaultImport(load(2)),H=namespaceImport(load(5));
E.default.contextBridge.exposeInMainWorld("renamed",{copy:(0,H.sender)("test:renamed")});
`),
);
expect(result.electron.call_paths).toContainEqual(
expect.objectContaining({
entry: "renamed.copy",
channel: "test:renamed",
terminal: "electron.ipcRenderer.send",
}),
);
expect(
result.electron.call_paths
?.flatMap((p) => p.steps)
.every((step) => step.label.length > 0),
).toBe(true);
});
it("resolves an empty bootstrap module key through an exported Electron bridge", () => {
const result = analyzeJavaScriptStaticSource(`(() => {
const modules = {
""(module) { module.exports = require("electron"); },
9(module, exports, load) {
const electron = load("");
electron.contextBridge.exposeInMainWorld("desktop", {
copy: () => electron.ipcRenderer.send("test:empty-module"),
});
},
};
function load(id) {
const module = { exports: {} };
modules[id].call(module.exports, module, module.exports, load);
return module.exports;
}
load(9);
})();`);
expect(result.bundler_registrations).toMatchObject([
{
entry_module_keys: ["9"],
modules: [{ module_key: "" }, { module_key: "9" }],
},
]);
expect(result.electron.call_paths).toContainEqual(
expect.objectContaining({
entry: "desktop.copy",
channel: "test:empty-module",
terminal: "electron.ipcRenderer.send",
}),
);
});
it("does not trust helper names or follow returns after a definite throw", () => {
for (const helper of [
`function __toESM() {return {ipcRenderer:{send(){}}}}`,
`function __toESM(value) {throw Error("inert");return value;}`,
`function __toESM(value) {if(true){throw Error("inert")}return value;}`,
]) {
const result = analyzeJavaScriptStaticSource(`
const electron = require("electron");
${helper}
const wrapped = __toESM(electron);
electron.contextBridge.exposeInMainWorld("desktop",{
copy:()=>wrapped.ipcRenderer.send("test:copy")
});
`);
expect(result.electron.call_paths ?? []).toEqual([]);
}
});
describe("wrapped Electron API identity", () => {
it("does not restore rejected Electron identities through wrapper substitution", () => {
for (const source of [
`const e=require("electron");e.ipcMain={on(){}};e.ipcMain.on("bad",event=>event.sender.copy());`,
`function require(){return {ipcMain:{on(){}}}};const e=require("electron");e.ipcMain.on("bad",event=>event.sender.copy());`,
`const e=require("electron");const ipc=e.ipcRenderer,alias=ipc;delete alias.send;function send(channel){ipc.send(channel)}send("bad");`,
`require("electron/renderer").ipcRenderer={};const e=require("electron");function send(channel){e.ipcRenderer.send(channel)}send("bad");`,
`const e=require("electron");[e.ipcRenderer]=replacements;function send(channel){e.ipcRenderer.send(channel)}send("bad");`,
`const e=require("electron");for(e.contextBridge of replacements){}function expose(api){e.contextBridge.exposeInMainWorld("api",api)}expose({copy:()=>navigator.clipboard.writeText("bad")});`,
`const e=require("electron");const ipc=e.ipcRenderer;Reflect.deleteProperty(ipc,"send");function send(channel){ipc.send(channel)}send("bad");`,
]) {
const { electron } = analyzeJavaScriptStaticSource(source);
expect(electron.call_paths ?? []).toEqual([]);
expect(electron.ipc).toEqual([]);
expect(electron.context_bridge_apis).toEqual([]);
}
});
it("keeps unaffected Electron methods available after a sibling method write", () => {
const { electron } = analyzeJavaScriptStaticSource(`
const e=require("electron");
delete e.ipcRenderer.send;
function invoke(channel){e.ipcRenderer.invoke(channel)}
invoke("good");
`);
expect(electron.ipc).toContainEqual(
expect.objectContaining({ channel: "good", operation: "invoke" }),
);
});
});
it.each([false, true])(
"preserves a guarded bridge entry sharing a registration with an unconditional member (reverse=%s)",
(reverse) => {
const members = ["always:register", "conditional:flag?register:()=>{}"];
if (reverse) members.reverse();
const result = analyzeJavaScriptStaticSource(`const e=require("electron");
function register(){e.ipcMain.on("bridge:register",()=>{});}
e.contextBridge.exposeInMainWorld("api",{${members.join(",")}});`);
expect(result.electron.call_paths).toContainEqual(
expect.objectContaining({
entry_kind: "bridge-member",
entry: "api.conditional",
terminal: "electron.ipcMain.on",
conditions: expect.arrayContaining([
expect.objectContaining({ expression: "flag" }),
]),
}),
);
},
);