Open DebadattaMeher opened 1 year ago
You are experiencing the limitations of this library in terms of encrypted PDFs. See here: https://github.com/Hopding/pdf-lib#encryption-handling.
You are using ignoreEncryption
, but this will just "hide" the issue.
Thanks for building this awesome library, maintaining and documenting it so cleanly. Will there be a support for encrypted PDFs in future ?
I am not the original author of this package, but i've forked it and build very basic/crude decryption support: https://github.com/KammererTob/pdf-lib
Note that this is probably not bug-free and also not very efficient (it parses the PDF twice), but from my limited testing it worked for my purpose. I have not opened a PR for this, because of the above mentioned issues and also missing unit-tests
To use it you need to keep "ignoreEncryption: true" and it should then try to decrypt it.
I am not the original author of this package, but i've forked it and build very basic/crude decryption support: https://github.com/KammererTob/pdf-lib
Note that this is probably not bug-free and also not very efficient (it parses the PDF twice), but from my limited testing it worked for my purpose. I have not opened a PR for this, because of the above mentioned issues and also missing unit-tests
To use it you need to keep "ignoreEncryption: true" and it should then try to decrypt it.
I used this option "ignoreEncryption: true"
to be able to open the PDF document and try to draw lines on it. But unable to save the PDF after drawing lines. The output PDF is unedited (without containing the drawn lines) if used the encryption option during saving OR blank (empty pages) with exact same number of pages if used without the encryption option.
Hello @KammererTob, did you publish your fork somewhere?
@GiuseppePennisi No. I haven't published my fork anywhere. For my own project i build it once and then used the minified file directly.
We'll try to add this to our fork and maintain it. Our fork already adds support to drawing svg. see this PR. I'll tell you if I succeeded.
@KammererTob Can you confirm the following points with me?
Right now, there is no way to provide the password. I need to add this to the constructor of PDFDocument
and pass it to CipherTransformFactory
You will try to match the password with the userPassword and the ownerPassword of the pdf. Right now, if the password is the same for both, you check the userPassword first. We should probably switch that order, otherwise, the owner cannot access the higher credentials
If I load a pdf with password, I get this error:
Uncaught (in promise) TypeError: dict.get(...) is undefined
CipherTransformFactory crypto.js:1355
PDFDocument PDFDocument.js:52
load PDFDocument.js:132
fulfilled tslib.es6.js:73
promise callback*step tslib.es6.js:75
__awaiter tslib.es6.js:76
__awaiter tslib.es6.js:72
load PDFDocument.js:124
test test27.html:56
onclick test27.html:1staticOnEvent
algorithm
is 5
at that moment.
@Sharcoux It has been a while since i looked at the specs, but here are my answers from the top of my head:
load()
. I just load the file, and if it requires a password, I ask for the password and load again. So, nothing that should be handled from pdf-lib(dict.get(PDFName.of("EncryptMetadata")) as PDFBool).asBoolean() !== false;
. There is no EncryptMetadata in the dict apparently...I could solve the 3rd issue. Apparently:
EncryptMetadata (Boolean): It specifies whether the document metadata (information about the document itself such as title, author, etc.) is to be encrypted. This entry is meaningful only when encrypting metadata, which is when the value of the V entry (version of the standard security handler) in the encryption dictionary is greater than or equal to 2.
If EncryptMetadata is true (or if it's not specified), then metadata should be encrypted.
If EncryptMetadata is false, metadata should remain in plain text.
In some cases, for certain PDF versions or types of encryption, the EncryptMetadata key might not be present in the encryption dictionary. Therefore, when reading or processing the encryption dictionary in a PDF, it's essential to account for the possibility that the EncryptMetadata key might be absent. If it's not specified, its default value should be considered as true.
I solved some more issues, but I'm now stuck at this:
Uncaught (in promise) Error: Expected instance of PDFDict, but got instance of undefined
UnexpectedObjectTypeError errors.js:22
lookup PDFContext.js:81
lookup PDFDict.js:52
Pages PDFCatalog.js:7
computePages PDFDocument.js:26
access Cache.js:11
getPages PDFDocument.js:478
getPageCount PDFDocument.js:462
save PDFDocument.js:1139
__awaiter tslib.es6.js:76
__awaiter tslib.es6.js:72
save PDFDocument.js:1133
test test27.html:57
It happens as soon as I use any method from the pdfDoc generated.
The error occurs when trying to read "Pages": return this.lookup(PDFName.of('Pages'), PDFDict) as PDFPageTree;
The final error is line 166 of PDFContext.
I'm done. You can try npm package @cantoo/pdf-lib
. Some details might change in the next few days, but don't hesitate to try and report.
PDFObjectParser.parseString
method in pdf-lib
doesn't handle encrypted strings correctly. Therefore strings don't get decrypted properly and decryption code by @KammererTob corrupts the document. I ported the parseString
function from pdf.js
(https://github.com/chebum/pdf-lib/commit/485d3523ef0b1582332aef4f768f52604f5a5dd1) - this seems to solve the problem.
I have no news from hopding for a while. We maintain the repo @cantoo/pdf-lib for now. Do you know if your change is needed there too? It seems to work on our end.
It seems to work on our end.
@Sharcoux It seems to be working for some of the encoded strings, but not for all - some strings don't get decoded properly. For example, check object number 60 in this document https://github.com/chebum/pdf-lib/blob/master/assets/pdfs/encrypted_3.pdf. T field should say "Karen Scoon"
const pdfDoc = await PDFDocument.load(
fs.readFileSync('assets/pdfs/encrypted_3.pdf'),
{
parseSpeed: ParseSpeeds.Fastest,
},
);
expect(pdfDoc).toBeInstanceOf(PDFDocument);
const originalObjects = pdfDoc.context.enumerateIndirectObjects();
const originalObj60 = originalObjects.find(obj => obj[0].objectNumber === 60) as [PDFRef, PDFDict];
expect(originalObj60[1].get(PDFName.of('T'))?.toString()).toEqual('(Karen Scoon)');
What were you trying to do?
I am trying to draw some lines in an encrypted PDF document. I tried with 2 things to do this as the first approach did not work.
How did you attempt to do it?
Code Below for first approach.
inputFile, outputFile are paths to file. eg: /tmp/tmpfiles/sample.pdf
Code Below for 2nd approach.
What actually happened?
In case of drawing line directly to the encrypted document, the lines are not visible or not drawn in the PDF. The lines doesn't appear in the PDF when opened in any viewer (chrome, default mac preview).
I will use 'srcPDF' to refer to the encrypted PDF document and 'destPDF' to refer to the copied PDF document in further description below
On copying the srcPDF document to a destPDF, the pages in the destPDF document are blank (white pages). The destPDF contain same number of pages as the srcPDF. The file-size of the destPDF document is same as the srcPDF document.
What did you expect to happen?
How can we reproduce the issue?
I cannot share the PDF as it contains confidential detail and PII data. If possible, use the Automobile policy declaration PDF of Travelers insurance provider in USA.
I've share the code in the description.
Version
1.17.1
What environment are you running pdf-lib in?
Node
Checklist
Additional Notes
I apologize for not being able to share the PDF sample.