fix(pdf): stop page tools failing on short and encrypted PDFs (#594)

Empty the hardcoded page-range default in remove/split/extract PDF tools (remove-pages defaulted to "2,4-6", out of range for any PDF under 6 pages) and disable submit until a range is entered. Reject password-protected PDFs up front for PDF-only tools with guidance to unlock first, instead of failing cryptically in the qpdf worker. Adds integration + e2e coverage.
This commit is contained in:
SnapOtter
2026-07-21 06:14:43 +00:00
committed by GitHub
parent 4ba7503f15
commit 73df107758
11 changed files with 173 additions and 9 deletions
+23
View File
@@ -5,6 +5,7 @@ import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from
const PDF = readFixture(fixtures.document.pdf3);
const SIG = readFixture(fixtures.image.base.png200);
const ENCRYPTED_PDF = readFixture(fixtures.document.encrypted);
// The stamping test invokes the docs profile's doc_sign script (PyMuPDF) and is
// gated on fitz so it skips where PyMuPDF is not installed (e.g. CI integration
@@ -136,6 +137,28 @@ describe("sign-pdf", () => {
expect(JSON.parse(res.body)).toMatchObject({ error: "Invalid PDF" });
});
it("rejects a password-protected PDF before enqueueing work", async () => {
// A signature can't be stamped onto an encrypted PDF without the password;
// reject it up front (before any Python call) with guidance to unlock first.
const res = await postFields([
{
name: "file",
filename: "encrypted.pdf",
contentType: "application/pdf",
content: ENCRYPTED_PDF,
},
{ name: "sig0", filename: "sig0.png", contentType: "image/png", content: SIG },
{
name: "placements",
content: JSON.stringify([{ sig: 0, page: 0, x: 0, y: 0, w: 0.25, h: 0.1 }]),
},
]);
expect(res.statusCode).toBe(400);
const body = JSON.parse(res.body);
expect(body.details || body.error).toMatch(/password-protected|unlock/i);
});
it("rejects an invalid signature image before enqueueing work", async () => {
const res = await postFields([
{ name: "file", filename: "in.pdf", contentType: "application/pdf", content: PDF },