Files
snowspeeder 824a964f9d
Test and deploy / test-and-deploy (push) Successful in 2m28s
Rebuild printable roast plans and remove machine-based adjustments
2026-09-05 14:56:11 -04:00

46 lines
1.8 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import { mkdtemp, writeFile, symlink, rm, mkdir } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { readAlogFromLibrary } from "../server/alog-library.js";
import { setup, signup } from "./helpers.js";
test("server filesystem roast library is restricted to administrators", async () => {
const { agent, db } = await setup();
await signup(agent, "[email protected]");
assert.equal((await agent.get("/api/alog/library")).status, 403);
assert.equal((await agent.get("/api/alog/library/example.alog")).status, 403);
await db.query("UPDATE users SET role='admin' WHERE email=$1", [
"[email protected]",
]);
assert.equal((await agent.get("/api/alog/library")).status, 200);
});
test("library reader rejects path traversal and symlinks outside its directory", async (t) => {
const root = await mkdtemp(path.join(os.tmpdir(), "roast-library-"));
const old = process.env.ALOG_DIR;
process.env.ALOG_DIR = path.join(root, "library");
await mkdir(process.env.ALOG_DIR);
t.after(async () => {
if (old === undefined) delete process.env.ALOG_DIR;
else process.env.ALOG_DIR = old;
await rm(root, { recursive: true, force: true });
});
const content = JSON.stringify({
timex: [0, 60, 120],
temp1: [20, 30, 40],
temp2: [30, 40, 50],
mode: "C",
});
await writeFile(path.join(root, "outside.alog"), content);
await writeFile(path.join(process.env.ALOG_DIR, "inside.alog"), content);
await symlink(
path.join(root, "outside.alog"),
path.join(process.env.ALOG_DIR, "link.alog"),
);
await assert.rejects(readAlogFromLibrary("../outside.alog"), {
code: "bad_filename",
});
await assert.rejects(readAlogFromLibrary("link.alog"), { code: "not_found" });
assert.ok(await readAlogFromLibrary("inside.alog"));
});