feat(import): harden untrusted spreadsheet boundaries
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import { cp, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
MAX_DISPO_WORKBOOK_BYTES,
|
||||
readWorksheetMatrix,
|
||||
} from "../use-cases/dispo-import/read-workbook.js";
|
||||
|
||||
const referenceWorkbookPath = fileURLToPath(
|
||||
new URL("../../../../samples/Dispov2/MandatoryDispoCategories_V3.xlsx", import.meta.url),
|
||||
);
|
||||
|
||||
const tempDirectories: string[] = [];
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(
|
||||
tempDirectories.splice(0).map(async (directory) => {
|
||||
await rm(directory, { recursive: true, force: true });
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
async function makeTempDirectory(): Promise<string> {
|
||||
const directory = await mkdtemp(path.join(os.tmpdir(), "capakraken-read-workbook-"));
|
||||
tempDirectories.push(directory);
|
||||
return directory;
|
||||
}
|
||||
|
||||
describe("readWorksheetMatrix", () => {
|
||||
it("reads trusted xlsx worksheets through the hardened reader", async () => {
|
||||
const rows = await readWorksheetMatrix(referenceWorkbookPath, "EID-Attr");
|
||||
|
||||
expect(rows.length).toBeGreaterThan(0);
|
||||
expect(rows.some((row) => row.length > 0)).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects legacy .xls workbook paths", async () => {
|
||||
const directory = await makeTempDirectory();
|
||||
const legacyPath = path.join(directory, "legacy-input.xls");
|
||||
await cp(referenceWorkbookPath, legacyPath);
|
||||
|
||||
await expect(readWorksheetMatrix(legacyPath, "EID-Attr")).rejects.toThrow(
|
||||
'Only .xlsx workbooks are supported for dispo imports',
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects oversized workbook files before parsing", async () => {
|
||||
const directory = await makeTempDirectory();
|
||||
const oversizedPath = path.join(directory, "oversized.xlsx");
|
||||
await writeFile(oversizedPath, Buffer.alloc(MAX_DISPO_WORKBOOK_BYTES + 1, 0));
|
||||
|
||||
await expect(readWorksheetMatrix(oversizedPath, "Sheet1")).rejects.toThrow(
|
||||
"Workbook file exceeds the",
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user