mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-05-31 07:11:00 +02:00
Add a Content-Security-Policy to pdf.js' viewer.html (bug 1960363)
This commit is contained in:
parent
bf9ae7622f
commit
94de952b65
@ -1209,6 +1209,10 @@ function discardCommentsCSS() {
|
||||
}
|
||||
|
||||
function preprocessHTML(source, defines) {
|
||||
defines = {
|
||||
...defines,
|
||||
TESTING: defines.TESTING ?? process.env.TESTING === "true",
|
||||
};
|
||||
const outName = getTempFile("~preprocess", ".html");
|
||||
preprocess(source, outName, defines);
|
||||
const out = fs.readFileSync(outName).toString();
|
||||
|
||||
@ -26,8 +26,11 @@ import {
|
||||
waitForPageChanging,
|
||||
waitForPageRendered,
|
||||
} from "./test_utils.mjs";
|
||||
import path from "path";
|
||||
import { PNG } from "pngjs";
|
||||
|
||||
const __dirname = import.meta.dirname;
|
||||
|
||||
describe("PDF viewer", () => {
|
||||
describe("Zoom origin", () => {
|
||||
let pages;
|
||||
@ -1892,5 +1895,108 @@ describe("PDF viewer", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("@page size stylesheet under CSP", () => {
|
||||
let pages;
|
||||
|
||||
beforeEach(async () => {
|
||||
pages = await loadAndWait(
|
||||
"basicapi.pdf",
|
||||
".textLayer .endOfContent",
|
||||
null,
|
||||
{
|
||||
earlySetup: () => {
|
||||
// Capture state while window.print() runs — the print service's
|
||||
// destroy() removes the @page stylesheet right after, on the
|
||||
// afterprint event.
|
||||
window._pageRuleApplied = null;
|
||||
window.print = () => {
|
||||
window._pageRuleApplied = [
|
||||
...document.querySelectorAll("style"),
|
||||
].some(
|
||||
s =>
|
||||
s.sheet?.cssRules.length > 0 &&
|
||||
[...s.sheet.cssRules].some(r => r.cssText.includes("@page"))
|
||||
);
|
||||
};
|
||||
},
|
||||
appSetup: app => {
|
||||
app._testPrintResolver = Promise.withResolvers();
|
||||
},
|
||||
eventBusSetup: eventBus => {
|
||||
eventBus.on(
|
||||
"afterprint",
|
||||
() => {
|
||||
window.PDFViewerApplication._testPrintResolver.resolve();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await closePages(pages);
|
||||
});
|
||||
|
||||
// The print service injects an inline
|
||||
// <style>@page { size: WxH pt }</style> to match the PDF's page
|
||||
// dimensions. If the CSP `style-src-elem` directive blocks inline
|
||||
// <style> elements, the element is created but its content is never
|
||||
// parsed — `sheet.cssRules` stays empty and the @page rule has no
|
||||
// effect. See web/viewer.html.
|
||||
it("must apply the injected @page rule (no CSP block)", async () => {
|
||||
await Promise.all(
|
||||
pages.map(async ([browserName, page]) => {
|
||||
await waitAndClick(page, "#printButton");
|
||||
await awaitPromise(
|
||||
await page.evaluateHandle(() => [
|
||||
window.PDFViewerApplication._testPrintResolver.promise,
|
||||
])
|
||||
);
|
||||
|
||||
const hasPageRule = await page.evaluate(
|
||||
() => window._pageRuleApplied
|
||||
);
|
||||
expect(hasPageRule)
|
||||
.withContext(
|
||||
`In ${browserName}: injected @page stylesheet was parsed`
|
||||
)
|
||||
.toBeTrue();
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Open a new PDF via the file input", () => {
|
||||
let pages;
|
||||
|
||||
beforeEach(async () => {
|
||||
pages = await loadAndWait("tracemonkey.pdf", ".textLayer .endOfContent");
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await closePages(pages);
|
||||
});
|
||||
|
||||
// The "Open" input wraps the chosen file in a blob URL,
|
||||
// which the worker then fetches. `connect-src` in the production CSP must
|
||||
// therefore allow `blob:` — see web/viewer.html.
|
||||
it("must load a PDF picked through the file input (blob URL)", async () => {
|
||||
await Promise.all(
|
||||
pages.map(async ([browserName, page]) => {
|
||||
const fileInput = await page.$("#fileInput");
|
||||
await fileInput.uploadFile(
|
||||
path.join(__dirname, "../pdfs/basicapi.pdf")
|
||||
);
|
||||
|
||||
await page.waitForFunction(
|
||||
() => window.PDFViewerApplication.pdfDocument?.numPages === 3
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -26,6 +26,20 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
<title>PDF.js viewer</title>
|
||||
|
||||
<!--
|
||||
The print service injects an inline <style>@page { size: … }</style>
|
||||
at print time (web/pdf_print_service.js, web/firefox_print_service.js)
|
||||
to match the PDF's page dimensions. Since the size varies per PDF the
|
||||
content can't be pre-hashed, so style-src-elem allows 'unsafe-inline'.
|
||||
Inline style="…" attributes stay blocked via style-src (no fallback).
|
||||
-->
|
||||
<!--#if MOZCENTRAL-->
|
||||
<!--<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'none'; script-src resource: 'wasm-unsafe-eval'; worker-src resource:; style-src resource:; style-src-elem resource: 'unsafe-inline'; img-src resource: blob: data:; font-src resource:; connect-src resource:; base-uri 'none'; form-action 'none';"
|
||||
/>-->
|
||||
<!--#endif-->
|
||||
|
||||
<!--#if MOZCENTRAL-->
|
||||
<!--#include viewer-snippet-firefox-extension.html-->
|
||||
<!--#endif-->
|
||||
|
||||
@ -4,19 +4,7 @@
|
||||
users with recognizing which checkbox they have to click when they
|
||||
visit chrome://extensions.
|
||||
-->
|
||||
<p
|
||||
id="chrome-pdfjs-logo-bg"
|
||||
style="
|
||||
display: block;
|
||||
padding-left: 60px;
|
||||
min-height: 48px;
|
||||
background-size: 48px;
|
||||
background-repeat: no-repeat;
|
||||
font-size: 14px;
|
||||
line-height: 1.8em;
|
||||
word-break: break-all;
|
||||
"
|
||||
>
|
||||
<p id="chrome-pdfjs-logo-bg">
|
||||
Click on "<span id="chrome-file-access-label">Allow access to file URLs</span>" at
|
||||
<a id="chrome-link-to-extensions-page">chrome://extensions</a>
|
||||
<br />
|
||||
|
||||
@ -713,6 +713,25 @@ dialog :link {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/*#if !MOZCENTRAL*/
|
||||
#printServiceDialog {
|
||||
min-width: 200px;
|
||||
}
|
||||
/*#endif*/
|
||||
|
||||
/*#if CHROME*/
|
||||
#chrome-pdfjs-logo-bg {
|
||||
display: block;
|
||||
padding-left: 60px;
|
||||
min-height: 48px;
|
||||
background-size: 48px;
|
||||
background-repeat: no-repeat;
|
||||
font-size: 14px;
|
||||
line-height: 1.8em;
|
||||
word-break: break-all;
|
||||
}
|
||||
/*#endif*/
|
||||
|
||||
.grab-to-pan-grab {
|
||||
cursor: grab !important;
|
||||
}
|
||||
|
||||
@ -29,6 +29,35 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||
<!--#endif-->
|
||||
<title>PDF.js viewer</title>
|
||||
|
||||
<!--
|
||||
The print service injects an inline <style>@page { size: … }</style>
|
||||
at print time (web/pdf_print_service.js, web/firefox_print_service.js)
|
||||
to match the PDF's page dimensions. Since the size varies per PDF the
|
||||
content can't be pre-hashed, so style-src-elem allows 'unsafe-inline'.
|
||||
Inline style="…" attributes stay blocked via style-src (no fallback).
|
||||
-->
|
||||
<!--#if MOZCENTRAL-->
|
||||
<!--<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'none'; script-src resource: 'wasm-unsafe-eval'; worker-src resource:; style-src resource:; style-src-elem resource: 'unsafe-inline'; img-src resource: blob: data:; font-src resource:; connect-src resource:; base-uri 'none'; form-action 'none';"
|
||||
/>-->
|
||||
<!--#elif TESTING-->
|
||||
<!--<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'none'; script-src 'self' 'wasm-unsafe-eval' 'unsafe-eval'; worker-src 'self' blob:; style-src 'self'; style-src-elem 'self' 'unsafe-inline'; img-src 'self' blob: data:; font-src 'self' data:; connect-src * blob: data:; base-uri 'self'; form-action 'none';"
|
||||
/>-->
|
||||
<!--#elif CHROME-->
|
||||
<!--<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self' blob:; style-src 'self'; style-src-elem 'self' 'unsafe-inline'; img-src 'self' blob: data:; font-src 'self' data:; connect-src * blob: data:; base-uri 'self'; form-action 'none';"
|
||||
/>-->
|
||||
<!--#else-->
|
||||
<!--<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self' blob:; style-src 'self'; style-src-elem 'self' 'unsafe-inline'; img-src 'self' blob: data:; font-src 'self' data:; connect-src * blob: data:; base-uri 'none'; form-action 'none';"
|
||||
/>-->
|
||||
<!--#endif-->
|
||||
|
||||
<!--#if MOZCENTRAL-->
|
||||
<!--#include viewer-snippet-firefox-extension.html-->
|
||||
<!--#elif CHROME-->
|
||||
@ -1237,7 +1266,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||
</dialog>
|
||||
|
||||
<!--#if !MOZCENTRAL-->
|
||||
<dialog id="printServiceDialog" style="min-width: 200px">
|
||||
<dialog id="printServiceDialog">
|
||||
<div class="row">
|
||||
<span data-l10n-id="pdfjs-print-progress-message"></span>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user