Skip to content

Commit d1d79da

Browse files
bajrangCoderclaude
andcommitted
fix: dispatch worker actions through a Map
CodeQL still flagged `actions[action](...)` as an unvalidated dynamic method call even with the hasOwnProperty guard. Looking handlers up in a Map means a message's action name can only reach the defined handlers, never inherited Object methods, and avoids Object.hasOwn (Chrome 93+). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 0cc6252 commit d1d79da

2 files changed

Lines changed: 57 additions & 55 deletions

File tree

‎plugin.zip‎

-13 Bytes
Binary file not shown.

‎src/worker.js‎

Lines changed: 57 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -60,71 +60,73 @@ async function loadPyodideAndPackages(baseUrl = "", packages) {
6060
}
6161
}
6262

63-
const actions = {
64-
async init(data) {
65-
const { packages, baseUrl, cacheFileUrl } = data;
66-
self.cacheFileUrl = cacheFileUrl;
67-
try {
68-
await loadPyodideAndPackages(baseUrl, packages);
63+
// A Map, so a message's action name can only reach these handlers and never
64+
// inherited Object methods like `constructor` (Object.hasOwn needs Chrome 93)
65+
const actions = new Map(
66+
Object.entries({
67+
async init(data) {
68+
const { packages, baseUrl, cacheFileUrl } = data;
69+
self.cacheFileUrl = cacheFileUrl;
70+
try {
71+
await loadPyodideAndPackages(baseUrl, packages);
6972

70-
// override python input
71-
await self.pyodide.runPython(`import sys
73+
// override python input
74+
await self.pyodide.runPython(`import sys
7275
def input(prompt=''):
7376
print(prompt)
7477
return sys.stdin.readline().strip()
7578
7679
__builtins__.input = input
7780
`);
78-
self.postMessage({
79-
action: "init",
80-
success: true,
81-
});
82-
} catch (error) {
83-
postInitError(error);
84-
}
85-
},
86-
async run(data) {
87-
const { code } = data;
88-
if (!self.pyodide) {
89-
self.postMessage({
90-
action: "run",
91-
success: false,
92-
error: "Python is not loaded yet.",
93-
});
94-
return;
95-
}
96-
try {
97-
await self.pyodide.loadPackagesFromImports(code, {
98-
messageCallback: stdout,
99-
errorCallback: stderr,
100-
});
101-
const output = await self.pyodide.runPythonAsync(code);
102-
self.postMessage({
103-
action: "run",
104-
success: true,
105-
output: output?.toString() ?? output ?? "",
106-
});
107-
} catch (error) {
108-
self.postMessage({
109-
action: "run",
110-
success: false,
111-
error: error?.message ?? error?.toString(),
112-
});
113-
}
114-
},
115-
input(data) {
116-
const { line } = data;
117-
self.line = line;
118-
},
119-
};
81+
self.postMessage({
82+
action: "init",
83+
success: true,
84+
});
85+
} catch (error) {
86+
postInitError(error);
87+
}
88+
},
89+
async run(data) {
90+
const { code } = data;
91+
if (!self.pyodide) {
92+
self.postMessage({
93+
action: "run",
94+
success: false,
95+
error: "Python is not loaded yet.",
96+
});
97+
return;
98+
}
99+
try {
100+
await self.pyodide.loadPackagesFromImports(code, {
101+
messageCallback: stdout,
102+
errorCallback: stderr,
103+
});
104+
const output = await self.pyodide.runPythonAsync(code);
105+
self.postMessage({
106+
action: "run",
107+
success: true,
108+
output: output?.toString() ?? output ?? "",
109+
});
110+
} catch (error) {
111+
self.postMessage({
112+
action: "run",
113+
success: false,
114+
error: error?.message ?? error?.toString(),
115+
});
116+
}
117+
},
118+
input(data) {
119+
const { line } = data;
120+
self.line = line;
121+
},
122+
}),
123+
);
120124

121125
self.onmessage = async (e) => {
122-
const { action } = e.data;
126+
const handler = actions.get(e.data.action);
123127

124-
// only the handlers defined above, never inherited Object methods
125-
// biome-ignore lint/suspicious/noPrototypeBuiltins: Object.hasOwn needs Chrome 93, the build targets Chrome 90
126-
if (Object.prototype.hasOwnProperty.call(actions, action)) {
127-
await actions[action](e.data);
128+
if (handler) {
129+
await handler(e.data);
128130
}
129131
};
130132

0 commit comments

Comments
 (0)