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) {