diff --git a/src/index.js b/src/index.js index 5556f03..8e468fb 100644 --- a/src/index.js +++ b/src/index.js @@ -185,7 +185,16 @@ const getBrowserType = name => { // todo: not need this const portRange = [ 10000, 60000 ]; const generatePort = () => (Math.floor(Math.random() * (portRange[1] - portRange[0] + 1)) + portRange[0]); -const startBrowser = async (url, { allowHTTP = false, allowRedirects = 'same-origin', windowSize, forceBrowser, forceEngine }) => { +// default CSP policy. tl;dr: allow everything if same-origin, and allow all mostly non-dangerous things for all domains (images, css, requests) +const csp_sameOnly = `'self' 'unsafe-inline'`; +const csp_allowAll = `https: data: blob: 'unsafe-inline'`; +const defaultCSP = [ 'upgrade-insecure-requests' ].concat( + [ 'default-src' ].map(x => `${x} ${csp_sameOnly}`) +).concat( + [ 'connect-src', 'prefetch-src', 'font-src', 'img-src', 'media-src', 'style-src', 'form-action' ].map(x => `${x} ${csp_allowAll}`) +).join('; '); + +const startBrowser = async (url, { allowHTTP = false, allowRedirects = 'same-origin', windowSize, forceBrowser, forceEngine, localCSP = defaultCSP }) => { const [ browserPath, browserName ] = await findBrowserPath(forceBrowser, forceEngine); const browserFriendlyName = getFriendlyName(browserName); @@ -202,7 +211,7 @@ const startBrowser = async (url, { allowHTTP = false, allowRedirects = 'same-ori const basePath = isAbsolute(url) ? url : join(ranJsDir, url); const closeHandlers = []; - if (openingLocal && browserType === 'firefox') closeHandlers.push(await LocalHTTP({ url: localUrl, basePath })); + if (openingLocal && browserType === 'firefox') closeHandlers.push(await LocalHTTP({ url: localUrl, basePath, csp: localCSP })); const Window = await (browserType === 'firefox' ? Firefox : Chromium)({ dataPath, @@ -220,7 +229,8 @@ const startBrowser = async (url, { allowHTTP = false, allowRedirects = 'same-ori closeHandlers, browserType, dataPath, - allowRedirects + allowRedirects, + localCSP }); return Window; diff --git a/src/launcher/inject.js b/src/launcher/inject.js index 0da2db8..e7a96b1 100644 --- a/src/launcher/inject.js +++ b/src/launcher/inject.js @@ -27,7 +27,7 @@ const acquireTarget = async (CDP, filter = () => true) => { })).sessionId; }; -export default async (CDP, proc, injectionType = 'browser', { dataPath, browserName, browserType, openingLocal, url, basePath, allowRedirects, closeHandlers }) => { +export default async (CDP, proc, injectionType = 'browser', { dataPath, browserName, browserType, openingLocal, url, basePath, allowRedirects, localCSP, closeHandlers }) => { let pageLoadCallback, pageLoadPromise = new Promise(res => pageLoadCallback = res); let frameLoadCallback = () => {}, onWindowMessage = () => {}; CDP.onMessage(async msg => { @@ -79,7 +79,7 @@ export default async (CDP, proc, injectionType = 'browser', { dataPath, browserN let sessionId; if (injectionType === 'browser') sessionId = await acquireTarget(CDP, target => target.url !== 'about:blank'); - if (openingLocal && browserType === 'chromium') await LocalCDP(CDP, { sessionId, url, basePath }); + if (openingLocal && browserType === 'chromium') await LocalCDP(CDP, { sessionId, url, basePath, csp: localCSP }); await CDP.sendMessage('Runtime.enable', {}, sessionId); // enable runtime API CDP.sendMessage('Page.enable', {}, sessionId); // enable page API diff --git a/src/lib/local/cdp.js b/src/lib/local/cdp.js index 2701cdc..f6458d1 100644 --- a/src/lib/local/cdp.js +++ b/src/lib/local/cdp.js @@ -1,8 +1,8 @@ import createLocalFulfill from './fulfill.js'; import { log } from '../logger.js'; -export default async (CDP, { sessionId, basePath, url }) => { - const localFulfill = createLocalFulfill(basePath); +export default async (CDP, { sessionId, basePath, url, csp }) => { + const localFulfill = createLocalFulfill(basePath, csp); CDP.onMessage(async msg => { if (msg.method === 'Fetch.requestPaused') { diff --git a/src/lib/local/fulfill.js b/src/lib/local/fulfill.js index 186ed7d..789a77e 100644 --- a/src/lib/local/fulfill.js +++ b/src/lib/local/fulfill.js @@ -10,7 +10,9 @@ const generatePath = (pathname, indexFile) => { return pathname; }; -export default givenPath => { +export default (givenPath, csp) => { + if (!csp) csp = undefined; + const basePath = extname(givenPath) ? dirname(givenPath) : givenPath; const indexFile = extname(basePath) ? basename(basePath) : 'index.html'; @@ -36,7 +38,8 @@ export default givenPath => { status: 200, body, headers: { - 'Content-Type': mimeType(ext) + 'Content-Type': mimeType(ext), + 'Content-Security-Policy': csp } }; }; diff --git a/src/lib/local/http.js b/src/lib/local/http.js index 23451c6..1883e41 100644 --- a/src/lib/local/http.js +++ b/src/lib/local/http.js @@ -2,8 +2,8 @@ import { createServer } from 'http'; import createLocalFulfill from './fulfill.js'; import { log } from '../logger.js'; -export default async ({ basePath, url }) => { - const localFulfill = createLocalFulfill(basePath); +export default async ({ basePath, url, csp }) => { + const localFulfill = createLocalFulfill(basePath, csp); const port = parseInt(url.split(':').pop()); const server = createServer(async (req, res) => {