Checkpoint web parity through Chromium input tasks
This commit is contained in:
53
tools/web/server-job-isolation.mjs
Normal file
53
tools/web/server-job-isolation.mjs
Normal file
@@ -0,0 +1,53 @@
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
export const SERVER_JOB_DIRECTORY_SCHEMA = 1;
|
||||
const JOB_ID = /^[-A-Za-z0-9:_./]{1,256}$/;
|
||||
|
||||
function validateJobId(jobId) {
|
||||
if (typeof jobId !== "string" || !JOB_ID.test(jobId) || jobId.includes("..")) throw new Error("SERVER_JOB_DIRECTORY_INVALID: jobId is invalid");
|
||||
}
|
||||
|
||||
function validateRoot(root) {
|
||||
if (typeof root !== "string" || !path.isAbsolute(root)) throw new Error("SERVER_JOB_DIRECTORY_INVALID: root must be absolute");
|
||||
return path.resolve(root);
|
||||
}
|
||||
|
||||
export async function createServerJobDirectory(root, jobId) {
|
||||
const resolvedRoot = validateRoot(root);
|
||||
validateJobId(jobId);
|
||||
await fs.mkdir(resolvedRoot, { recursive: true, mode: 0o700 });
|
||||
const randomPrefix = `.blender-job-${crypto.randomUUID()}-`;
|
||||
const directory = await fs.mkdtemp(path.join(resolvedRoot, randomPrefix), { encoding: "utf8" });
|
||||
await fs.chmod(directory, 0o700);
|
||||
return Object.freeze({ schemaVersion: SERVER_JOB_DIRECTORY_SCHEMA, jobId, root: resolvedRoot, path: directory, directoryName: path.basename(directory), state: "ALLOCATED", cleanupCount: 0 });
|
||||
}
|
||||
|
||||
export async function cleanupServerJobDirectory(job) {
|
||||
if (!job || job.schemaVersion !== SERVER_JOB_DIRECTORY_SCHEMA || typeof job.path !== "string" || typeof job.root !== "string") throw new Error("SERVER_JOB_DIRECTORY_INVALID: receipt is invalid");
|
||||
if (job.state === "CLEANED") return job;
|
||||
const root = validateRoot(job.root);
|
||||
const directory = path.resolve(job.path);
|
||||
if (path.dirname(directory) !== root || !path.basename(directory).startsWith(".blender-job-")) throw new Error("SERVER_JOB_DIRECTORY_INVALID: directory escaped the job root");
|
||||
await fs.chmod(directory, 0o700);
|
||||
try { await fs.chmod(path.join(directory, "source"), 0o700); } catch (error) { if (error?.code !== "ENOENT") throw error; }
|
||||
await fs.rm(directory, { recursive: true, force: false });
|
||||
return Object.freeze({ ...job, state: "CLEANED", cleanupCount: 1 });
|
||||
}
|
||||
|
||||
export async function prepareServerJobWorkspace(job, sourceBytes, sourceName = "source.blend") {
|
||||
if (!job || job.schemaVersion !== SERVER_JOB_DIRECTORY_SCHEMA || job.state !== "ALLOCATED") throw new Error("SERVER_JOB_WORKSPACE_INVALID: job receipt is not allocated");
|
||||
if (!(sourceBytes instanceof Uint8Array) || sourceBytes.byteLength < 1) throw new Error("SERVER_JOB_WORKSPACE_INVALID: source bytes are empty");
|
||||
if (typeof sourceName !== "string" || !/^[A-Za-z0-9_.-]{1,128}$/.test(sourceName) || sourceName.includes("..")) throw new Error("SERVER_JOB_WORKSPACE_INVALID: source name is invalid");
|
||||
const sourceDirectory = path.join(job.path, "source");
|
||||
const outputDirectory = path.join(job.path, "output");
|
||||
await fs.mkdir(sourceDirectory, { mode: 0o700 });
|
||||
await fs.mkdir(outputDirectory, { mode: 0o700 });
|
||||
const sourcePath = path.join(sourceDirectory, sourceName);
|
||||
await fs.writeFile(sourcePath, sourceBytes, { mode: 0o444, flag: "wx" });
|
||||
await fs.chmod(sourceDirectory, 0o555);
|
||||
await fs.chmod(sourcePath, 0o444);
|
||||
await fs.chmod(outputDirectory, 0o700);
|
||||
return Object.freeze({ schemaVersion: SERVER_JOB_DIRECTORY_SCHEMA, sourceDirectory, sourcePath, outputDirectory, sourceMode: "0444", sourceDirectoryMode: "0555", outputDirectoryMode: "0700", sourceReadOnly: true, outputWritable: true });
|
||||
}
|
||||
Reference in New Issue
Block a user