From 920e0d00b9a5864c63f996196f4dc65d87ff228b Mon Sep 17 00:00:00 2001 From: Vladimir Date: Fri, 24 Apr 2026 15:52:03 +0300 Subject: [PATCH 1/2] Add Metadata pop-up (extract encryption dictionary) --- src/core/crypto.js | 10 ++++++++++ src/core/document.js | 4 ++++ src/core/worker.js | 4 ++++ src/core/xref.js | 4 ++++ src/display/api.js | 13 +++++++++++++ 5 files changed, 35 insertions(+) diff --git a/src/core/crypto.js b/src/core/crypto.js index cfff2b8db5df4..3c9119c4f7e6c 100644 --- a/src/core/crypto.js +++ b/src/core/crypto.js @@ -1183,6 +1183,16 @@ class CipherTransformFactory { } } + getEncryptionDictionary() { + const encryptionDict = {}; + ["V", "R", "O", "U", "OE", "UE", "P"] + .forEach((key) => { + const value = this.dict.get(key); + if (value != null) encryptionDict[key] = value; + }); + return encryptionDict; + } + createCipherTransform(num, gen) { if (this.algorithm === 4 || this.algorithm === 5) { return new CipherTransform( diff --git a/src/core/document.js b/src/core/document.js index 46a2626a3a814..1eb0de1d910ec 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -1067,6 +1067,10 @@ class PDFDocument { }; } + get encryptionDictionary() { + return shadow(this, "encryptionDictionary", this.xref.getEncryptionDictionary()); + } + parse(recoveryMode) { this.xref.parse(recoveryMode); this.catalog = new Catalog(this.pdfManager, this.xref); diff --git a/src/core/worker.js b/src/core/worker.js index 87fe7a8fb4d3b..c1cf76bfe2c65 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -518,6 +518,10 @@ class WorkerMessageHandler { ]); }); + handler.on("GetEncryptionDictionary", function (data) { + return pdfManager.ensureDoc("encryptionDictionary"); + }); + handler.on("GetMarkInfo", function (data) { return pdfManager.ensureCatalog("markInfo"); }); diff --git a/src/core/xref.js b/src/core/xref.js index c13c08a7d3bde..d8e6cfbb07c3c 100644 --- a/src/core/xref.js +++ b/src/core/xref.js @@ -163,6 +163,10 @@ class XRef { throw new InvalidPDFException("Invalid Root reference."); } + getEncryptionDictionary() { + return this.encrypt?.getEncryptionDictionary(); + } + processXRefTable(parser) { if (!("tableState" in this)) { // Stores state of the table as we process it so we can resume diff --git a/src/display/api.js b/src/display/api.js index 336472b47ba39..780606ff23257 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -992,6 +992,15 @@ class PDFDocumentProxy { return this._transport.getMetadata(); } + /** + * @returns {Promise} A promise that is resolved with + * a object that contains the encryption dictionary fields for the PDF + * document, or `null` when no encryption dictionary values are present in the PDF file. + */ + getEncryptionDictionary() { + return this._transport.getEncryptionDictionary(); + } + /** * @typedef {Object} MarkInfo * Properties correspond to Table 321 of the PDF 32000-1:2008 spec. @@ -3057,6 +3066,10 @@ class WorkerTransport { return promise; } + getEncryptionDictionary() { + return this.messageHandler.sendWithPromise("GetEncryptionDictionary", null); + } + getMarkInfo() { return this.messageHandler.sendWithPromise("GetMarkInfo", null); } From 9c20d9f1e3535262e06d3c047a796b5f4686d6fb Mon Sep 17 00:00:00 2001 From: Vladimir Date: Mon, 27 Apr 2026 10:37:41 +0300 Subject: [PATCH 2/2] Small fix --- src/core/document.js | 8 ++++---- src/core/worker.js | 9 +++------ src/display/api.js | 13 ------------- 3 files changed, 7 insertions(+), 23 deletions(-) diff --git a/src/core/document.js b/src/core/document.js index 1eb0de1d910ec..3f7616113239c 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -1067,10 +1067,6 @@ class PDFDocument { }; } - get encryptionDictionary() { - return shadow(this, "encryptionDictionary", this.xref.getEncryptionDictionary()); - } - parse(recoveryMode) { this.xref.parse(recoveryMode); this.catalog = new Catalog(this.pdfManager, this.xref); @@ -2135,6 +2131,10 @@ class ExtendedPDFDocument extends PDFDocument { get structureTree() { return shadow(this, "structureTree", this.catalog.structureTree); } + + get encryptionDictionary() { + return shadow(this, "encryptionDictionary", this.xref.getEncryptionDictionary()); + } } export { Page, ExtendedPDFDocument as PDFDocument }; diff --git a/src/core/worker.js b/src/core/worker.js index c1cf76bfe2c65..c5c45bf53ed42 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -177,10 +177,11 @@ class WorkerMessageHandler { finishWorkerTask(task); } - const [numPages, fingerprints, structureTree] = await Promise.all([ + const [numPages, fingerprints, structureTree, encryptionDictionary] = await Promise.all([ pdfManager.ensureDoc("numPages"), pdfManager.ensureDoc("fingerprints"), pdfManager.ensureDoc("structureTree"), + pdfManager.ensureDoc("encryptionDictionary"), ]); // Get htmlForXfa after numPages to avoid to create HTML twice. @@ -188,7 +189,7 @@ class WorkerMessageHandler { ? await pdfManager.ensureDoc("htmlForXfa") : null; - return { numPages, fingerprints, htmlForXfa, structureTree }; + return { numPages, fingerprints, htmlForXfa, structureTree, encryptionDictionary }; } async function getPdfManager({ @@ -518,10 +519,6 @@ class WorkerMessageHandler { ]); }); - handler.on("GetEncryptionDictionary", function (data) { - return pdfManager.ensureDoc("encryptionDictionary"); - }); - handler.on("GetMarkInfo", function (data) { return pdfManager.ensureCatalog("markInfo"); }); diff --git a/src/display/api.js b/src/display/api.js index 780606ff23257..336472b47ba39 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -992,15 +992,6 @@ class PDFDocumentProxy { return this._transport.getMetadata(); } - /** - * @returns {Promise} A promise that is resolved with - * a object that contains the encryption dictionary fields for the PDF - * document, or `null` when no encryption dictionary values are present in the PDF file. - */ - getEncryptionDictionary() { - return this._transport.getEncryptionDictionary(); - } - /** * @typedef {Object} MarkInfo * Properties correspond to Table 321 of the PDF 32000-1:2008 spec. @@ -3066,10 +3057,6 @@ class WorkerTransport { return promise; } - getEncryptionDictionary() { - return this.messageHandler.sendWithPromise("GetEncryptionDictionary", null); - } - getMarkInfo() { return this.messageHandler.sendWithPromise("GetMarkInfo", null); }