bpampuch / pdfmake

Client/server side PDF printing in pure JavaScript
http://pdfmake.org
Other
11.57k stars 2.03k forks source link

how to add Digital Signature in pdfmake #1015

Open bandham opened 7 years ago

bandham commented 7 years ago

Hi, I'm able to add the PDF417-2D barcode using the canvas property. Now I want to add a digital signature, googled but couldn't get any idea on how to do this.

can someone help me on adding digital signature to the pdf document generated using pdfmake.

Thanks in advance. only barcode.pdf

liborm85 commented 7 years ago

Digital signature isn't supported. Is related to support in pdfkit - issue: https://github.com/devongovett/pdfkit/issues/187

Issue marked as fetature request.

nicenemo commented 4 years ago

From the comments I learned that PDFKit is used under the covers.

Can the sample code provided by this module https://www.npmjs.com/package/node-signpdf#generate-a-pdf be used as a solution??

I would like to be able to provide my own signature blob and certificate (created by Azure KeyVault) as an option instead of doing the actual signing in the code it self.

Brief description of Azure Signing

Azure takes a hash of the unsigned array of the PDF. That get's signed by Azure Keyvault using a key provisioned private key. The returned signature and certificate are added to the PDF. We currently use Java with PDFBox & Bouncy Castle. We want to get rid of the Java components.

navanshu commented 3 years ago

What do you mean by under the covers?

rscotten commented 3 years ago

@navanshu He means "under the hood," meaning pdfmake runs on top of pdfkit, i.e. pdfkit is a dependency (see package.json).

Biokimist commented 2 years ago

Is there any news about the requested feature that allow us to sign pdf with pdfMake ?

palvarez-icci commented 2 years ago

Are there plans to work on this feature or is there a recommended work around solution for digital signature?

AbhishekCityMall commented 2 years ago

any solutions yet ??

Biokimist commented 2 years ago

I stoped working on that I don’t know. But I hope so..

Le lun. 13 juin 2022 à 06:01, AbhishekCityMall @.***> a écrit :

any solutions yet ??

— Reply to this email directly, view it on GitHub https://github.com/bpampuch/pdfmake/issues/1015#issuecomment-1153437616, or unsubscribe https://github.com/notifications/unsubscribe-auth/ATG27WCKALZNXZTO72OILT3VO2XCTANCNFSM4DMXNLGA . You are receiving this because you commented.Message ID: @.***>

afilp commented 1 year ago

I am also looking for such a solution, can please someone show us a workaround on how to use pdfmake? Thanks a lot.

vdiezel commented 1 year ago

