Giter Club home page Giter Club logo

node-signpdf's Introduction

@signpdf

Known Vulnerabilities Coverage as reported by Coveralls GitHub last commit

Formerly known as node-signpdf @signpdf is a family of packages trying to make signing of PDFs simple in Node.js.

Purpose

The main purpose of this package is to demonstrate the way signing can be achieved in a piece of readable code as it can take a lot of hours to figure out.

Usage

When this repo was started we really wanted people to understand the signing flow. If that's your case, you should read the [Signing PDF in simple steps] section. If you are here with "Give me the code", you should maybe go to our packages/examples.

Depending on your usecase you may need different combinations of packages.

I am getting PDFs that already have placeholders

This is the most simple case of them all. $ npm i -S @signpdf/signpdf @signpdf/signer-p12 node-forge. Then have a look at the with-placeholder.js example. It should be as simple as:

import signpdf from '@signpdf/signpdf';
import { P12Signer } from '@signpdf/signer-p12';
...
const signer = new P12Signer(fs.readFileSync(PATH_TO_P12_CERTIFICATE));
const signedPdf = await signpdf.sign(fs.readFileSync(PATH_TO_PDF_FILE), signer);

I am generating a PDF with PDFKit

This is how the library was started as we needed to sign a document that we were generating on the fly. You will need $ npm i -S @signpdf/signpdf @signpdf/placeholder-pdfkit010 @signpdf/signer-p12 node-forge and a look at the pdfkit010.js example.

I have a .pdf file and I want to sign it

This seems to be the most common usecase - people work with PDF documents coming from different sources and they need to digitally sign them. Both placeholder helpers placeholder-plain and placeholder-pdf-lib can help here.

Plain

Start with $ npm i -S @signpdf/signpdf @signpdf/placeholder-plain @signpdf/signer-p12 node-forge. Head over to either the JS example or the TS one. An advantage of working with the plain version would be that in theory it should be quicker and use less memory (not benchmarked). A great disadvantage: it is very fragile relying on strings being poisitioned in a certain way.

PDF-LIB

$ npm i -S @signpdf/signpdf @signpdf/placeholder-pdf-lib pdf-lib @signpdf/signer-p12 node-forge gets you started. Then comes the the PDF-LIB example. PDF-LIB provides tremendous PDF API, it is very well documented and well supported.

Packages

@signpdf is split into multiple packages. In the case where you are already working with the PDF-generating library PDFKit, this is the command you will start with once you want to start signing these documents: $ npm i -S @signpdf/signpdf @signpdf/placeholder-pdfkit010 @signpdf/signer-p12 node-forge. So what are all these packages and why do you need them?

npm version

This is the main package, the integrating one, the one that wraps everything up. It uses a Signer implementation that provides cryptographic signing to sign a well-prepared PDF document. A PDF document is well-prepared if it has a signature placeholder. If your PDF does not have that, you may want to add one using one of our placeholder helpers.

Signers

Signers are small libraries that @signpdf/signpdf will call with a PDF and they will know how to provide an e-signature in return. Their output is then fed as the signature in the resulting document.

npm version

With the help of its peerDependency node-forge the P12 signer provides the actual cryptographic signing of a Buffer using a P12 certificate bundle. This is done in detached mode as required for PDF.

Placeholder helpers

A placeholder is the e-signature equivallent of the label "Sign here:......." in your paper document. They are a required part of the process of Signing PDFs. Different projects acquire their PDFs differently so we try to support some helpers that know how to add e-signature placeholders.

npm version

Works on top of PDFKit 0.11.0+ and given a PDFDocument that is in the works (not yet ended), adds an e-signature placeholder. When the placeholder is in place @signpdf/signpdf can complete the process.

npm version

Works on top of PDFKit 0.10.0 and given a PDFDocument that is in the works (not yet ended), adds an e-signature placeholder. When the placeholder is in place @signpdf/signpdf can complete the process.

npm version

Uses the process and knowledge from placeholder-pdfkit010 on how to add e-signature placeholder but implements it with plain string operations (.indexOf(), .replace(), .match(), etc.). Because of the lack of semantics it is rather fragile. Additionally it doesn't support streams and only works on PDF version <= 1.3. Regardless of those disadvantages this helper seems to be the most popular among the users of @signpdf. When the placeholder is in place @signpdf/signpdf can complete the process.

npm version

Works with PDF-LIB and given a loaded PDFDocument, adds an e-signature placeholder. When the placeholder is in place @signpdf/signpdf can complete the process.

Notes

Signing PDF in simple steps

Generate a PDF or read a ready one

We have examples of PDFKit generation of documents and we also have some where a ready .pdf file is read. Browse through our examples.

Append a signature placeholder

What's needed is a Sig element and a Widget that is also linked in a Form. The form needs to be referenced in the Root descriptor of the PDF as well. A (hopefully) readable sample is available in the helpers. Note the Contents descriptor of the Sig where zeros are placed that will later be replaced with the actual signature.

We provides placeholder helpers that do that.

Signature length

Note: Signing in detached mode makes the signature length independent of the PDF's content length, but it may still vary between different signing certificates. So every time you sign using the same P12 you will get the same length of the output signature, no matter the length of the signed content. It is safe to find out the actual signature length your certificate produces and use it to properly configure the placeholder length.

PAdES compliant signatures

To produce PAdES compliant signatures, the ETSI Signature Dictionary SubFilter value must be ETSI.CAdES.detached instead of the standard Adobe value. This can be declared using the subFilter option argument passed to placeholder helpers.

