33 lines
1.4 KiB
TypeScript
33 lines
1.4 KiB
TypeScript
// 沙箱子进程入口:先加载任务表,再撤销全部权限,然后从 stdin 读一条 {job, input},把 {ok, result | error} 写到 stdout。
|
|
// 开发 / 测试由 deno run 直接跑本文件;编译二进制以 `<自身> --role sandbox` 拉起(main.ts 在加载其余模块前分派)。
|
|
import { SANDBOX_JOBS } from "./jobs.ts";
|
|
|
|
const PERMISSIONS = ["read", "write", "net", "env", "run", "ffi", "sys"] as const;
|
|
|
|
async function writeAll(bytes: Uint8Array) {
|
|
let off = 0;
|
|
while (off < bytes.length) off += await Deno.stdout.write(bytes.subarray(off));
|
|
}
|
|
|
|
export async function sandboxWorkerMain(): Promise<void> {
|
|
for (const name of PERMISSIONS) {
|
|
try {
|
|
Deno.permissions.revokeSync({ name } as Deno.PermissionDescriptor);
|
|
} catch {
|
|
// 运行时不认识的权限名:跳过
|
|
}
|
|
}
|
|
let out: unknown;
|
|
try {
|
|
const req = JSON.parse(await new Response(Deno.stdin.readable).text()) as { job: string; input: unknown };
|
|
const fn = (SANDBOX_JOBS as Record<string, (i: unknown) => unknown>)[req.job];
|
|
if (!fn) throw new Error(`没有这个沙箱任务:${req.job}`);
|
|
out = { ok: true, result: await fn(req.input) };
|
|
} catch (e) {
|
|
out = { ok: false, error: `${(e as Error).name}: ${(e as Error).message}`.slice(0, 2000) };
|
|
}
|
|
await writeAll(new TextEncoder().encode(`${JSON.stringify(out)}\n`));
|
|
}
|
|
|
|
if (import.meta.main) await sandboxWorkerMain();
|