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) {
|
function preprocessHTML(source, defines) {
|
||||||
|
defines = {
|
||||||
|
...defines,
|
||||||
|
TESTING: defines.TESTING ?? process.env.TESTING === "true",
|
||||||
|
};
|
||||||
const outName = getTempFile("~preprocess", ".html");
|
const outName = getTempFile("~preprocess", ".html");
|
||||||
preprocess(source, outName, defines);
|
preprocess(source, outName, defines);
|
||||||
const out = fs.readFileSync(outName).toString();
|
const out = fs.readFileSync(outName).toString();
|
||||||
|
|||||||
@ -26,8 +26,11 @@ import {
|
|||||||
waitForPageChanging,
|
waitForPageChanging,
|
||||||
waitForPageRendered,
|
waitForPageRendered,
|
||||||
} from "./test_utils.mjs";
|
} from "./test_utils.mjs";
|
||||||
|
import path from "path";
|
||||||
import { PNG } from "pngjs";
|
import { PNG } from "pngjs";
|
||||||
|
|
||||||
|
const __dirname = import.meta.dirname;
|
||||||
|
|
||||||
describe("PDF viewer", () => {
|
describe("PDF viewer", () => {
|
||||||
describe("Zoom origin", () => {
|
describe("Zoom origin", () => {
|
||||||
let pages;
|
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" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||||
<title>PDF.js viewer</title>
|
<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-->
|
<!--#if MOZCENTRAL-->
|
||||||
<!--#include viewer-snippet-firefox-extension.html-->
|
<!--#include viewer-snippet-firefox-extension.html-->
|
||||||
<!--#endif-->
|
<!--#endif-->
|
||||||
|
|||||||
@ -4,19 +4,7 @@
|
|||||||
users with recognizing which checkbox they have to click when they
|
users with recognizing which checkbox they have to click when they
|
||||||
visit chrome://extensions.
|
visit chrome://extensions.
|
||||||
-->
|
-->
|
||||||
<p
|
<p id="chrome-pdfjs-logo-bg">
|
||||||
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;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
Click on "<span id="chrome-file-access-label">Allow access to file URLs</span>" at
|
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>
|
<a id="chrome-link-to-extensions-page">chrome://extensions</a>
|
||||||
<br />
|
<br />
|
||||||
|
|||||||
@ -713,6 +713,25 @@ dialog :link {
|
|||||||
margin-top: 10px;
|
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 {
|
.grab-to-pan-grab {
|
||||||
cursor: grab !important;
|
cursor: grab !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,35 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||||||
<!--#endif-->
|
<!--#endif-->
|
||||||
<title>PDF.js viewer</title>
|
<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-->
|
<!--#if MOZCENTRAL-->
|
||||||
<!--#include viewer-snippet-firefox-extension.html-->
|
<!--#include viewer-snippet-firefox-extension.html-->
|
||||||
<!--#elif CHROME-->
|
<!--#elif CHROME-->
|
||||||
@ -1237,7 +1266,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
<!--#if !MOZCENTRAL-->
|
<!--#if !MOZCENTRAL-->
|
||||||
<dialog id="printServiceDialog" style="min-width: 200px">
|
<dialog id="printServiceDialog">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span data-l10n-id="pdfjs-print-progress-message"></span>
|
<span data-l10n-id="pdfjs-print-progress-message"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user