vbuch / node-signpdf

Simple signing of PDFs in node.
MIT License
676 stars 174 forks source link

Trouble with Signed PDFs: Valid Signature but No Green Tick in Acrobat #253

Closed ngvhob closed 2 months ago

ngvhob commented 2 months ago

Description: Below is the implementation of a Node.js application for digitally signing PDF documents using the @signpdf/signpdf package. Despite successfully signing the PDF with a valid signature, the Adobe Acrobat software does not display the green tick mark indicating the signature's validity.

const multer = require("multer");
const fs = require("fs");
const path = require("path");
const signpdf = require("@signpdf/signpdf").default;
const { P12Signer } = require("@signpdf/signer-p12");
const { pdflibAddPlaceholder } = require("@signpdf/placeholder-pdf-lib");
const { degrees, PDFDocument, rgb, StandardFonts } = require("pdf-lib");

const storage = multer.diskStorage({
  destination: "uploads/",
  filename: function (req, file, cb) {
    cb(
      null,
      file.fieldname + "-" + Date.now() + path.extname(file.originalname)
    );
  },
});

exports.upload = multer({ storage: storage }).single("file");

exports.signDocument = async (req, res, next) => {
  try {
    const pdfPath = req.file.path;
    const pfxPath = "assets/docsinger.pfx";
    const password = "Mawai@123";
    let pdfBuffer, signedPdfBuffer;
    pdfBuffer = fs.readFileSync(pdfPath);
    let pfxBuffer = fs.readFileSync(pfxPath);
    let pdfDoc = await PDFDocument.load(pdfBuffer);
    const page = pdfDoc.getPages()[0];
    const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica);
    const fontSize = 12;
    const x = 50;
    const y = 500;
    page.drawText("Signed Signature", {
      x: x,
      y: y - 60,
      size: fontSize,
      font: helveticaFont,
      color: rgb(0, 0, 0),
    });
    pdflibAddPlaceholder({
      pdfDoc,
      pdfBuffer,
      reason: "SwiftDocuSign",
      contactInfo: "jebaprince@swiftant.com",
      name: "Jeba Prince",
      location: "SwiftDocuSign",
      date: new Date(),
      signatureLength: 15000,
      widgetRect: [0, 0, 200, 50],
    });

    let pdfBufferWithPlaceholder = Buffer.from(await pdfDoc.save());
    const p12Signer = new P12Signer(pfxBuffer, {
      passphrase: password,
    });

    try {
      signedPdfBuffer = await signpdf.sign(pdfBufferWithPlaceholder, p12Signer);
      console.log("Signing done!", signedPdfBuffer);
    } catch (error) {
      throw new Error(error);
    }
    try {
      fs.writeFileSync(pdfPath, signedPdfBuffer);
    } catch (error) {
      throw new Error("Failed to write signed PDF to file");
    }
    // Send response
    res.status(200).send({
      success: true,
      message: "PDF signed successfully",
    });
  } catch (error) {
    // Handle errors
    console.error("Error signing PDF:", error);
    res.status(500).send({
      success: false,
      error: error.message,
    });
  }
};

This code uploads a PDF file, adds text content, creates a signature placeholder, and digitally signs the document using a .pfx file. Despite the successful signing process, Adobe Acrobat does not display the green tick mark indicating the signature's validity and even after putting the widgetRect values didn't help me as I thought invisible certificate might have been the issue but it wasn't. Screenshot (16) Further insights or suggestions to resolve this issue would be highly appreciated.

ngvhob commented 2 months ago

UPDATE : On adding the visual tag implementation I tried to solve the issue but it still remains same no green tick.

const multer = require("multer");
const fs = require("fs");
const path = require("path");
const signpdf = require("@signpdf/signpdf").default;
const { P12Signer } = require("@signpdf/signer-p12");
const { pdflibAddPlaceholder } = require("@signpdf/placeholder-pdf-lib");
const { PDFDocument, rgb, StandardFonts } = require("pdf-lib");
// const { SUBFILTER_ETSI_CADES_DETACHED } = require("@signpdf/utils");
const storage = multer.diskStorage({
  destination: "uploads/",
  filename: function (req, file, cb) {
    cb(
      null,
      file.fieldname + "-" + Date.now() + path.extname(file.originalname)
    );
  },
});

function topLeftToBottomLeft(coords, page) {
  const pageHeight = page.getHeight();
  return [
    coords[0],
    pageHeight - coords[1],
    coords[2], // x2
    pageHeight - coords[3],
  ];
}

async function addVisual(pdfDoc) {
  const page = pdfDoc.getPages()[0]; // Get the first page
  var margin = 30;
  var padding = 10;
  var label = "Signed with @signpdf";

  const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica);
  const fontSize = 10;
  const x = page.getWidth() - margin;
  const y = page.getHeight() - margin;

  page.drawText(label, {
    x: x,
    y: y,
    size: fontSize,
    font: helveticaFont,
    color: rgb(0, 0, 0),
  });

  return [
    x - padding,
    y - padding,
    x + fontSize + padding,
    y + fontSize + padding,
  ];
}

exports.upload = multer({ storage: storage }).single("file");

exports.signDocument = async (req, res, next) => {
  try {
    const pdfPath = req.file.path;
    const pfxPath = "assets/docsinger.pfx";
    const password = "Mawai@123";
    let pdfBuffer, signedPdfBuffer;
    pdfBuffer = fs.readFileSync(pdfPath);
    let pfxBuffer = fs.readFileSync(pfxPath);
    let pdfDoc = await PDFDocument.load(pdfBuffer);
    const page = pdfDoc.getPages()[0];
    const widgetRect = await addVisual(pdfDoc);
    pdflibAddPlaceholder({
      pdfDoc,
      pdfBuffer,
      reason: "SwiftDocuSign",
      contactInfo: "jebaprince@swiftant.com",
      name: "Jeba Prince",
      location: "SwiftDocuSign",
      date: new Date(),
      signatureLength: 15000,
      widgetRect: topLeftToBottomLeft(widgetRect, page),
    });
    let pdfBufferWithPlaceholder = Buffer.from(await pdfDoc.save());
    const p12Signer = new P12Signer(pfxBuffer, {
      passphrase: password,
    });

    try {
      signedPdfBuffer = await signpdf.sign(pdfBufferWithPlaceholder, p12Signer);
      console.log("Signing done!");
    } catch (error) {
      throw new Error(error);
    }
    try {
      fs.writeFileSync(pdfPath, signedPdfBuffer);
    } catch (error) {
      throw new Error("Failed to write signed PDF to file");
    }
    // Send response
    res.status(200).send({
      success: true,
      message: "PDF signed successfully",
    });
  } catch (error) {
    // Handle errors
    console.error("Error signing PDF:", error);
    res.status(500).send({
      success: false,
      error: error.message,
    });
  }
};
vbuch commented 2 months ago

https://stackoverflow.com/a/40391641/2528232