52 lines
1.7 KiB
JavaScript
52 lines
1.7 KiB
JavaScript
// Bootstrap for the standalone PDF viewer page. Plays the role of app.js in
|
|
// viewer-phase1: it owns the #pdfMessage overlay and hands one URL to PdfViewer
|
|
// (from pdf_viewer.js, unchanged). Everything else — zoom, resize, retry — lives
|
|
// in PdfViewer already.
|
|
//
|
|
// URL contract: /viewer/index.html?file=<urlencoded /api/... path>
|
|
// Same-origin only: any file value that is not a root-relative /api/ path is
|
|
// refused before it ever reaches pdf.js.
|
|
|
|
const viewer = document.querySelector(".viewer");
|
|
const pdfContainer = document.querySelector("#pdfViewer");
|
|
const pdfMessage = document.querySelector("#pdfMessage");
|
|
|
|
function showMessage(text) {
|
|
viewer.classList.remove("loaded");
|
|
pdfMessage.textContent = text;
|
|
pdfMessage.hidden = false;
|
|
}
|
|
|
|
// Only root-relative /api/ paths. Rejects absolute URLs ("https://..."),
|
|
// protocol-relative ones ("//host/api/x") and anything outside /api/.
|
|
function safeFileUrl(raw) {
|
|
if (!raw) return null;
|
|
if (!raw.startsWith("/api/") || raw.startsWith("//")) return null;
|
|
// A backslash can be normalized to "/" by some URL parsers — reject outright.
|
|
if (raw.includes("\\")) return null;
|
|
return raw;
|
|
}
|
|
|
|
const params = new URLSearchParams(globalThis.location.search);
|
|
const file = safeFileUrl(params.get("file"));
|
|
|
|
if (!file) {
|
|
showMessage(
|
|
params.get("file")
|
|
? "Refused to load this document: only same-origin /api/ paths are allowed."
|
|
: "Select a document",
|
|
);
|
|
} else {
|
|
showMessage("Loading PDF…");
|
|
const pdfViewer = new PdfViewer(pdfContainer);
|
|
viewer.classList.add("loaded");
|
|
pdfMessage.hidden = true;
|
|
pdfViewer.load(file).catch((error) => {
|
|
showMessage(
|
|
`Cannot open PDF: ${
|
|
error instanceof Error ? error.message : String(error)
|
|
}`,
|
|
);
|
|
});
|
|
}
|