Skip to content

Commit 7963a3a

Browse files
committed
improve circumvention of CSP in Firefox
+ auto-switch to adoptedStyleSheets if failed
1 parent 26c2255 commit 7963a3a

File tree

1 file changed

+29
-16
lines changed

1 file changed

+29
-16
lines changed

content/style-injector.js

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
3333
let isEnabled = true;
3434
let isTransitionPatched = chrome.app && CSS.supports('accent-color', 'red'); // Chrome 93
3535
let exposeStyleName;
36+
let ffCsp; // circumventing CSP via a non-empty textContent, https://bugzil.la/1706787
3637
let nonce = '';
3738
// will store the original method refs because the page can override them
3839
let creationDoc, createElement, createElementNS;
@@ -191,16 +192,18 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
191192
if (iOld >= 0) ass[iOld].mediaText += '-old';
192193
return el;
193194
}
194-
if (!creationDoc) initCreationDoc();
195+
if (!creationDoc && (el = initCreationDoc(style))) {
196+
return el;
197+
}
195198
if (root instanceof SVGSVGElement) {
196199
// SVG document style
197-
el = createElementNS.call(creationDoc, 'http://www.w3.org/2000/svg', 'style');
200+
el = createElementNS('http://www.w3.org/2000/svg', 'style');
198201
} else if (document instanceof XMLDocument) {
199202
// XML document style
200-
el = createElementNS.call(creationDoc, 'http://www.w3.org/1999/xhtml', 'style');
203+
el = createElementNS('http://www.w3.org/1999/xhtml', 'style');
201204
} else {
202205
// HTML document style; also works on HTML-embedded SVG
203-
el = createElement.call(creationDoc, 'style');
206+
el = createElement('style');
204207
}
205208
if (id) {
206209
el.id = `${PREFIX}${id}`;
@@ -223,8 +226,7 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
223226
window !== top ? '#' + Math.random().toString(36).slice(2) : '' // https://crbug.com/1298600
224227
} */`);
225228
}
226-
// Firefox bug(?) circumvents CSP on AMO via textContent, same as Chrome's intentional behavior
227-
if (!nonce && !isExt && !chrome.app && isSecureContext) {
229+
if (ffCsp) {
228230
el.textContent = code.join('');
229231
return;
230232
}
@@ -266,17 +268,27 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
266268
and since userAgent.navigator can be spoofed via about:config or devtools,
267269
we're checking for getPreventDefault that was removed in FF59
268270
*/
269-
function initCreationDoc() {
270-
creationDoc = !Event.prototype.getPreventDefault && document.wrappedJSObject;
271-
if (creationDoc) {
272-
({createElement, createElementNS} = creationDoc);
273-
const el = addElement(createStyle({code: ['']}));
274-
const isApplied = el.sheet;
275-
removeElement(el);
276-
if (isApplied) return;
271+
function initCreationDoc(style) {
272+
creationDoc = Event.prototype.getPreventDefault ? document : wrappedDoc;
273+
for (let retry = 0, el, ok; !ok && retry < 2; retry++) {
274+
createElement = creationDoc.createElement.bind(creationDoc);
275+
createElementNS = creationDoc.createElementNS.bind(creationDoc);
276+
if (chrome.app) return;
277+
if (!retry || ffCsp) {
278+
try {
279+
el = addElement(createStyle({code: ['a:not(a){}']}));
280+
ok = el.sheet;
281+
removeElement(el);
282+
if (ok) return;
283+
} catch (err) {}
284+
}
285+
if (retry && ffCsp) { // ffCsp bug got fixed
286+
console.debug('Stylus switched to document.adoptedStyleSheets due to a strict CSP of the page');
287+
ass = wrappedAss;
288+
return createStyle(style);
289+
}
290+
creationDoc = document;
277291
}
278-
creationDoc = document;
279-
({createElement, createElementNS} = creationDoc);
280292
}
281293

282294
function remove(id) {
@@ -342,6 +354,7 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
342354
function updateConfig(cfg) {
343355
exposeStyleName = cfg.name;
344356
nonce = cfg.nonce || nonce;
357+
ffCsp = !nonce && !isExt && !chrome.app && isSecureContext;
345358
if (!ass !== !cfg.ass) {
346359
toggleObservers();
347360
addRemoveElements();

0 commit comments

Comments
 (0)