Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/publish_website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ on:
permissions:
contents: read

# Allow only one concurrent deployment, without cancelling in-progress runs, so
# that an in-flight Pages deployment is allowed to finish before the next starts.
concurrency:
group: "pages"
cancel-in-progress: false

jobs:
build:
name: Build
Expand Down
2 changes: 1 addition & 1 deletion src/core/core_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ function escapePDFName(str) {
if (start < i) {
buffer.push(str.substring(start, i));
}
buffer.push(`#${char.toString(16)}`);
buffer.push(`#${char.toString(16).padStart(2, "0")}`);
start = i + 1;
}
}
Expand Down
5 changes: 5 additions & 0 deletions test/unit/core_utils_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,11 @@ describe("core_utils", function () {
"#23#28#29#3c#3e#5b#5d#7b#7d#2f#25"
);
});

it("should escape control characters using two hexadecimal digits", function () {
expect(escapePDFName("\x00\x09\x0a\x1f")).toEqual("#00#09#0a#1f");
expect(escapePDFName("a\tb")).toEqual("a#09b");
});
});

describe("escapeString", function () {
Expand Down
4 changes: 2 additions & 2 deletions web/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -1207,7 +1207,7 @@ const PDFViewerApplication = {
this.pdfViewer.setDocument(null);
this.pdfLinkService.setDocument(null);
this.pdfDocumentProperties?.setDocument(null);
this.signaturePropertiesManager?.reset();
this.signaturePropertiesManager?.setDocument(null);
}
this.pdfLinkService.externalLinkEnabled = true;
this.store = null;
Expand Down Expand Up @@ -1905,7 +1905,7 @@ const PDFViewerApplication = {
verifier,
eventBus: this.eventBus,
});
this.signaturePropertiesManager.loadFromDocument(pdfDocument);
this.signaturePropertiesManager.setDocument(pdfDocument);
return true;
},

Expand Down
58 changes: 21 additions & 37 deletions web/digital_signature_properties_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ function bannerStateForResults(results) {
let worst = "verified";
for (const r of results) {
if (
r &&
r.status &&
r?.status &&
STATUS_INFO[r.status].priority > STATUS_INFO[worst].priority
) {
worst = r.status;
Expand Down Expand Up @@ -193,15 +192,6 @@ class SignaturePropertiesManager {
// is updated via #updateButtonState().
#needsRender = false;

// Identifies the current `loadFromDocument` call. Each load rotates the
// token; in-flight `#verify()` promises capture the value at start and
// bail on resolve if the manager has since switched to another document.
// Prevents a stale verification for doc A from writing into doc B's
// results map after a fast doc-switch.
#loadToken = null;

// Held only to ferry per-signature byte payloads from the worker into
// `#verify`. Cleared in `reset()` so we don't pin a closed document.
#pdfDocument = null;

constructor({ appConfig, verifier, eventBus }) {
Expand Down Expand Up @@ -258,10 +248,21 @@ class SignaturePropertiesManager {
);
}

async loadFromDocument(pdfDocument) {
const token = Symbol("sig-load");
this.#loadToken = token;
async setDocument(pdfDocument) {
if (this.#pdfDocument) {
this.#signatures = [];
this.#results.clear();
this.#pendingVerify.clear();
this.#needsRender = false;
this.#hideButton();
this.#close();
this.#updateButtonState();
}
this.#pdfDocument = pdfDocument;

if (!pdfDocument) {
return;
}
this.#signatures = [];
this.#results.clear();
this.#pendingVerify.clear();
Expand All @@ -275,8 +276,7 @@ class SignaturePropertiesManager {
console.warn("getSignatures failed:", ex);
signatures = [];
}
if (this.#loadToken !== token) {
// A newer document load (or reset) raced ahead — drop this result.
if (pdfDocument !== this.#pdfDocument) {
return;
}
this.#signatures = signatures || [];
Expand Down Expand Up @@ -305,26 +305,10 @@ class SignaturePropertiesManager {
// Kick off verification automatically — the toolbar button reflects the
// aggregate state and updates as each signature resolves.
for (const sig of this.#signatures) {
this.#verify(sig, token);
this.#verify(sig, pdfDocument);
}
}

reset() {
// Rotate the token so any in-flight verify from the previous document
// sees a mismatch and bails before mutating state.
this.#loadToken = null;
this.#pdfDocument = null;
this.#signatures = [];
this.#results.clear();
this.#pendingVerify.clear();
this.#needsRender = false;
this.#hideButton();
this.#close();
this.#updateButtonState();
}

// --- internal ---

#showButton() {
const root = this.#appConfig.signaturePropertiesButton.parentElement;
if (root) {
Expand Down Expand Up @@ -635,7 +619,7 @@ class SignaturePropertiesManager {
return total;
}

async #verify(signature, loadToken) {
async #verify(signature, pdfDocument) {
if (!this.#verifier || this.#pendingVerify.has(signature.id)) {
return;
}
Expand All @@ -648,8 +632,8 @@ class SignaturePropertiesManager {
// lazily, one signature at a time, so the bytes never sit in main
// thread memory for the document's lifetime. `bytes` goes out of
// scope as soon as the verifier returns.
const bytes = await this.#pdfDocument?.getSignatureData(signature.id);
if (this.#loadToken !== loadToken) {
const bytes = await pdfDocument.getSignatureData(signature.id);
if (pdfDocument !== this.#pdfDocument) {
return;
}
if (!bytes) {
Expand All @@ -667,7 +651,7 @@ class SignaturePropertiesManager {
};
}
this.#pendingVerify.delete(signature.id);
if (this.#loadToken !== loadToken) {
if (pdfDocument !== this.#pdfDocument) {
// The user switched documents while this verify was in flight; the
// result belongs to a defunct load and would corrupt the new doc.
return;
Expand Down
Loading