46 lines
1.8 KiB
JavaScript
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"));
|
|
});
|