I managed to "somewhat" sign my pdf using the node-signpdf package (https://github.com/vbuch/node-signpdf/issues/167) and a couple of hacks. Posting here because might be a good starting point to get it perfect.

const pdf = printer.createPdfKitDocument(docDescription, { bufferPages: true })

/* this is required because of a possible node-sign bug */
/* https://github.com/vbuch/node-signpdf/issues/88 */
pdf.initForm()

/* we need to add the placeholder for the signature */
/* the pdfkitAddPlaceholder from the node-signpdf library is not working here, so I created an adjusted version, see below  */
const refs = pdfkitAddPlaceholder({
  pdf,
  pdfBuffer: Buffer.from([pdf]),
  reason: 'NSA - we know what you are doing',
})

Object.keys(refs).forEach(key => refs[key].end())

/* store your unsigned pdf  */

const storagePath = '/path/to/pdf'
const pdfStream = fs.createWriteStream(storagePath)
pdf.pipe(pdfStream)
pdf.end()

const finished = util.promisify(stream.finished)  // using node's 'util' package
await finished(pdfStream)

const signedPdf = signer.default.sign(
  fs.readFileSync(storagePath),
   fs.readFileSync(pathToP12Store),
  options,  // optional, e,g, { passphrase: 'mypw_for_p12' }
)

/* overwrite non-signed file */
fs.writeFileSync(storagePath, signedPdf)

The document is shown as validly signed in my Okular PDF viewer - but there seems to be an issue in the byterange of the signature. Okular complains with a small error message, while adobe will straight out claim that the signature is invalid because of the byte range (and also if you use a self-signed P12 keystore as it looks like)

my package versions:

"node-forge": "1.3.1" "node-signpdf": "1.5.0" "pdfmake": "0.2.7"

my custom addPlaceholder method:

/* this is a custom version of node-signpdf kits pdfkitAddPlacerHolder */
/* https://github.com/vbuch/node-signpdf/issues/88 */

/* this was copied and then only modified slightly
/* to make it work!!! */

const _const = require('node-signpdf/dist/helpers/const')
const _pdfkitReferenceMock = require('node-signpdf/dist/helpers/pdfkitReferenceMock')

const pdfkitAddPlaceholder = ({
  pdf,
  pdfBuffer,
  reason,
  contactInfo = 'emailfromp1289@gmail.com',
  name = 'Name from p12',
  location = 'Location from p12',
  signatureLength = _const.DEFAULT_SIGNATURE_LENGTH,
  byteRangePlaceholder = _const.DEFAULT_BYTE_RANGE_PLACEHOLDER,
  subFilter = _const.SUBFILTER_ADOBE_PKCS7_DETACHED,
}) => {
  const signature = pdf.ref({
    Type: 'Sig',
    Filter: 'Adobe.PPKLite',
    SubFilter: subFilter,
    ByteRange: [0, byteRangePlaceholder, byteRangePlaceholder, byteRangePlaceholder],
    Contents: Buffer.from(String.fromCharCode(0).repeat(signatureLength)),
    Reason: new String(reason),
    M: new Date(),
    ContactInfo: new String(contactInfo),
    Name: new String(name),
    Location: new String(location)
  })

  const acroFormPosition = pdfBuffer.lastIndexOf('/Type /AcroForm')
  const isAcroFormExists = acroFormPosition !== -1
  let fieldIds = []
  let acroFormId

  if (isAcroFormExists) {
    let acroFormStart = acroFormPosition

    const charsUntilIdEnd = 10
    const acroFormIdEnd = acroFormPosition - charsUntilIdEnd

    const maxAcroFormIdLength = 12
    let foundAcroFormId = ''
    let index = charsUntilIdEnd + 1

    for (index; index < charsUntilIdEnd + maxAcroFormIdLength; index += 1) {
      const acroFormIdString = pdfBuffer.slice(acroFormPosition - index, acroFormIdEnd).toString()

      if (acroFormIdString[0] === '\n') {
        break
      }

      foundAcroFormId = acroFormIdString
      acroFormStart = acroFormPosition - index
    }

    const pdfSlice = pdfBuffer.slice(acroFormStart)
    const acroForm = pdfSlice.slice(0, pdfSlice.indexOf('endobj')).toString()
    acroFormId = parseInt(foundAcroFormId)
    const acroFormFields = acroForm.slice(acroForm.indexOf('/Fields [') + 9, acroForm.indexOf(']'));
    fieldIds = acroFormFields.split(' ').filter((element, i) => i % 3 === 0).map(fieldId => new _pdfkitReferenceMock.default(fieldId))
  }

  const signatureName = 'Signature'

  const widget = pdf.ref({
    Type: 'Annot',
    Subtype: 'Widget',
    FT: 'Sig',
    Rect: [0, 0, 0, 0],
    V: signature,
    T: new String(signatureName + (fieldIds.length + 1)),
    F: 4,
    P: pdf.page.dictionary,
  })

  pdf.page.dictionary.data.Annots = [widget]

  let form

  if (!isAcroFormExists) {
    form = pdf.ref({
      Type: 'AcroForm',
      SigFlags: 3,
      Fields: [...fieldIds, widget],
      /******************************/
      /* This is the critical change*/
      DR: {
        Font: {},
      },
      /******************************/
    })
  } else {
    form = pdf.ref({
      Type: 'AcroForm',
      SigFlags: 3,
      Fields: [...fieldIds, widget],
    }, acroFormId)
  }

  pdf._root.data.AcroForm = form
  return {
    signature,
    form,
    widget,
  }
}

module.exports = pdfkitAddPlaceholder
efrenmarin45 commented 1 year ago

Any update on this feature request?