import { pdfkitAddPlaceholder } from '@signpdf/placeholder-pdfkit010';
import { SUBFILTER_ETSI_CADES_DETACHED } from '@signpdf/utils';

const pdfToSign = pdfkitAddPlaceholder({
  ...,
  subFilter: SUBFILTER_ETSI_CADES_DETACHED,
});

Generate and apply signature

That's where the @signpdf/signpdf kicks in. Given a PDF and a signer implementation a signature is generated and replaced in the placeholder.

import signpdf from '@signpdf/signpdf';

...
const signedPdf = await signpdf.sign(pdfBuffer, signer);

Credits

node-forge

node-forge is used for working with signatures. It is an awesome package written in pure JavaScript and supports signing in detached mode. Many thanks to all the guys who wrote and maintain it.

PDFKit

PDFKit is extensively used for generating PDFs with a signature placeholder and additionally its flows are used in placeholder-plain. Thanks to the guys of PDFKit as they've made PDF generation incredibly easy.

pdfsign.js

The signing flow of @signpdf/signpdf and @signpdf/signer-p12 is a rework of what was already in pdfsign.js so thanks go to @tbocek.

node-signpdf's People

Contributors

alekssakovsky avatar andres-blanco avatar ashirman avatar avirambaranes avatar brunoserrano avatar cdebevotte avatar danielbom avatar dcbr avatar dependabot[bot] avatar dhensby avatar eltimuro avatar erikn69 avatar maldimirov avatar marin-aldimirov avatar mgyugcha avatar mohammedessehemy avatar neuromancer64 avatar niklas-dahl avatar pernikov avatar richardbray avatar therpobinski avatar timotheeg avatar vbuch avatar vizicsaba89 avatar waaronking avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-signpdf's Issues

Fix the regex that extract the signature from PDF Buffer

I tried to verify some the signature of PDFs, and it fails when trying to extract the signature form the files. I make some tests with many files and I notice the ByteRange has, in some cases, an empty space at the end of the ByteRange, like this:

/ByteRange [0 79529 95531 2230 ]

And to make work properly with this case, the regex that gets the match, need to be modified to something like this:

/\/ByteRange \[(\d+) +(\d+) +(\d+) +(\d+)\s?\]/

If You want, I can make a PR with the fix, it's a simple thing, but it will help me a lot.

plainAddPlaceholder displaces view of PDF

Describe the bug and the expected behaviour
View of the pdf is displaced when plainAddPlaceholder is used. PDF generated by wkhtmltopdf
Is it a bug in signing or in the helpers?
Its an issue with helpers, "plainAddPlaceholder". Updating pageIndex to 1 of "plainAddPlaceholder" resolves the issue
To Reproduce
Sample code is below

// generate pdf by command below
wkhtmltopdf "https://google.com" <path_of_file>

// Code to addPlaceHolder
const fs = require('fs')
const node_signpdf = require('node-signpdf')
const plainAddPlaceholder = require('./helpers').plainAddPlaceholder
const SignPdf = new node_signpdf.SignPdf()
const signBuffer = fs.readFileSync(certificate.p12);
let pdfBuffer = fs.readFileSync(input.pdf);
pdfBuffer = plainAddPlaceholder({
pdfBuffer,
reason : 'I have reviewed It'
});
fs.writeFileSync('fileWithPlaceHolder.pdf', pdfBuffer);

[Feature] Support signing pdf which uses Cross-reference streams

Hi Valery--I ran into a problem signing pdf which contains Cross-reference streams. Beginning with PDF 1.5, cross-reference information may be stored in a cross-reference stream instead of in a cross-reference table:

... objects ...
12 0 obj % Cross-reference stream
<< /Type /XRef % Cross-reference stream dictionary
/Size ...
/Root ...

stream
... % Stream data containing cross-reference information
endstream
endobj
... more objects ...
startxref
byte_offset_of_cross-reference_stream % Points to object 12
%%EOF

