Skip to content
Snippets Groups Projects
Commit 2f2e9fd7 authored by Fred Chasen's avatar Fred Chasen
Browse files

Add request interception handler

parent 469393cb
No related branches found
No related tags found
No related merge requests found
......@@ -26,6 +26,9 @@ program
.option("-t, --timeout [ms]", "Set a max timeout of [ms]")
.option("-x, --html", "output html file")
.option("-b, --blockLocal", "Disallow access to filesystem for local files")
.option("-r, --blockRemote", "Disallow requests to remote servers")
.option("--allowedPath [allowedPaths]", "Only allow access to given filesystem paths, repeatable.", collect, [])
.option("--allowedDomain [allowedDomains]", "Only allow access to given remote domains, repeatable", collect, [])
.option("--outline-tags [tags]", "Specifies that an outline should be " +
"generated for the resulting PDF document. [tags] specifies which " +
"HTML tags should be considered for that outline. " +
......@@ -35,13 +38,13 @@ program
"added to the HTML document before rendering. This is useful for " +
"adding custom pagedjs handlers. The option can be repeated.",
collect, [])
.option("--browserEndpoint", "Use a remote Chrome server with browserWSEndpoint")
.parse(process.argv);
function collect(value, previous) {
return previous.concat(value);
}
let input = program.inputs || program.args[0];
let dir = process.cwd();
......@@ -49,7 +52,7 @@ let dir = process.cwd();
let relativePath;
let allowLocal;
try {
input = new URL(input);
let uri = new URL(input);
allowLocal = false;
} catch (error) {
relativePath = path.resolve(dir, input);
......@@ -104,7 +107,14 @@ if (typeof input === "string") {
}
(async () => {
let printer = new Printer(headless, allowLocal, program.additionalScript);
let printer = new Printer({
headless: headless,
allowLocal: allowLocal,
allowRemote: !program.blockRemote,
allowedPaths: program.allowedPaths,
allowedDomains: program.allowedDomains,
additionalScripts: program.additionalScript,
});
printer.on("page", (page) => {
if (page.position === 0) {
......
This diff is collapsed.
{
"name": "pagedjs-cli",
"version": "0.0.10",
"version": "0.1.0",
"author": "Fred Chasen",
"license": "MIT",
"homepage": "https://pagedmedia.org",
......@@ -16,20 +16,20 @@
},
"main": "index.js",
"dependencies": {
"commander": "^3.0.2",
"commander": "^5.0.0",
"express": "^4.17.1",
"hyphenopoly": "^3.2.1",
"hyphenopoly": "^4.2.1",
"katex": "^0.11.1",
"lodash": "^4.17.15",
"mathjax": "^3.0.0",
"mathjax": "^3.0.1",
"node-fetch": "^2.6.0",
"ora": "^4.0.2",
"pagedjs": "0.1.34",
"ora": "^4.0.3",
"pagedjs": "0.1.40",
"pdf-lib": "0.6.4",
"puppeteer": "^2.0.0",
"puppeteer": "^2.1.1",
"replace-ext": "^1.0.0"
},
"devDependencies": {
"eslint": "^6.5.1"
"eslint": "^6.8.0"
}
}
......@@ -14,20 +14,37 @@ let scriptPath = paths[0] + "node_modules" + paths[paths.length-1];
const PostProcesser = require("./postprocesser");
class Printer extends EventEmitter {
constructor(headless, allowLocal, additionalScripts) {
constructor(options = {}) {
super();
this.headless = headless !== false;
this.allowLocal = allowLocal;
this.headless = options.headless !== false;
this.allowLocal = options.allowLocal;
this.allowRemote = options.allowRemote;
this.additionalScripts = options.additionalScripts;
this.allowedPaths = options.allowedPaths || [];
this.allowedDomains = options.allowedDomains || [];
this.ignoreHTTPSErrors = options.ignoreHTTPSErrors;
this.browserWSEndpoint = options.browserEndpoint;
this.pages = [];
this.additionalScripts = additionalScripts;
}
async setup() {
const browser = await puppeteer.launch({
let puppeteerOptions = {
headless: this.headless,
args: this.allowLocal ? ["--allow-file-access-from-files", "--disable-dev-shm-usage"] : ["--disable-dev-shm-usage"],
ignoreHTTPSErrors: true
});
args: ["--disable-dev-shm-usage"],
ignoreHTTPSErrors: this.ignoreHTTPSErrors
}
if (this.allowLocal) {
puppeteerOptions.args.push("--allow-file-access-from-files");
}
if (this.browserWSEndpoint) {
puppeteerOptions.browserWSEndpoint = this.browserWSEndpoint;
}
const browser = await puppeteer.launch(puppeteerOptions);
this.browser = browser;
......@@ -46,17 +63,13 @@ class Printer extends EventEmitter {
const page = await this.browser.newPage();
let uri, url, html;
let uri, url, relativePath, html;
if (typeof input === "string") {
try {
uri = new URL(input);
if (uri.protocol === "https:") {
html = await fetch(input)
.then(res => res.text());
}
url = input;
} catch (error) {
let relativePath = path.resolve(dir, input);
relativePath = path.resolve(dir, input);
url = "file://" + relativePath;
}
} else {
......@@ -64,6 +77,36 @@ class Printer extends EventEmitter {
html = input.html;
}
await page.setRequestInterception(true);
page.on('request', (request) => {
let uri = new URL(request.url());
let { host, protocol, pathname } = uri;
let local = protocol === "file:"
if (local && this.withinAllowedPath(pathname) === false) {
request.abort();
return;
}
if (local && !this.allowLocal) {
request.abort();
return;
}
if (host && this.isAllowedDomain(host) === false) {
request.abort();
return;
}
if (host && !this.allowRemote) {
request.abort();
return;
}
request.continue();
});
if (html) {
await page.setContent(html)
.catch((e) => {
......@@ -299,6 +342,28 @@ class Printer extends EventEmitter {
return this.browser.close();
}
withinAllowedPath(pathname) {
if (!this.allowedPaths || this.allowedPaths.length === 0) {
return true;
}
for (let parent of this.allowedPaths) {
const relative = path.relative(parent, pathname);
if (relative && !relative.startsWith('..') && !path.isAbsolute(relative)) {
return true;
}
}
return false;
}
isAllowedDomain(domain) {
if (!this.allowedDomains || this.allowedDomains.length === 0) {
return true;
}
return this.allowedDomains.includes(domain);
}
}
module.exports = Printer;
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment