node-signpdf
node-signpdf copied to clipboard
Issue with PFX
Describe the bug and the expected behaviour
(node:209944) UnhandledPromiseRejectionWarning: TypeError: sign is not a function
at assinarPdfComPfx (/root/cert/app.js:66:24)
at /root/cert/app.js:78:15
at Object.<anonymous> (/root/cert/app.js:78:79)
at Module._compile (internal/modules/cjs/loader.js:1114:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10)
at Module.load (internal/modules/cjs/loader.js:979:32)
at Function.Module._load (internal/modules/cjs/loader.js:819:12)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12)
at internal/main/run_main_module.js:17:47
(Use `node --trace-warnings ...` to show where the warning was created)
(node:209944) 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: 2)
(node:209944) [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.
Is it a bug in signing or in the helpers? Why yhe bug with sign is not function?
To Reproduce
const forge = require('node-forge');
const fs = require('fs');
const { sign } = require('node-signpdf');
const { plainAddPlaceholder } = require('node-signpdf/dist/helpers');
function readPfxFile(filePath, pfxPassword) {
const pfxFile = fs.readFileSync(filePath);
const asn1 = forge.asn1.fromDer(pfxFile.toString('binary'));
const pfx = forge.pkcs12.pkcs12FromAsn1(asn1, pfxPassword);
const bags = pfx.getBags({bagType: forge.pki.oids.certBag});
const keyBags = pfx.getBags({bagType: forge.pki.oids.pkcs8ShroudedKeyBag});
const certificate = bags[forge.pki.oids.certBag][0].cert;
const privateKey = keyBags[forge.pki.oids.pkcs8ShroudedKeyBag][0].key;
const certPem = forge.pki.certificateToPem(certificate);
const privateKeyPem = forge.pki.privateKeyToPem(privateKey);
console.log('Certificado:');
console.log('Emitido para: ', certificate.subject.attributes.map(attr => `${attr.name}=${attr.value}`).join(', '));
console.log('Emitido por: ', certificate.issuer.attributes.map(attr => `${attr.name}=${attr.value}`).join(', '));
console.log('Válido de: ', certificate.validity.notBefore);
console.log('Válido até: ', certificate.validity.notAfter);
return { certPem, privateKeyPem };
}
function extrairDePfx(caminhoDoPfx, senhaPfx) {
const pfx = fs.readFileSync(caminhoDoPfx, {encoding: 'binary'});
const pfxAsn1 = forge.asn1.fromDer(pfx);
const pfxObj = forge.pkcs12.pkcs12FromAsn1(pfxAsn1, senhaPfx);
const keyBags = pfxObj.getBags({bagType: forge.pki.oids.pkcs8ShroudedKeyBag});
const privateKey = forge.pki.privateKeyToPem(keyBags[forge.pki.oids.pkcs8ShroudedKeyBag][0].key);
const certBags = pfxObj.getBags({bagType: forge.pki.oids.certBag});
const cert = forge.pki.certificateToPem(certBags[forge.pki.oids.certBag][0].cert);
return { privateKey, cert };
}
async function assinarPdfComPfx(caminhoDoPdf, caminhoDoPfx, senhaPfx) {
const { privateKey, cert } = extrairDePfx(caminhoDoPfx, senhaPfx);
let pdfBuffer = fs.readFileSync(caminhoDoPdf);
// Adicionar um placeholder de assinatura ao PDF, se necessário
pdfBuffer = plainAddPlaceholder({
pdfBuffer,
reason: 'Eu concordo com o conteúdo deste documento.',
signatureLength: 8192,
});
// Assinar o PDF
const assinatura = sign(pdfBuffer, privateKey, [cert], {
passphrase: senhaPfx,
});
fs.writeFileSync('./arquivo-assinado.pdf', assinatura);
}
const { certPem, privateKeyPem } = readPfxFile('./certificadoFinal.pfx', '123456');
console.log('Certificado:', certPem);
console.log('Chave Privada:', privateKeyPem);
(async () => assinarPdfComPfx('./1.pdf', './certificadoFinal.pfx', '123456'))();
Working with
var fs = require('fs');
var path = require('path');
var PDFDocument = require('pdf-lib').PDFDocument;
var pdflibAddPlaceholder = require('@signpdf/placeholder-pdf-lib').pdflibAddPlaceholder;
var signpdf = require('@signpdf/signpdf').default;
var P12Signer = require('@signpdf/signer-p12').P12Signer;
function work() {
// contributing.pdf is the file that is going to be signed
var sourcePath = path.join(__dirname, '1.pdf');
var pdfBuffer = fs.readFileSync(sourcePath);
// certificate.p12 is the certificate that is going to be used to sign
var certificatePath = path.join(__dirname, 'certificadoFinal.pfx');
var certificateBuffer = fs.readFileSync(certificatePath);
var signer = new P12Signer(certificateBuffer, { passphrase: "123456" });
// Load the document into PDF-LIB
PDFDocument.load(pdfBuffer).then(function (pdfDoc) {
// Add a placeholder for a signature.
pdflibAddPlaceholder({
pdfDoc: pdfDoc,
reason: 'The user is declaring consent through JavaScript.',
contactInfo: '[email protected]',
name: 'John Doe',
location: 'Free Text Str., Free World',
});
// Get the modified PDFDocument bytes
pdfDoc.save().then(function (pdfWithPlaceholderBytes) {
// And finally sign the document.
signpdf
.sign(pdfWithPlaceholderBytes, signer)
.then(function (signedPdf) {
// signedPdf is a Buffer of an electronically signed PDF. Store it.
var targetPath = path.join(__dirname, 'pdf-lib.pdf');
fs.writeFileSync(targetPath, signedPdf);
})
})
})
}
work();`
but with can't install : @signpdf/placeholder-pdfkit010 using v21 node.js
var fs = require('fs');
var path = require('path');
var PDFDocument = require('pdfkit');
var signpdf = require('@signpdf/signpdf').default;
var P12Signer = require('@signpdf/signer-p12').P12Signer;
var pdfkitAddPlaceholder = require('@signpdf/placeholder-pdfkit010').pdfkitAddPlaceholder;
/**
* Transform coordinates from top/left to bottom/left coordinate system
*/
function topLeftToBottomLeft(coords, page) {
return [
coords[0], // x1
page.height - coords[1], // y1
coords[2], // x2
page.height - coords[3], // y2
];
}
function addVisual(pdf) {
// Go to first page
pdf.switchToPage(0);
var margin = 30;
var padding = 10;
var label = 'Signed with @signpdf';
pdf
.fillColor('#008B93')
.fontSize(10);
var text = {
width: pdf.widthOfString(label),
height: pdf.heightOfString(label)
};
text.x = pdf.page.width - text.width - margin;
text.y = pdf.page.height - text.height - margin;
pdf.text(label, text.x, text.y, {width: text.width, height: text.height});
return [
text.x - padding,
text.y - padding,
text.x + text.width + padding,
text.y + text.height + padding,
];
}
function work() {
// Start a PDFKit document
var pdf = new PDFDocument({
autoFirstPage: false,
size: 'A4',
layout: 'portrait',
bufferPages: true,
});
pdf.info.CreationDate = '';
// At the end we want to convert the PDFKit to a string/Buffer and store it in a file.
// Here is how this is going to happen:
var pdfReady = new Promise(function (resolve) {
// Collect the ouput PDF
// and, when done, resolve with it stored in a Buffer
var pdfChunks = [];
pdf.on('data', function (data) {
pdfChunks.push(data);
});
pdf.on('end', function () {
resolve(Buffer.concat(pdfChunks));
});
});
// Add some content to the page(s)
pdf
.addPage()
.fillColor('#333')
.fontSize(25)
.moveDown()
.text('@signpdf');
// !!! ADDING VISUALS AND APPLYING TO SIGNATURE WIDGET ==>
// Add a some visuals and make sure to get their dimensions.
var visualRect = addVisual(pdf);
// Convert these dimension as Widgets' (0,0) is bottom-left based while the
// rest of the coordinates on the page are top-left.
var widgetRect = topLeftToBottomLeft(visualRect, pdf.page);
// Here comes the signing. We need to add the placeholder so that we can later sign.
var refs = pdfkitAddPlaceholder({
pdf: pdf,
pdfBuffer: Buffer.from([pdf]), // FIXME: This shouldn't be needed.
reason: 'Showing off.',
contactInfo: '[email protected]',
name: 'Sign PDF',
location: 'The digital world.',
signatureLength: 1612,
widgetRect: widgetRect, // <== !!! This is where we tell the widget to be visible
});
// <== !!! ADDING VISUALS AND APPLYING TO SIGNATURE WIDGET
// `refs` here contains PDFReference objects to signature, form and widget.
// PDFKit doesn't know much about them, so it won't .end() them. We need to do that for it.
Object.keys(refs).forEach(function (key) {
refs[key].end()
});
// Once we .end the PDFDocument, the `pdfReady` Promise will resolve with
// the Buffer of a PDF that has a placeholder for signature that we need.
// Other that we will also need a certificate
// certificate.p12 is the certificate that is going to be used to sign
var certificatePath = path.join(__dirname, 'certificadoFinal.pfx');
var certificateBuffer = fs.readFileSync(certificatePath);
var signer = new P12Signer(certificateBuffer, { passphrase: "123456" });
// Once the PDF is ready we need to sign it and eventually store it on disc.
pdfReady
.then(function (pdfWithPlaceholder) {
return signpdf.sign(pdfWithPlaceholder, signer);
})
.then(function (signedPdf) {
var targetPath = path.join(__dirname, 'pdfkit010-with-visual.pdf');
fs.writeFileSync(targetPath, signedPdf);
});
// Finally end the PDFDocument stream.
pdf.end();
// This has just triggered the `pdfReady` Promise to be resolved.
}
work();