Fix signature fields with widget children

This commit is contained in:
calixteman 2026-07-14 22:38:43 +02:00
parent 5e3272c929
commit 82c6046e1d
No known key found for this signature in database
GPG Key ID: 0C5442631EE0691F
2 changed files with 44 additions and 12 deletions

View File

@ -2009,20 +2009,19 @@ class PDFDocument {
if (!(field instanceof Dict)) { if (!(field instanceof Dict)) {
continue; continue;
} }
if (isName(field.get("FT"), "Sig")) {
const sigDict = this.xref.fetchIfRef(field.get("V"));
if (sigDict instanceof Dict) {
const parsed = this.#parseSignatureDict(field, sigDict, fieldRef);
if (parsed) {
out.push(parsed);
}
}
}
if (field.has("Kids")) { if (field.has("Kids")) {
// A terminal field can have Widget annotations as children, so its
// own signature must be collected before walking the field tree.
this.#collectSignatureFields(field.get("Kids"), out, visitedRefs); this.#collectSignatureFields(field.get("Kids"), out, visitedRefs);
continue;
}
if (!isName(field.get("FT"), "Sig")) {
continue;
}
const sigDict = this.xref.fetchIfRef(field.get("V"));
if (!(sigDict instanceof Dict)) {
continue;
}
const parsed = this.#parseSignatureDict(field, sigDict, fieldRef);
if (parsed) {
out.push(parsed);
} }
} }
} }

View File

@ -312,6 +312,39 @@ describe("document", function () {
expect(signatures[0].signerName).toEqual("John Smith"); expect(signatures[0].signerName).toEqual("John Smith");
}); });
it("extracts signature fields with Widget children", async function () {
const acroForm = new Dict();
acroForm.set("SigFlags", 3);
const sigRef = Ref.get(33, 0);
const sigFieldRef = Ref.get(34, 0);
const widgetRef = Ref.get(35, 0);
const sigDict = makeSigDict({
byteRange: [0, 50, 100, 150],
name: "Alice",
});
const sigField = makeSigField({ T: "sig_alice", sigRef });
sigField.set("Kids", [widgetRef]);
const widget = new Dict();
widget.set("Subtype", Name.get("Widget"));
widget.set("Parent", sigFieldRef);
const xref = new XRefMock([
{ ref: sigRef, data: sigDict },
{ ref: sigFieldRef, data: sigField },
{ ref: widgetRef, data: widget },
]);
acroForm.set("Fields", [sigFieldRef]);
const pdfDocument = getDocument(acroForm, xref);
const signatures = await pdfDocument.signatures;
expect(signatures.length).toEqual(1);
expect(signatures[0].fieldName).toEqual("sig_alice");
expect(signatures[0].signerName).toEqual("Alice");
});
it("skips signatures with malformed ByteRange", async function () { it("skips signatures with malformed ByteRange", async function () {
const acroForm = new Dict(); const acroForm = new Dict();
acroForm.set("SigFlags", 3); acroForm.set("SigFlags", 3);