diff --git a/src/display/api.js b/src/display/api.js index 415ca9e2d..5c48b6a8e 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -2644,9 +2644,11 @@ class WorkerTransport { if (loadingTask.onPassword) { const updatePassword = password => { - this._passwordCapability.resolve({ - password, - }); + if (password instanceof Error) { + this._passwordCapability.reject(password); + } else { + this._passwordCapability.resolve({ password }); + } }; try { loadingTask.onPassword(updatePassword, exception.code); diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 24ca5fea3..fc56ae9a2 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -239,7 +239,7 @@ describe("api", function () { const passwordNeededCapability = createPromiseCapability(); const passwordIncorrectCapability = createPromiseCapability(); // Attach the callback that is used to request a password; - // similarly to how viewer.js handles passwords. + // similarly to how the default viewer handles passwords. loadingTask.onPassword = function (updatePassword, reason) { if ( reason === PasswordResponses.NEED_PASSWORD && @@ -405,6 +405,38 @@ describe("api", function () { } ); + it( + "creates pdf doc from password protected PDF file and passes an Error " + + "(asynchronously) to the onPassword callback (bug 1754421)", + async function () { + const loadingTask = getDocument( + buildGetDocumentParams("issue3371.pdf") + ); + expect(loadingTask instanceof PDFDocumentLoadingTask).toEqual(true); + + // Attach the callback that is used to request a password; + // similarly to how the default viewer handles passwords. + loadingTask.onPassword = function (updatePassword, reason) { + waitSome(() => { + updatePassword(new Error("Should reject the loadingTask.")); + }); + }; + + await loadingTask.promise.then( + function () { + // Shouldn't get here. + expect(false).toEqual(true); + }, + function (reason) { + expect(reason instanceof PasswordException).toEqual(true); + expect(reason.code).toEqual(PasswordResponses.NEED_PASSWORD); + } + ); + + await loadingTask.destroy(); + } + ); + it("creates pdf doc from empty typed array", async function () { const loadingTask = getDocument(new Uint8Array(0)); expect(loadingTask instanceof PDFDocumentLoadingTask).toEqual(true); diff --git a/web/password_prompt.js b/web/password_prompt.js index 583a13a68..442cdb809 100644 --- a/web/password_prompt.js +++ b/web/password_prompt.js @@ -51,18 +51,18 @@ class PasswordPrompt { this.reason = null; // Attach the event listeners. - this.submitButton.addEventListener("click", this.verify.bind(this)); - this.cancelButton.addEventListener("click", this.close.bind(this)); + this.submitButton.addEventListener("click", this.#verify.bind(this)); + this.cancelButton.addEventListener("click", this.#cancel.bind(this)); this.input.addEventListener("keydown", e => { if (e.keyCode === /* Enter = */ 13) { - this.verify(); + this.#verify(); } }); this.overlayManager.register( this.overlayName, this.container, - this.close.bind(this), + this.#cancel.bind(this), true ); } @@ -87,7 +87,7 @@ class PasswordPrompt { }); } - verify() { + #verify() { const password = this.input.value; if (password?.length > 0) { this.close(); @@ -95,6 +95,11 @@ class PasswordPrompt { } } + #cancel() { + this.close(); + this.updateCallback(new Error("PasswordPrompt cancelled.")); + } + setUpdateCallback(updateCallback, reason) { this.updateCallback = updateCallback; this.reason = reason;