vbuch / node-signpdf

Simple signing of PDFs in node.
MIT License
719 stars 178 forks source link

pdfkitAddPlaceholder fails using pdfkit 0.11.0 #88

Closed vladh1 closed 3 years ago

vladh1 commented 4 years ago

Describe the bug and the expected behaviour pdfkitAddPlaceholder fails using pdfkit 0.11.0 with the error: "Cannot read property 'fonts' of undefined"

Is it a bug in signing or in the helpers? Issue is related to the pdfkitAddPlaceholder helper

To Reproduce

const signer = require('node-signpdf').default;
const pdfkitAddPlaceholder = require('node-signpdf/dist/helpers/pdfkitAddPlaceholder').default;
const fs = require('fs');
const PDFDocument = require('pdfkit');
const pdf = new PDFDocument({
    autoFirstPage: true,
    size: 'A4',
    layout: 'portrait',
    bufferPages: true,
});
pdf.info.CreationDate = '';

// Add some content to the page
pdf
    .fillColor('#333')
    .fontSize(25)
    .moveDown()
    .text('HELLO WORLD');

// Collect the ouput PDF
// and, when done, resolve with it stored in a Buffer
const pdfChunks = [];
pdf.on('data', (data) => {
    pdfChunks.push(data);
});
pdf.on('end', () => {
    console.log("pdfDoc.end");
    let pdfBuffer = Buffer.concat(pdfChunks);
    let signedPDF = signer.sign(pdfBuffer, fs.readFileSync('pdf/cert/certificate.pfx'));
    fs.writeFileSync('pdf/document.pdf', signedPDF);
});

// Externally (to PDFKit) add the signature placeholder.
const refs = pdfkitAddPlaceholder({
    pdf,
    pdfBuffer: Buffer.from([pdf]),
    reason: 'I am the author'
});
// Externally end the streams of the created objects.
// PDFKit doesn't know much about them, so it won't .end() them.
Object.keys(refs).forEach(key => refs[key].end());

// Also end the PDFDocument stream.
// See pdf.on('end'... on how it is then converted to Buffer.
pdf.end();
copperwall commented 4 years ago

This isn't a total solution, but I ran into this today and noticed that there's a new method on the PDFDocument instance called pdf.initForm that sets up an AcroForm, but the code in pdfkitAddPlaceholder doesn't copy all of the fields that pdfkit places on the initial AcroForm ref so when .end is called on the form it fails to find the fields originally placed on the form by pdfkit.

It looks like pdfkitAddPlaceholder needs to be updated to include those fields. https://github.com/foliojs/pdfkit/blob/master/lib/mixins/acroform.js#L83

vbuch commented 4 years ago

https://github.com/vbuch/node-signpdf/issues/49

copperwall commented 4 years ago

Hey @vbuch I'm interested in working on this if that works for you.

vbuch commented 4 years ago

@copperwall I dont have the time to do it, so you are more than welcome. Please create a separate helper for that as people with pdfkit10 will probably still want to use the available one.

Of course, thats if they are incompatible.

nayaras commented 4 years ago

Any updates on this?

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had activity in the past 90 days. It will be closed if no further activity occurs. Thank you for your contributions.

eminoda commented 2 years ago

pdfkit 更新并添加了一些方法,比如:initForm,导致 node-signpdf 中的 pdfkitAddPlaceholder 不能正常工作!

你可以单独写一个 pdfkitAddPlaceholder 方法,把一些异常错误做个处理:

// ...
const pdf = new PDFDocument({
      autoFirstPage: false,
      size: 'A4',
      layout: 'portrait',
      bufferPages: true,
    })
    pdf.initForm() // 注意!!!
    pdf
      .addPage()
      .fillColor('#333')
      .fontSize(25)
      .text('Hello PdfDocument ' + Date.now())
      .save()
// ...
// your pdfkitAddPlaceholder.js
// ...
let form;

if (!isAcroFormExists) {
  // Create a form (with the widget) and link in the _root
  form = pdf.ref({
    Type: 'AcroForm',
    SigFlags: 3,
    Fields: [...fieldIds, widget],
    // 注意!!!
    DR: {
      Font: {}
    }
  });
} else {
// ...