(http://benno.id.au/refs/PDFReference15_v5.pdf)
(https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf)

As it turns out google docs download pdfs in 1.5 format with compressed cross-reference stream, for example:
3 0 obj
<< /Type /XRef /Length 50 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 17269 /ID [<731c6cc871d74233cb9a7240c2f04753><731c6cc871d74233cb9a7240c2f04753>] >>
stream
xœcbdàgb8 $˜–‚XF@‚±�DÜ��‰@Â* $›ÆÀĸÿ9H �#6� �ƒ�0
endstream
endobj

Let me know if you think you might have time to implement.

Error 4002 PDF might contain errors in Digital Signature

I used the fluent reports in generating the PDF file then apply the digital Signature, The function works but I received the error when I tried to click See Signature version and it says ERROR 4002
"Malformed drawing instructions: Syntax error. Page content violates the grammar for page content definition. For example, the instruction might specify drawing a square but the syntax for doing it is incorrect." Doing this with the pdfkit as PDF generator didnt show any errors like this but however I wanted to use FLUENT REPORTS but this error keep showing up.

Sign PDF with external service returning signature + certificate from hash (no private key access)

Hi,

The application is great but in my case I don't have access to a p12 certificate containing a private key to build the CMS. I only have access to an external provider that takes a hash I give him as input and return user certificate as well as signature of the hash in response (never access to the private key from my point of view). Would it be possible to achieve the construction of the signature to be inserted in the PDF with such external provider?

Thank you for your help

Method to auto generate p12 files?

What is the recomended solutuion to generating P12 files? I can't expect my users to generate in Adobe and export to make use of this library. What were you ideas on how this could sign documents automatically from many different users?

Second page

Can you please help me with example to signed the pdf in the second page to nth page, would appreciate it, thanks

Cannot set property 'Annots' of undefined

`const signer = require('node-signpdf').default;
const fs = require('fs');
const { addSignaturePlaceholder } = require('./node-signpdf-master/dist/helpers');
const PDFDocument = require('pdfkit');

const createPdf = (params = {
placeholder: { reason : 'Digital signed by my key' },
text: 'this is content pdf',
}) => new Promise((resolve) => {
const pdf = new PDFDocument({
autoFirstPage: true,
size: 'A4',
layout: 'portrait',
bufferPages: true,
});
pdf.info.CreationDate = '';
pdf.fillColor('#333').fontSize(25).moveDown().text(params.text);

const pdfChunks = [];
pdf.on('data', (data) => {
pdfChunks.push(data);
});
pdf.on('end', () => {
resolve(Buffer.concat(pdfChunks));
});

const refs = addSignaturePlaceholder({
pdf,
reason: 'I am the author',
...params.placeholder,
});

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

});

const action = async () => {
let pdfBuffer = await createPdf();
let p12Buffer = fs.readFileSync(__dirname + '/baominh.key.p12')

let pdf = signer.sign(pdfBuffer, p12Buffer, { passphrase : '12345678', asn1StrictParsing : true });
fs.writeFileSync(__dirname + '/demo.pdf', pdf);
}

action();`
Hello! I have been the error: 'Cannot set property 'Annots' of undefined' when i runed the code above. Can you help me with this?

Verify error

I got the error "Too few bytes to parse DER" on this line
const p7Asn1 = _nodeForge2.default.asn1.fromDer(signature);

I'm only using the library to verify a PDF that is signed

Support of ECDSA Certificate

For the moment, only RSA certificates are supported (forge dependency constraint)
Any plan to support ECDSA certificate?

Multiple signatures invalidates previous signatures

Hi!

Thanks for creating this lib.

I am having trouble with adding multiple signatures by using plainAddPlaceholder(). If I add multiple signatures, all previous signatures get invalidated. I have attached the two PDFs.

Here is my code:

         import signer from './node-signpdf/signpdf';
         import plainAddPlaceholder from './node-signpdf/helpers/plainAddPlaceholder';

        // Create and get .p12 certificate
        const certificate = await createCertificate()

        // Add signature and forms
        pdfBuffer = await plainAddPlaceholder({
            pdfBuffer,
            reason: 'Because I can',
            signatureLength: certificate.length
        })

        
        // Sign document
        const file = signer.sign(
            pdfBuffer,
            certificate,
            {passphrase: 'password'}
        );

The createCertificate function creates a self-signed certificate:

import { pki, pkcs12, util, asn1 } from "node-forge"
import moment from "moment";

export default async () => {

    // generate a keypair
    let keys = pki.rsa.generateKeyPair(2048);

    // create a new certificate
    let cert = pki.createCertificate();

    // fill the required fields
    cert.publicKey = keys.publicKey;
    cert.serialNumber = '01';
    cert.validity.notBefore = moment().startOf('day').toDate();
    cert.validity.notAfter = moment().startOf('day').toDate();
    cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 3);  

    // Set issuer
    const issuer = [{
        name: 'commonName',
        value: 'salire.no'
    }, {
        name: 'countryName',
        value: 'NO'
    }, {
        shortName: 'ST',
        value: 'Vestland'
    }, {
        name: 'localityName',
        value: 'Bergen'
    }, {
        name: 'organizationName',
        value: 'Salire AS'
    }, 
    {
        shortName: 'OU',
        value: 'Salire'
    }];

    // Set subject
    const subject = [{
        name: 'commonName',
        value: 'My name'
    }, {
        name: 'countryName',
        value: 'NO'
    }, {
        shortName: 'ST',
        value: 'Vestland'
    }, {
        name: 'localityName',
        value: 'Bergen'
    }, {
        name: 'organizationName',
        value: 'Min organisasjon'
    }, {
        shortName: 'OU',
        value: ' '
    }];

    // here we set subject and issuer as different objects
    cert.setSubject(subject);
    cert.setIssuer(issuer);

    // the actual certificate signing
    cert.sign(keys.privateKey);

    // generate a p12 using AES (default)
    var newPkcs12Asn1 = pkcs12.toPkcs12Asn1(keys.privateKey, cert, 'password');
    
    // base64-encode p12
    const p12Der = asn1.toDer(newPkcs12Asn1).getBytes();
    var buffer = Buffer.from(p12Der, 'binary');

    return buffer
}

5e011ae8f6d4d2656fa8c4cc.pdf
5e011ae8f6d4d2656fa8c4cc (1).pdf

Two signatures

Thank you so much for this awesome library. I would like to ask whether there is a way to put two signatures directly in one go.

trouble

D:\Projects\pdf-digital-signature\node_modules\node-signpdf\dist\signpdf.js:67
throw new _SignPdfError2.default(Could not find ByteRange placeholder: ${byteRangeString}, _SignPdfError2.default.TYPE_PARSE);
^

