Disable printing when enablePermission is true and the pdf isn't allowed to be printed (bug 1978985)

This commit is contained in:
Calixte Denizet 2025-07-28 17:42:13 +02:00
parent f16e0b6daa
commit 806f9c1cee
6 changed files with 117 additions and 5 deletions

View File

@ -1302,4 +1302,57 @@ describe("PDF viewer", () => {
);
});
});
describe("Printing can be disallowed for some pdfs (bug 1978985)", () => {
let pages;
beforeEach(async () => {
pages = await loadAndWait(
"print_protection.pdf",
"#passwordDialog",
null,
null,
{ enablePermissions: true }
);
});
afterEach(async () => {
await closePages(pages);
});
it("must check that printing is disallowed", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await page.waitForSelector("#printButton", {
visible: true,
});
const selector = "#passwordDialog input#password";
await page.waitForSelector(selector, { visible: true });
await page.type(selector, "1234");
await page.click("#passwordDialog button#passwordSubmit");
await page.waitForSelector(".textLayer .endOfContent");
// The print button should be hidden.
await page.waitForSelector("#printButton", {
hidden: true,
});
await page.waitForSelector("#secondaryPrint", {
hidden: true,
});
const hasThrown = await page.evaluate(() => {
try {
window.print();
} catch {
return true;
}
return false;
});
expect(hasThrown).withContext(`In ${browserName}`).toBeTrue();
})
);
});
});
});

View File

@ -738,3 +738,4 @@
!bug1978317.pdf
!dates.pdf
!dates_save.pdf
!print_protection.pdf

BIN
test/pdfs/print_protection.pdf Executable file

Binary file not shown.

View File

@ -190,6 +190,7 @@ const PDFViewerApplication = {
_caretBrowsing: null,
_isScrolling: false,
editorUndoBar: null,
_printPermissionPromise: null,
// Called once when the document is loaded.
async initialize(appConfig) {
@ -369,6 +370,7 @@ const PDFViewerApplication = {
enableAutoLinking: x => x === "true",
enableFakeMLManager: x => x === "true",
enableGuessAltText: x => x === "true",
enablePermissions: x => x === "true",
enableUpdatedAddImage: x => x === "true",
highlightEditorColors: x => x,
maxCanvasPixels: x => parseInt(x),
@ -407,6 +409,7 @@ const PDFViewerApplication = {
)
: new EventBus();
this.eventBus = AppOptions.eventBus = eventBus;
mlManager?.setEventBus(eventBus, abortSignal);
const overlayManager = (this.overlayManager = new OverlayManager());
@ -798,9 +801,19 @@ const PDFViewerApplication = {
});
}
const togglePrintingButtons = visible => {
appConfig.toolbar?.print?.classList.toggle("hidden", !visible);
appConfig.secondaryToolbar?.printButton.classList.toggle(
"hidden",
!visible
);
};
if (!this.supportsPrinting) {
appConfig.toolbar?.print?.classList.add("hidden");
appConfig.secondaryToolbar?.printButton.classList.add("hidden");
togglePrintingButtons(false);
} else {
eventBus.on("printingallowed", ({ isAllowed }) =>
togglePrintingButtons(isAllowed)
);
}
if (!this.supportsFullscreen) {
@ -1335,6 +1348,25 @@ const PDFViewerApplication = {
load(pdfDocument) {
this.pdfDocument = pdfDocument;
this._printPermissionPromise = new Promise(resolve => {
this.eventBus.on(
"printingallowed",
({ isAllowed }) => {
if (
typeof PDFJSDev !== "undefined" &&
PDFJSDev.test("MOZCENTRAL") &&
!isAllowed
) {
window.print = () => {
console.warn("Printing is not allowed.");
};
}
resolve(isAllowed);
},
{ once: true }
);
});
pdfDocument.getDownloadInfo().then(({ length }) => {
this._contentLength = length; // Ensure that the correct length is used.
this.loadingBar?.hide();
@ -1893,7 +1925,7 @@ const PDFViewerApplication = {
return;
}
if (!this.supportsPrinting) {
if (!this.supportsPrinting || !this.pdfViewer.printingAllowed) {
this._otherError("pdfjs-printing-not-supported");
return;
}
@ -1961,8 +1993,8 @@ const PDFViewerApplication = {
this.pdfPresentationMode?.request();
},
triggerPrinting() {
if (this.supportsPrinting) {
async triggerPrinting() {
if (this.supportsPrinting && (await this._printPermissionPromise)) {
window.print();
}
},

View File

@ -256,6 +256,10 @@ window.print = function () {
dispatchEvent("beforeprint");
} finally {
if (!activeService) {
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
// eslint-disable-next-line no-unsafe-finally
throw new Error("window.print() is not supported");
}
console.error("Expected print service to be initialized.");
ensureOverlay().then(function () {
overlayManager.closeIfActive(dialog);

View File

@ -254,6 +254,8 @@ class PDFViewer {
#mlManager = null;
#printingAllowed = true;
#scrollTimeoutId = null;
#switchAnnotationEditorModeAC = null;
@ -415,6 +417,10 @@ class PDFViewer {
}
}
get printingAllowed() {
return this.#printingAllowed;
}
get pagesCount() {
return this._pages.length;
}
@ -672,9 +678,23 @@ class PDFViewer {
textLayerMode: this.#textLayerMode,
};
if (!permissions) {
this.#printingAllowed = true;
this.eventBus.dispatch("printingallowed", {
source: this,
isAllowed: this.#printingAllowed,
});
return params;
}
this.#printingAllowed =
permissions.includes(PermissionFlag.PRINT_HIGH_QUALITY) ||
permissions.includes(PermissionFlag.PRINT);
this.eventBus.dispatch("printingallowed", {
source: this,
isAllowed: this.#printingAllowed,
});
if (
!permissions.includes(PermissionFlag.COPY) &&
this.#textLayerMode === TextLayerMode.ENABLE
@ -843,6 +863,8 @@ class PDFViewer {
this.#annotationEditorUIManager?.destroy();
this.#annotationEditorUIManager = null;
this.#printingAllowed = true;
}
this.pdfDocument = pdfDocument;