vbuch / node-signpdf

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

TypeError: Cannot read property 'split' of undefined #79

Closed Danny626 closed 3 years ago

Danny626 commented 4 years ago

Hi! I have the error with this pdf file and others generated with a same library, please if you could give me a hand I would really appreciate it.

Here is the pdf file: descarga.pdf

The code used to sign:

    const p12Buffer = fs.readFileSync('./assets/certificados/certificate.pfx');
    let pdfBuffer = fs.readFileSync('./assets/pdfEntrada/descarga.pdf');
    pdfBuffer = plainAddPlaceholder({
        pdfBuffer,
        reason: 'I have reviewed it.',
        signatureLength: 1612,
    });
    pdfBuffer = await signer.sign(
        pdfBuffer,
        p12Buffer,
        {passphrase: 'password'},
    );

and i am getting this error.

(node:8496) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'split' of undefined at getXref (C:\Users\danie\Proyectos\firmaDig_backend\helpers\plainAddPlaceholder\readRefTable.js:48:36) at getFullXrefTable (C:\Users\danie\Proyectos\firmaDig_backend\helpers\plainAddPlaceholder\readRefTable.js:77:27) at readRefTable (C:\Users\danie\Proyectos\firmaDig_backend\helpers\plainAddPlaceholder\readRefTable.js:99:27) at readPdf (C:\Users\danie\Proyectos\firmaDig_backend\helpers\plainAddPlaceholder\readPdf.js:22:22) at plainAddPlaceholder (C:\Users\danie\Proyectos\firmaDig_backend\helpers\plainAddPlaceholder\index.js:36:18) at firmarPDF2 (C:\Users\danie\Proyectos\firmaDig_backend\app.js:231:17) at procesoCompleto (C:\Users\danie\Proyectos\firmaDig_backend\app.js:55:11) at C:\Users\danie\Proyectos\firmaDig_backend\app.js:34:5 at Layer.handle [as handle_request] (C:\Users\danie\Proyectos\firmaDig_backend\node_modules\express\lib\router\layer.js:95:5) at next (C:\Users\danie\Proyectos\firmaDig_backend\node_modules\express\lib\router\route.js:137:13) (node:8496) 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(). (rejection id: 2) (node:8496) [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.

i-olivares commented 4 years ago

Hi @Danny626 ,

I think I know what it is causing the error, pdf files have usually a structure like Head+ Body + xref Table + trailer (https://resources.infosecinstitute.com/pdf-file-format-basic-structure/#gref) but it turns out that pdfs created but adobe acrobat newer versions have not the trailer part (https://acrobatusers.com/forum/pdf-creation/no-trailer-newly-created-pdfs/ ). Therefore, the program fails when trying to identify parts of the pdf and store them in variables -> you get the error " Cannot read property 'split' of undefined" because the variable is undefined.

Well, It's been a month since you posted the issue so maybe you already know it but perhaps It helps someone else. Were you finally able to sign the pdf? I'm having trouble to achieve it , I could use a hand!

molinajulian commented 4 years ago

Hi @Danny626 , I had the same problem and I found a solution. If you open the PDF with a text editor, you will see at the top of the file something similar to %PDF-1.5 . In my case, my version was 1.6. You must convert your PDF to version 1.3. I used this page for that. This works for me.

Kunamatata commented 4 years ago

@vbuch does node-signpdf support PDF version 1.3 and not higher ?

vbuch commented 4 years ago

Not sure how much higher is not supported. But, yes, streams, linearized, etc... features that I've seen in 1.5+ are not supported. PRs are always welcome.

davidlimajet commented 4 years ago

Someone has managed to solve this problem? Regards

gizmodus commented 4 years ago

I have the same problem and downgrading the pdf document to 1.3 as suggested by @molinajulian unfortunately did not help.

NoahCardoza commented 4 years ago

@molinajulian While that tip fixed the errors for me, now Acrobat doesn't detect a signature after being signed 😞

I'm happy to try and fix this issue but I'm not exactly sure where to start @vbuch. Any suggestions?

As I understand the problem: This so called "trailer" sections of the PDF is missing in newer versions. Is this part important at all the the signing process? Or might it be safe to basically ignore the fact that there is no "trailer"?

NoahCardoza commented 4 years ago

Here is an example repo for reference.

NoahCardoza commented 4 years ago

After further research, while it does seem to be a problem with the lib not being able to read newer PDFs, I found a simple work around for the time being:

pdftk input.pdf output output.pdf

Is able add the proper trailer to the end of the PDF. In my case the PDF was also protected, so I used:

qpdf --decrypt encrypted.pdf unencrypted.pdf
pdftk unencrypted.pdf output output.pdf

Note: This was able to preserve the form fields!

I hope this helps someone else and saves them the 3 days it took me!

At the moment, fixing this issue is no longer a priority, but I am interested in learning more about PDFs so I may look into this at a later date.

NoahCardoza commented 4 years ago

@gizmodus Check out the my last comment and let me know if that works for you too.

vbuch commented 4 years ago

The trailer is not essential to the signing, but ... is essential to parsing the PDF. That's where the whole info on the document's structure was held until 1.3. I don't have the time to read on how > 1.3 is parsed. May be trivial. May be complex. No clue. It goes through reading the specs.

gizmodus commented 4 years ago

In the meantime, I was able to sign the PDF by applying the placeholder with pdf-lib like explained here: https://github.com/Hopding/pdf-lib/issues/112

The signature is visible now in Acrobat. The only problem is that in Acrobat it says: "Signature is invalid: There are errors in the formatting or information contained in this signature (The signature byte range is invalid)"

Does anybody has a clue what could be the cause of this?

davidlimajet commented 4 years ago

Hello everyone, I managed to solve this problem by changing the version of the PDF with libreoffice-convert before signing it.

Arisdolanan commented 3 years ago

sorry briefly my code, this code works on me!

i use pdf-lib : 1.14.1 node-signpdf : 1.3.2.

const { PDFDocument, } = require("pdf-lib");

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

//add this your code var pdfDoc = await PDFDocument.load(bytes, { ignoreEncryption: true, });

//add this your code const pdfBytes = await pdfDoc.save({ useObjectStreams: false });

const p12Buffer = fs.readFileSync(path.join(__dirname, "../utils/test.pfx"));

const pdfBuffer = fs.readFileSync(${sourceFolder}/${test}); dinamic

const pdfWithPlaceholder = plainAddPlaceholder({ pdfBuffer, reason: "i can do it", });

const signedPdf = signer.sign(pdfWithPlaceholder, p12Buffer, { passphrase: "test", });

fs.writeFileSync("test-id.pdf", signedPdf);

fratt-elca commented 3 years ago

I can confirm that @Arisdolanan solution works!

I was already using pdf-lib to add a "visual signature" on the document before signing it, and it was not working, but adding { useObjectStreams: false } to the save() method did the trick!

Thanks a lot!

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.

ghoshpushpendu commented 2 years ago

this issue occurs when you are using PDF-Lib to add or parse the PDF before the signing process.

{ useObjectStreams: false } to the save() method did the trick! in pdf-lib

vbuch commented 11 months ago

If this is to be resolved the starting point would be: https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.7old.pdf Section 3.4.7 Cross-Reference Streams

The file @Danny626 has posted here uses that feature which came in PDF 1.5. What needs to happen is an implementation that can parse the following XRef:


<< /Type /XRef % Cross-reference stream dictionary
/Size ...
/Root ...
>>
stream
... % Stream data containing cross-reference information
endstream
endobj```