Error: Could not find ByteRange placeholder: /ByteRange [0 /********** /********** /**********]
at SignPdf.sign (D:\Projects\pdf-digital-signature\node_modules\node-signpdf\dist\signpdf.js:67:19)

sign() is not a function

All is said in the title.

In the example, you use signer.sign(......), it simply doesn't work

Not working on Edge

Hello! Thank you for the project first of all.

I have a problem running this library in Microsoft Edge, when I run my project shows an error in console at the beginning.

Screenshot_1

When debug I see the error here:

Screenshot_2

Do you know something about that?

Thank you for your help!

Adobe Parameter Error After Sign

I have ported the code to work with express.
Steps

  1. Add Placeholder to PDF Buffer
  2. Get Sign Header
  3. Use Forge to sign with p12 file saved in root folder
  4. Use fs.writefilesync to write the buffer with signature to a new pdf file

The created pdf file opens with the content. It shows a signature on the document but Adobe says its invalid, when trying to validate it I get
"""
Error during signature verification.

Adobe Acrobat error.
Bad parameter.
"""

I'm using plainAddPlaceholder to add the placeholder.
I am trying to get it to work with already created pdf files.

Error: A PDF file must end with an EOF line.

I had some problems when reading the pdf file from the buffer, since once called the function .sign (), this throws the following error:

/Users/iopazo/Develop/uno/transmision-api/node_modules/node-signpdf/dist/helpers/removeTrailingNewLine.js:40
     throw new _SignPdfError.default (
     ^

Error: A PDF file must end with an EOF line.

Imagine the problem was with one of my PDF files, but checking these if they have the final line.

Here is my integration:

    const signer = require('node-signpdf').default;

    let pdfBuffer = fs.readFileSync(file);

    const signedPdf = signer.sign(pdfBuffer, fs.readFileSync(signature));
    console.log(signedPdf);

comprobante_incorporacion.pdf

From already thank you very much!

How-to Sign already create PDF document

Hi Guys,

Grate work...
I'll will appreciate to create and submit a demo of using node-signpdf for the ones using jsPDF.
The problem is that I can not find how to create the placeholders as shows on the tests

const signature = pdf.ref({ Type: 'Sig', Filter: 'Adobe.PPKLite', SubFilter: 'adbe.pkcs7.detached', ByteRange: [ 0, DEFAULT_BYTE_RANGE_PLACEHOLDER, DEFAULT_BYTE_RANGE_PLACEHOLDER, DEFAULT_BYTE_RANGE_PLACEHOLDER, ], Contents: Buffer.from(String.fromCharCode(0).repeat(signatureLength)), Reason: new String(reason), // eslint-disable-line no-new-wrappers M: new Date(), });
When looking on the jsPDF I could not find the equivalent to pdf.ref, but I am sure there is a way to do that, any idea?

Sign PDF document with multiple digital signatures

Hi Vbuch!

First of all, thanks for making node-signpdf!

I was able to figure it out how to sign a pdf document by looking at the tests, and it works nice. Unfortunately i can't find a solution to sign a document with 2 or more different digital signatures. Is there a way to do that with node-signpdf?

Invalid IdMessageDigest

When we create the signed PDF based on the certificate provided by the Brazilian Government and when we verify it on this site: https://verificador.iti.gov.br/

It gives the error of verification mentioning:

Invalid. Failed to build the attribute: 1.2.840.113549.1.9.4 - Problems getting the hash

When we use the same certificate on some other C# library, it works perfectly fine.
Can you please check the same and provide the feedback on this.

Because of the privacy issues, I cannot share the certificate but it indeed does not work with this Node Library.
Will look forward to the solution.

PKCS#11 put already signed data to pdf signature

Hi Valery! Thank you by the project.
I need to sign data using a SmartCard Token, that implements PKCS#11 layer, i already have a working implementation using NodeJS (Migrating from a Java implementation) to sign the data based on some PDF binary, now i need to put this signed data in the PDF, i take a look to your code and i need to ask, to solve my issue, i just need to replace the signed data (generated by node-forge based on .pfx) by my signed data (generated from my current implementation, that already signed with PDF binary and the Token PKCS#11) in code? Thats it? I have spent time to find some PKCS#11 solution to NodeJS but i didn't found pratically nothing, and all PDF libraries have only support to p12|pfx, thank you!

Could not find ByteRange placeholder

HI I am trying to sign a pre-generated pdf using node-signpdf and I am getting this error again and again. here is my code:-

const signer = require('node-signpdf').default;

function test() {
let pdfBuffer =  fs.readFileSync('./Foo.pdf'); 
let cert =  fs.readFileSync('./certificate.p12');

 let  test = signer.sign(pdfBuffer, cert);
  console.log(test, "response")
}
test();

I am getting below error -

SignPdfError: Could not find ByteRange placeholder: /ByteRange [0 /********** /********** /**********]
    at SignPdf.sign (/home/hp/app/node_modules/node-signpdf/dist/signpdf.js:53:13)
    at test (/home/hp/app/index.js:96:21)
    at Object.<anonymous> (/home/hp/app/index.js:100:1)
    at Module._compile (internal/modules/cjs/loader.js:1157:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1177:10)
    at Module.load (internal/modules/cjs/loader.js:1001:32)
    at Function.Module._load (internal/modules/cjs/loader.js:900:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)
    at internal/main/run_main_module.js:18:47 {
  type: 3

confused arguments

import signer from 'node-signpdf';

const signedPdf = signer.sign(
fs.readFileSync(PATH_TO_P12_CERTIFICATE),
fs.readFileSync(PATH_TO_PDF_FILE)
); <<<<<<<- in manual

sign(pdfBuffer, p12Buffer) { <<<<<<<<- in code

Signing with pkcs11

Hey, I have a branch working with pkcs11 tokens. It's still a WIP but it works. The relevant code is here: https://github.com/SIU-Toba/node-signpdf/blob/feature/pkcs11-token/src/signpdf.js#L137

The problem I have is that the token needs the raw byte buffer to digest and sign. The node-forge lib sends a message digest object as parameter, so I don't have access to the raw bytes.
I created this issue in node-forge digitalbazaar/forge#729

Does anybody here knows how can I obtain the raw signable buffer from the message digest sent by node-forge? This is important if you want to use signed attributes.

Question regarding embedded timestamp

Hi,

First of all - thank you for the work, it seems very promising.

I've cloned the repo and tried to figure out if there is any way to add an embedded timestamp using a TSA (Trusted timestamp authority). Currently when signing a document (for example in the test files), Adobe will show a warning that the "Signing time is from the clock on the signer's computer".

Is there any way to provide an embedded timestamp to the signature?
If not, is this something on your radar for future improvements?

plainAddPlaceholder creating invisible signature

Not sure it is the expected or intended behavior or not.

However, in my case, I have an already created PDF (not made using PDFKit). I used plainAddPlaceholder function to create the placeholder and then added the signature. The output PDF have the signature properly, but Acrobat Reader is saying "invisible signature".

How can I add some text and show the signature in the PDF, without using PDFKit?

Blank pdf after signing

I investigated this bug and found that after signing the PDF file will be empty if it contained any link to website. Also, if the link href contain # instead of address (like http://google.com) everything will be fine.

 try {
            output = plainAddPlaceholder({
                pdfBuffer: fs.readFileSync(filename),
                reason: reason || 'my signature',
                signatureLength: 8192
            });
        } catch (e) {
            console.log('Error during adding placeholder');
            console.log(e.message);
            return response
                .status(500)
                .send({
                    message: 'Error during adding placeholder',
                    fn: plainAddPlaceholder ? plainAddPlaceholder.toString() : '-',
                    error: e.message,
                    trace: JSON.stringify(e.trace)
                });
        }
        try {
            const signedPdf = signer.sign(output, fs.readFileSync(cert));
            fs.writeFileSync(__dirname + '/last.pdf', signedPdf);
            fs.writeFileSync(filename, signedPdf);
            const {signature, signedData} = extractSignature(signedPdf);
            console.log(`Successfully signed ${filename}`);
            return response
                .send({ message: 'ok' });
        } catch (e) {
            console.log('Error during singing PDF');
            console.log(e.message);
            return response
                .status(500)
                .send({
                    message: 'Error during singing PDF',
                    error: e.message,
                    trace: JSON.stringify(e.trace)
                });
        }

Uploading pdf and certificate using multer and sign pdf but there is error Could not find ByteRange placeholder: /ByteRange [0 /********** /********** /**********]

Help please i have to complete this task
Here is my code

const fs = require('fs');

const express = require('express');
const multer = require('multer');
const signer = require('node-signpdf').default;

const app = express();

const fileStorage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, `./uploads`);
  },
  filename: (req, file, cb) => {
    let fileName = file.originalname.split(' ').join('-');
    cb(null, Date.now().toString() + '-' + fileName);
  }
});

const upload = multer({ storage: fileStorage });

app.post('/pdf/sign', upload.fields([{ name: 'pdf' }, { name: 'certificate' }]), (req, res) => {
  const pdf = req.files.pdf[0].path;
  const certificate = req.files.certificate[0].path;

  const signedPdf = signer.sign(
    fs.readFileSync(pdf),
    fs.readFileSync(certificate)
  );

  fs.writeFileSync(`${__dirname}/upload/${req.files.pdf[0].filename}-signed`, signedPdf);

  res.status(200).json({
    message: 'success',
  });
});

const port = 3000;
app.listen(port, () => console.log(`Appliction is listening on ${port}`));

signer.sign is not a function

I'm trying to sign PDFfiles using NodeJs.

This is my code in a file called sign.js:

`
var signer = require("node-signpdf");
var fs = require("fs");

function signIt() {
const PATH_TO_PDF_FILE = "./declaracao.pdf";
const PATH_TO_P12_CERTIFICATE = "./Associacao.pfx";

var signedPdf = signer
.sign(
fs.readFileSync(PATH_TO_PDF_FILE),
fs.readFileSync(PATH_TO_P12_CERTIFICATE)
)
.then((result) => {
console.log(result);
})
.catch((err) => {
console.log(err);
});

console.log(signedPdf);
}

signIt();
`

Anyway, when I try node sign.js I receive a signer.sig is not a function

What am I missing?

[ERROR] Could not find a declaration file for module 'node-signpdf'. '(...)node_modules/node-signpdf/dist/signpdf.js' implicitly has an 'any' type. Try `npm install @types/node-signpdf` if it exists or add a new declaration (.d.ts) file containing `declare module 'node-signpdf';`ts(7016)

I got this error when I tried to run this code:

import signer from 'node-signpdf';

const PATH_TO_PDF_FILE = "test.pdf"; 
const PATH_TO_P12_CERTIFICATE = "key.p12";

const signedPdf = signer.sign(
  fs.readFileSync(PATH_TO_PDF_FILE),
  fs.readFileSync(PATH_TO_P12_CERTIFICATE),
);
/(...)/app.js:1
(function (exports, require, module, __filename, __dirname) { import signer from 'node-signpdf';
                                                                     ^^^^^^

SyntaxError: Unexpected identifier
    at new Script (vm.js:79:7)
    at createScript (vm.js:251:10)
    at Object.runInThisContext (vm.js:303:10)
    at Module._compile (internal/modules/cjs/loader.js:657:28)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
    at startup (internal/bootstrap/node.js:283:19)

Signature details null

Hello,
i adapt your code signpdf.test.js to make it simpler, but when i use pdfsig to check the signature, the fields return null:

pdfsig bla.pdf 
Digital Signature Info of: bla.pdf
Internal Error (0): Input couldn't be parsed as a CMS signature
Syntax Error (0): Illegal values in ByteRange array
Signature #1:
  - Signer Certificate Common Name: (null)
  - Signer full Distinguished Name: (null)
  - Signing Time: Nov 18 2019 14:18:39
  - Signing Hash Algorithm: unknown
  - Signature Type: adbe.pkcs7.detached
  - Signature Validation: Signature has not yet been verified.

This is my code:

global.signpdf = require('node-signpdf'); 
global.PDF = require('pdfkit'); 
...
                doc = new PDF(.....);
                ....
                if (toSign) {

                    let fieldIds = [], form;
                    const signatureLength = 8192,
                            byteRangePlaceholder = '**********',
                            signature = doc.ref({
                                Type: 'Sig',
                                Filter: 'Adobe.PPKLite',
                                SubFilter: 'adbe.pkcs7.detached',
                                ByteRange: [
                                    0,
                                    byteRangePlaceholder,
                                    byteRangePlaceholder,
                                    byteRangePlaceholder
                                ],
                                Contents: Buffer.from(String.fromCharCode(0).repeat(signatureLength)),
                                Reason: new String("Blabla"),
                                M: new Date(),
                                ContactInfo: new String("[email protected]"),
                                Name: new String('Bla'),
                                Location: new String('Bla')
                            }),
                            signatureName = 'Signature',
                            widget = doc.ref({
                                Type: 'Annot',
                                Subtype: 'Widget',
                                FT: 'Sig',
                                Rect: [0, 0, 0, 0],
                                V: signature,
                                T: new String(signatureName + (fieldIds.length + 1)),
                                F: 4,
                                P: doc.page.dictionary
                            });
                    doc.page.dictionary.data.Annots = [widget];

                    form = doc.ref({
                        Type: 'AcroForm',
                        SigFlags: 3,
                        Fields: [...fieldIds, widget]
                    });
                    doc._root.data.AcroForm = form;
                    signature.end();
                    widget.end();
                    form.end();
                }
                doc.end();
                const assinarPDF = new signpdf.SignPdf(
                        FS.readFileSync("./bla.pdf"),
                        FS.readFileSync(".bla.p12")
                        );

Can you help identifiyng what am i missing? Thank you.

How to generate a pdf file with the signature and its certificate using token

Hi Experts,
Im using a GEMALTO USB Key SmartCard, and i want to put a digital signature in my PDF file.

For that, I read several articles on google about this topic.
After these readings, I succeeded to write a code, that could get the PRIVATE_KEY, PUBLIC_KEY and the SIGNATURE from my token (see myExample_1.js myExample_1.txt and his result
result.txt).

Now my question is:
How can i get the certificate from my token, and put it in my pdf file?

Thank you for help.

Cannot read property 'split' of undefined

can anyone help why I am getting this issue?
here is my code:-

const signer = require('node-signpdf').default;
const  {plainAddPlaceholder} = require('node-signpdf/dist/helpers');

const action = async () => {
var pdfBuffer = fs.readFileSync('./test.pdf');
 pdfBuffer = plainAddPlaceholder({
    pdfBuffer,
    reason: 'I am the author',
    signatureLength: 1612,
  });
let p12Buffer = fs.readFileSync('./certificate.p12')
let pdf = signer.sign(pdfBuffer, p12Buffer);
fs.writeFileSync(__dirname + '/result.pdf', pdf);
}

action();

and i am getting this error.

(node:9110) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'split' of undefined
at getXref (/home/hp/project/node_modules/node-signpdf/dist/helpers/plainAddPlaceholder/readRefTable.js:55:34)
at getFullXrefTable (/home/hp/project/node_modules/node-signpdf/dist/helpers/plainAddPlaceholder/readRefTable.js:79:25)
at readRefTable (/home/hp/project/node_modules/node-signpdf/dist/helpers/plainAddPlaceholder/readRefTable.js:100:25)
at readPdf (/home/hp/project/node_modules/node-signpdf/dist/helpers/plainAddPlaceholder/readPdf.js:31:46)
at plainAddPlaceholder (/home/hp/project/node_modules/node-signpdf/dist/helpers/plainAddPlaceholder/index.js:54:37)
at action (/home/hp/project/index.js:92:14)
at Object. (/home/hp/project/index.js:105:1)
at Module._compile (internal/modules/cjs/loader.js:1157:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1177:10)
at Module.load (internal/modules/cjs/loader.js:1001:32)
(node:9110) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:9110) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

[Help] Could not find ByteRange placeholder

First of all, thank you for this amazing library. I would like to know when I read the PDF, there is an error 'Could not find ByteRange placeholder', how can I append the ByteRange to an existing PDF if it is not found?

Helpers not works with [email protected]

 PASS  src/helpers/plainAddPlaceholder/createBufferPageWithAnnotation.test.js
 PASS  src/helpers/removeTrailingNewLine.test.js
 PASS  src/helpers/extractSignature.test.js
 PASS  src/SignPdfError.test.js
 PASS  src/helpers/index.test.js
 PASS  src/helpers/plainAddPlaceholder/readRefTable.test.js
 PASS  src/helpers/plainAddPlaceholder/getIndexFromRef.test.js
 PASS  src/helpers/plainAddPlaceholder/index.test.js
 PASS  src/helpers/pdfkitReferenceMock.test.js
 PASS  src/helpers/plainAddPlaceholder/getPagesDictionaryRef.test.js
 PASS  src/helpers/pdfkitAddPlaceholder.test.js
 FAIL  src/helpers.test.js
  ● Helpers › extract signature from signed pdf

    TypeError: Cannot read property 'fonts' of undefined

      52 |     // Also end the PDFDocument stream.
      53 |     // See pdf.on('end'... on how it is then converted to Buffer.
    > 54 |     pdf.end();
         |         ^
      55 | });
      56 | 
      57 | describe('Helpers', () => {

      at PDFDocument.endAcroForm (node_modules/pdfkit/lib/mixins/acroform.js:78:37)
      at PDFDocument.end (node_modules/pdfkit/lib/document.js:274:10)
      at src/helpers.test.js:54:9
      at createPdf (src/helpers.test.js:15:7)
      at Object.<anonymous> (src/helpers.test.js:59:33)

 FAIL  src/signpdf.test.js
  ● Test signing › expects a reasonably sized placeholder

    expect(received).toBe(expected) // Object.is equality

    Expected: true
    Received: false

      105 |             expect('here').not.toBe('here');
      106 |         } catch (e) {
    > 107 |             expect(e instanceof SignPdfError).toBe(true);
          |                                               ^
      108 |             expect(e.type).toBe(SignPdfError.TYPE_INPUT);
      109 |             expect(e.message).toMatchSnapshot();
      110 |         }

      at Object.<anonymous> (src/signpdf.test.js:107:47)

  ● Test signing › signs input PDF

    TypeError: Cannot read property 'fonts' of undefined

      59 |     // Also end the PDFDocument stream.
      60 |     // See pdf.on('end'... on how it is then converted to Buffer.
    > 61 |     pdf.end();
         |         ^
      62 | });
      63 | 
      64 | describe('Test signing', () => {

      at PDFDocument.endAcroForm (node_modules/pdfkit/lib/mixins/acroform.js:78:37)
      at PDFDocument.end (node_modules/pdfkit/lib/document.js:274:10)
      at src/signpdf.test.js:61:9
      at createPdf (src/signpdf.test.js:13:29)
      at Object.<anonymous> (src/signpdf.test.js:113:31)

  ● Test signing › signs detached

    TypeError: Cannot read property 'fonts' of undefined

      59 |     // Also end the PDFDocument stream.
      60 |     // See pdf.on('end'... on how it is then converted to Buffer.
    > 61 |     pdf.end();
         |         ^
      62 | });
      63 | 
      64 | describe('Test signing', () => {

      at PDFDocument.endAcroForm (node_modules/pdfkit/lib/mixins/acroform.js:78:37)
      at PDFDocument.end (node_modules/pdfkit/lib/document.js:274:10)
      at src/signpdf.test.js:61:9
      at createPdf (src/signpdf.test.js:13:29)
      at Object.<anonymous> (src/signpdf.test.js:126:31)

  ● Test signing › signs with ca, intermediate and multiple certificates bundle

    TypeError: Cannot read property 'fonts' of undefined

      59 |     // Also end the PDFDocument stream.
      60 |     // See pdf.on('end'... on how it is then converted to Buffer.
    > 61 |     pdf.end();
         |         ^
      62 | });
      63 | 
      64 | describe('Test signing', () => {

      at PDFDocument.endAcroForm (node_modules/pdfkit/lib/mixins/acroform.js:78:37)
      at PDFDocument.end (node_modules/pdfkit/lib/document.js:274:10)
      at src/signpdf.test.js:61:9
      at createPdf (src/signpdf.test.js:13:29)
      at Object.<anonymous> (src/signpdf.test.js:165:31)

  ● Test signing › signs with passphrased certificate

    TypeError: Cannot read property 'fonts' of undefined

      59 |     // Also end the PDFDocument stream.
      60 |     // See pdf.on('end'... on how it is then converted to Buffer.
    > 61 |     pdf.end();
         |         ^
      62 | });
      63 | 
      64 | describe('Test signing', () => {

      at PDFDocument.endAcroForm (node_modules/pdfkit/lib/mixins/acroform.js:78:37)
      at PDFDocument.end (node_modules/pdfkit/lib/document.js:274:10)
      at src/signpdf.test.js:61:9
      at createPdf (src/signpdf.test.js:13:29)
      at Object.<anonymous> (src/signpdf.test.js:176:31)

  ● Test signing › errors on wrong certificate passphrase

    TypeError: Cannot read property 'fonts' of undefined

      59 |     // Also end the PDFDocument stream.
      60 |     // See pdf.on('end'... on how it is then converted to Buffer.
    > 61 |     pdf.end();
         |         ^
      62 | });
      63 | 
      64 | describe('Test signing', () => {

      at PDFDocument.endAcroForm (node_modules/pdfkit/lib/mixins/acroform.js:78:37)
      at PDFDocument.end (node_modules/pdfkit/lib/document.js:274:10)
      at src/signpdf.test.js:61:9
      at createPdf (src/signpdf.test.js:13:29)
      at Object.<anonymous> (src/signpdf.test.js:191:33)

  ● Test signing › errors when no matching certificate is found in bags

    TypeError: Cannot read property 'fonts' of undefined

      59 |     // Also end the PDFDocument stream.
      60 |     // See pdf.on('end'... on how it is then converted to Buffer.
    > 61 |     pdf.end();
         |         ^
      62 | });
      63 | 
      64 | describe('Test signing', () => {

      at PDFDocument.endAcroForm (node_modules/pdfkit/lib/mixins/acroform.js:78:37)
      at PDFDocument.end (node_modules/pdfkit/lib/document.js:274:10)
      at src/signpdf.test.js:61:9
      at createPdf (src/signpdf.test.js:13:29)
      at Object.<anonymous> (src/signpdf.test.js:207:33)

Test Suites: 2 failed, 11 passed, 13 total
Tests:       8 failed, 27 passed, 35 total
Snapshots:   19 passed, 19 total
Time:        3.203s, estimated 4s
Ran all test suites.

How-to make signature visible on PDF

Hi there,

thanks a lot for the lib.

I have implemented de signature with . a p12 file on the pdf and I am being able to check the signature on the available validation tools, but the signature is no visible on pdf itself when open on regular pdf viewer.

Is it possible to do so?
Let a visible mark that the document has being signed.

Thanks

For some PDFs plainAddPlaceholder returns error, although it works for w3dummy.pdf

function signExistingPDF(pdfFile: string) {
  let pdfBuffer = readFileSync(pdfFile);
  pdfBuffer = plainAddPlaceholder({
      pdfBuffer,
      reason: 'I have reviewed it.',
      // signatureLength: 1612,
  });

  return pdfBuffer;
}

Stack trace

TypeError: Cannot read property 'split' of undefined
    at getXref (/.../node_modules/node-signpdf/dist/helpers/plainAddPlaceholder/readRefTable.js:55:34)
    at getFullXrefTable (/.../node_modules/node-signpdf/dist/helpers/plainAddPlaceholder/readRefTable.js:79:25)
    at readRefTable (/.../node_modules/node-signpdf/dist/helpers/plainAddPlaceholder/readRefTable.js:100:25)
    at readPdf (/.../node_modules/node-signpdf/dist/helpers/plainAddPlaceholder/readPdf.js:31:46)
    at plainAddPlaceholder (/.../node_modules/node-signpdf/dist/helpers/plainAddPlaceholder/index.js:54:37)
    at signExistingPDF (/.../pdfsig/index.ts:66:15)
........

Although it works for w3dummy.pdf

Using require instead of nodejs modules (import)

Hello,

After install of the node-signpdf i do:

const signpdf = require('node-signpdf')
const sign = signpdf.sign(
                        FS.readFileSync("pdf.pdf"),
                        FS.readFileSync("p12.p12")
                        );

But it gives:
TypeError: signpdf.sign is not a function

How to proceed with this? Thank you.

TypeScript version

First of all, thank you for your awesome work, it is really far from trivial to implement the signing of PDFs in pure node. Great job.

In our team we are writing all the JavaScript code in TypeScript, so it is better manageable, better understandable and less error-prone and I was quite missing the type safety it in the node-signpdf. So I have stopped a little bit to migrate all the code to TypeScript (including tests). I was not able to back-engineer all the types used, so in few edge cases I have used magical keyword any.

All package.json scripts work, all tests pass, everything seems to be ok.
If you are interested I can send you PR.

function plainAddPlaceholder remove metadata of pdf

Hi.

I'm using a function plainAddPlaceholder to sign pdf with metadata. Library sign correctly a file, but remove all metadata of his.

This is my code:

const pdfBuffer = fs.readFileSync(absoluteLocalPath);
const signBuffer = fs.readFileSync(process.env.CERTIFICATE_PATH);
let inputBuffer = plainAddPlaceholder({
      pdfBuffer,
      reason: 'I have reviewed it.',
      signatureLength: signBuffer.length,
});

const signedPdf = signer.sign(
      inputBuffer,
     signBuffer,
     { passphrase: 'badssl.com' },
);

fs.writeFileSync(absoluteLocalPath, signedPdf);

Can you help me @vbuch?

Thanks

Regards.`

Unable to save a valid version of the signed PDF file

Describe the bug and the expected behaviour
Here is a test function that I use to test signing a dummy PDF document with a dummy certificate.

export const testFileSigning = (_req: Request, res: Response, next: NextFunction) => {

  // Hardcode some paths for testing purposes
  const pdfFilePath = "c:/temp/cert/cert.pdf";
  const pdfSignedFilePath = "c:/temp/cert/cert_signed.pdf";
  const certFilePath = "c:/temp/cert/certificate.p12";

  // Create some streams
  const p12Buffer = fs.readFileSync(certFilePath);
  let pdfBuffer = fs.readFileSync(pdfFilePath);

  // Add placeholder
  pdfBuffer = plainAddPlaceholder.default({
    pdfBuffer,
    reason: 'I have reviewed it.',
    signatureLength: 8192,
  });
  try {
    // Sign the doc
    pdfBuffer = signer.sign(pdfBuffer, p12Buffer);
  } catch (err) {
    console.error(`Error signing document`, err);
    next(err);
  }

  // Write to file
  fs.writeFile(pdfSignedFilePath, pdfBuffer, { encoding: 'binary' }, (err) => {
    if (!!err) {
      next(err);
    } else {
      res.locals.data = { signed: true };
      next();
    }
  });
};

So fs.writeFile saves the pdfBuffer that results from the sign method into a file called cert_signed.pdf.

When I open the file, the file is blank, it's broken / tiny so that it's zoomed in to like 4000%

image

and when I try to zoom out I see that error

There was a problem reading this document (14)

image

and the file itself seems to be corrupt / empty.

Is it a bug in signing or in the helpers?
I am not even sure if this is a bug or if I'm doing something wrong when trying to save the signed file. If it's a bug I would assume it's a bug with the sign function.

To Reproduce
I've described how to reproduce the issue in the previous points. I am testing with the certificate.p12 file that comes in this repo. I have also attached the 2 PDF files: the source cert.pdf file as well as the resulting cert_signed.pdf file.

cert.pdf
cert_signed.pdf

Your help would be appreciated. I saw someone else pointing to this error in a closed github issue so I figured I would make a separate issue for anyone facing the same problem as me.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.