From 88146c4a961c3edcdf2752fe37f3ed56064d2011 Mon Sep 17 00:00:00 2001 From: tophf Date: Mon, 16 Nov 2020 10:02:19 +0300 Subject: [PATCH] move sandbox patch into PatchCSP option --- _locales/en/messages.json | 2 +- background/style-via-webrequest.js | 47 +++++++++++++++++------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 840f4efe..2c75dee1 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -980,7 +980,7 @@ "message": "Patch CSP to allow style assets" }, "optionsAdvancedPatchCspNote": { - "message": "Enable this if some of your styles fail to show an image/background/font on sites with a strict Content-Security-Policy.\n\nEnabling this will loosen CSP a bit by merging it with img-src data: *; font-src data: *; style-src 'unsafe-inline' which means you should accept the potential risk and/or regularly check the CSS code of your styles. Read about CSS-based attacks for more information.\n\nNote, this is not guaranteed to take effect if another installed extension modifies the network response first." + "message": "Enable this if some of your styles fail to show an image/background/font on sites with a strict Content-Security-Policy.\n\nEnabling this will loosen CSP a bit (only on sites where a userstyle is applied) by merging it with img-src data: *; font-src data: *; style-src 'unsafe-inline' (and allow-same-origin for sandbox if it's specified) which means you should accept the potential risk and/or regularly check the CSS code of your styles. Read about CSS-based attacks for more information.\n\nNote, this is not guaranteed to take effect if another installed extension modifies the network response first." }, "optionsAdvancedStyleViaXhr": { "message": "Instant inject mode" diff --git a/background/style-via-webrequest.js b/background/style-via-webrequest.js index c63460fb..86ead33c 100644 --- a/background/style-via-webrequest.js +++ b/background/style-via-webrequest.js @@ -80,42 +80,47 @@ CHROME && (async () => { /** @param {chrome.webRequest.WebResponseHeadersDetails} req */ function modifyHeaders(req) { const {responseHeaders} = req; - const csp = responseHeaders.find(h => h.name.toLowerCase() === 'content-security-policy'); const id = stylesToPass[req.requestId]; if (!id) { return; } - let res; if (enabled.xhr) { - res = true; responseHeaders.push({ name: 'Set-Cookie', value: `${chrome.runtime.id}=${id}`, }); - // Allow cookies in CSP sandbox (known case: raw github urls) - if (csp) { - csp.value = csp.value.replace(/(?:^|;)\s*sandbox(\s+[^;]*|)(?=;|$)/, (s, allow) => - allow.split(/\s+/).includes('allow-same-origin') ? s : `${s} allow-same-origin`); - } } - if (enabled.csp && csp) { - res = true; - const src = {}; - for (let p of csp.value.split(';')) { - p = p.trim().split(/\s+/); - src[p[0]] = p.slice(1); - } - addToCsp(src, 'img-src', 'data:', '*'); - addToCsp(src, 'font-src', 'data:', '*'); - addToCsp(src, 'style-src', "'unsafe-inline'"); - csp.value = Object.entries(src).map(([k, v]) => `${k} ${v.join(' ')}`).join('; '); + const csp = enabled.csp && + responseHeaders.find(h => h.name.toLowerCase() === 'content-security-policy'); + if (csp) { + patchCsp(csp); } - if (res) { + if (enabled.xhr || csp) { return {responseHeaders}; } } - function addToCsp(src, name, ...values) { + /** @param {chrome.webRequest.HttpHeader} csp */ + function patchCsp(csp) { + const src = {}; + for (let p of csp.value.split(';')) { + p = p.trim().split(/\s+/); + src[p[0]] = p.slice(1); + } + // Allow style assets + patchCspSrc(src, 'img-src', 'data:', '*'); + patchCspSrc(src, 'font-src', 'data:', '*'); + // Allow our DOM styles + patchCspSrc(src, 'style-src', '\'unsafe-inline\''); + // Allow our XHR cookies in CSP sandbox (known case: raw github urls) + if (src.sandbox && !src.sandbox.includes('allow-same-origin')) { + src.sandbox.push('allow-same-origin'); + } + csp.value = Object.entries(src).map(([k, v]) => + `${k}${v.length ? ' ' : ''}${v.join(' ')}`).join('; '); + } + + function patchCspSrc(src, name, ...values) { let def = src['default-src']; let list = src[name]; if (def || list) {