From 89840649d9fb79862e0b9d9d9971a2b4a4bf8a24 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Fri, 19 Aug 2022 17:35:49 +0200 Subject: [PATCH] Ensure that we don't try to re-open, or update the password-callback, when the password dialog is already open Currently in `disableWorker=true` mode it's possible that opening of password-protected PDF documents outright fails, if an *incorrect* password is entered. Apparently the event ordering is subtly different in the non-Worker case, which causes the password-callback to be updated *before* the dialog has been fully closed. To avoid that we'll utilize a `PromiseCapability` to keep track of the state of the password dialog, such that we can delay both re-opening and (importantly) updating of the password-callback until doing so is safe. This patch *may* also fix issue 15330, but it's impossible for me to tell. --- web/password_prompt.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/web/password_prompt.js b/web/password_prompt.js index 2207b1a9d..891e65fb1 100644 --- a/web/password_prompt.js +++ b/web/password_prompt.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { PasswordResponses } from "pdfjs-lib"; +import { createPromiseCapability, PasswordResponses } from "pdfjs-lib"; /** * @typedef {Object} PasswordPromptOptions @@ -28,6 +28,8 @@ import { PasswordResponses } from "pdfjs-lib"; */ class PasswordPrompt { + #activeCapability = null; + #updateCallback = null; #reason = null; @@ -64,7 +66,17 @@ class PasswordPrompt { } async open() { - await this.overlayManager.open(this.dialog); + if (this.#activeCapability) { + await this.#activeCapability.promise; + } + this.#activeCapability = createPromiseCapability(); + + try { + await this.overlayManager.open(this.dialog); + } catch (ex) { + this.#activeCapability = null; + throw ex; + } const passwordIncorrect = this.#reason === PasswordResponses.INCORRECT_PASSWORD; @@ -92,6 +104,7 @@ class PasswordPrompt { #cancel() { this.#invokeCallback(new Error("PasswordPrompt cancelled.")); + this.#activeCapability.resolve(); } #invokeCallback(password) { @@ -105,7 +118,10 @@ class PasswordPrompt { this.#updateCallback = null; } - setUpdateCallback(updateCallback, reason) { + async setUpdateCallback(updateCallback, reason) { + if (this.#activeCapability) { + await this.#activeCapability.promise; + } this.#updateCallback = updateCallback; this.#reason = reason; }