🚧 signDocument using node signpdf and custom placeholder insert

This commit is contained in:
Timur Ercan
2023-03-01 19:54:22 +01:00
parent 02e225517c
commit 8387179cbf
7 changed files with 203 additions and 21 deletions

View File

@ -0,0 +1,55 @@
const { PDFArray, CharCodes } = require("pdf-lib");
/**
* Extends PDFArray class in order to make ByteRange look like this:
* /ByteRange [0 /********** /********** /**********]
* Not this:
* /ByteRange [ 0 /********** /********** /********** ]
*/
class PDFArrayCustom extends PDFArray {
static withContext(context) {
return new PDFArrayCustom(context);
}
clone(context) {
const clone = PDFArrayCustom.withContext(context || this.context);
for (let idx = 0, len = this.size(); idx < len; idx++) {
clone.push(this.array[idx]);
}
return clone;
}
toString() {
let arrayString = "[";
for (let idx = 0, len = this.size(); idx < len; idx++) {
arrayString += this.get(idx).toString();
if (idx < len - 1) arrayString += " ";
}
arrayString += "]";
return arrayString;
}
sizeInBytes() {
let size = 2;
for (let idx = 0, len = this.size(); idx < len; idx++) {
size += this.get(idx).sizeInBytes();
if (idx < len - 1) size += 1;
}
return size;
}
copyBytesInto(buffer, offset) {
const initialOffset = offset;
buffer[offset++] = CharCodes.LeftSquareBracket;
for (let idx = 0, len = this.size(); idx < len; idx++) {
offset += this.get(idx).copyBytesInto(buffer, offset);
if (idx < len - 1) buffer[offset++] = CharCodes.Space;
}
buffer[offset++] = CharCodes.RightSquareBracket;
return offset - initialOffset;
}
}
module.exports = PDFArrayCustom;

View File

@ -1,26 +1,78 @@
const signer = require("../../node_modules/node-signpdf/dist/signpdf");
const {
pdfkitAddPlaceholder,
} = require("../../node_modules/node-signpdf/dist/helpers/pdfkitAddPlaceholder");
import * as fs from "fs";
const fs = require("fs");
const signer = require("./node-signpdf/dist/signpdf");
import {
PDFDocument,
PDFName,
PDFNumber,
PDFHexString,
PDFString,
} from "pdf-lib";
export const signDocument = (documentAsBase64: string): any => {
export const signDocument = async (documentAsBase64: string): Promise<any> => {
// Custom code to add Byterange to PDF
const PDFArrayCustom = require("./PDFArrayCustom");
// The PDF we're going to sign
const pdfBuffer = Buffer.from(documentAsBase64, "base64");
const certBuffer = fs.readFileSync("public/certificate.p12");
console.log("adding placeholder..");
console.log(signer.pdfkitAddPlaceholder);
const inputBuffer = signer.pdfkitAddPlaceholder({
pdfBuffer,
reason: "Signed Certificate.",
contactInfo: "sign@example.com",
name: "Example",
location: "Jakarta",
signatureLength: certBuffer.length,
// The p12 certificate we're going to sign with
const p12Buffer = fs.readFileSync("ressources/certificate.p12");
const SIGNATURE_LENGTH = 4540;
const pdfDoc = await PDFDocument.load(pdfBuffer);
const pages = pdfDoc.getPages();
const ByteRange = PDFArrayCustom.withContext(pdfDoc.context);
ByteRange.push(PDFNumber.of(0));
ByteRange.push(PDFName.of(signer.DEFAULT_BYTE_RANGE_PLACEHOLDER));
ByteRange.push(PDFName.of(signer.DEFAULT_BYTE_RANGE_PLACEHOLDER));
ByteRange.push(PDFName.of(signer.DEFAULT_BYTE_RANGE_PLACEHOLDER));
const signatureDict = pdfDoc.context.obj({
Type: "Sig",
Filter: "Adobe.PPKLite",
SubFilter: "adbe.pkcs7.detached",
ByteRange,
Contents: PDFHexString.of("A".repeat(SIGNATURE_LENGTH)),
Reason: PDFString.of("Signed by Documenso"),
M: PDFString.fromDate(new Date()),
});
const signatureDictRef = pdfDoc.context.register(signatureDict);
const widgetDict = pdfDoc.context.obj({
Type: "Annot",
Subtype: "Widget",
FT: "Sig",
Rect: [0, 0, 0, 0],
V: signatureDictRef,
T: PDFString.of("Signature1"),
F: 4,
P: pages[0].ref,
});
const widgetDictRef = pdfDoc.context.register(widgetDict);
// Add our signature widget to the first page
pages[0].node.set(PDFName.of("Annots"), pdfDoc.context.obj([widgetDictRef]));
// Create an AcroForm object containing our signature widget
pdfDoc.catalog.set(
PDFName.of("AcroForm"),
pdfDoc.context.obj({
SigFlags: 3,
Fields: [widgetDictRef],
})
);
const modifiedPdfBytes = await pdfDoc.save({ useObjectStreams: false });
const modifiedPdfBuffer = Buffer.from(modifiedPdfBytes);
const signObj = new signer.SignPdf();
const signedPdfBuffer = signObj.sign(modifiedPdfBuffer, p12Buffer, {
passphrase: "",
});
console.log("signing..");
const signedPdf = new signer.SignPdf().sign(inputBuffer, certBuffer);
return signedPdf;
// Write the signed file
// fs.writeFileSync("./signed.pdf", signedPdfBuffer);
return signedPdfBuffer;
};