Skip to content

Commit

Permalink
fix #1701: improve circumvention of CSP in Firefox
Browse files Browse the repository at this point in the history
+ auto-switch to adoptedStyleSheets if failed
  • Loading branch information
tophf committed Nov 26, 2023
1 parent 26c2255 commit 5fdcc68
Showing 1 changed file with 26 additions and 15 deletions.
41 changes: 26 additions & 15 deletions content/style-injector.js
Expand Up @@ -33,6 +33,7 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
let isEnabled = true;
let isTransitionPatched = chrome.app && CSS.supports('accent-color', 'red'); // Chrome 93
let exposeStyleName;
let ffCsp;
let nonce = '';
// will store the original method refs because the page can override them
let creationDoc, createElement, createElementNS;
Expand Down Expand Up @@ -191,16 +192,18 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
if (iOld >= 0) ass[iOld].mediaText += '-old';
return el;
}
if (!creationDoc) initCreationDoc();
if (!creationDoc && (el = initCreationDoc(style))) {
return el;
}
if (root instanceof SVGSVGElement) {
// SVG document style
el = createElementNS.call(creationDoc, 'http://www.w3.org/2000/svg', 'style');
el = createElementNS('http://www.w3.org/2000/svg', 'style');
} else if (document instanceof XMLDocument) {
// XML document style
el = createElementNS.call(creationDoc, 'http://www.w3.org/1999/xhtml', 'style');
el = createElementNS('http://www.w3.org/1999/xhtml', 'style');
} else {
// HTML document style; also works on HTML-embedded SVG
el = createElement.call(creationDoc, 'style');
el = createElement('style');
}
if (id) {
el.id = `${PREFIX}${id}`;
Expand All @@ -224,7 +227,7 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
} */`);
}
// Firefox bug(?) circumvents CSP on AMO via textContent, same as Chrome's intentional behavior
if (!nonce && !isExt && !chrome.app && isSecureContext) {
if (ffCsp) {
el.textContent = code.join('');
return;
}
Expand Down Expand Up @@ -266,17 +269,24 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
and since userAgent.navigator can be spoofed via about:config or devtools,
we're checking for getPreventDefault that was removed in FF59
*/
function initCreationDoc() {
creationDoc = !Event.prototype.getPreventDefault && document.wrappedJSObject;
if (creationDoc) {
({createElement, createElementNS} = creationDoc);
const el = addElement(createStyle({code: ['']}));
const isApplied = el.sheet;
removeElement(el);
if (isApplied) return;
function initCreationDoc(style) {
creationDoc = Event.prototype.getPreventDefault ? document : wrappedDoc;
for (let retry = 0, el, ok; !ok && retry < 2; retry++) {
createElement = creationDoc.createElement.bind(creationDoc);
createElementNS = creationDoc.createElementNS.bind(creationDoc);
if (!retry || ffCsp) {
// In FF the first created style must be non-empty to circumvent CSP https://bugzil.la/1706787
el = addElement(createStyle({code: ['a:not(a){}']}));
ok = el.sheet;
removeElement(el);
}
if (!ok && retry && ffCsp) {
ass = wrappedAss;
console.debug('Stylus switched to document.adoptedStyleSheets due to a strict CSP of the page');
return createStyle(style);
}
creationDoc = document;
}
creationDoc = document;
({createElement, createElementNS} = creationDoc);
}

function remove(id) {
Expand Down Expand Up @@ -342,6 +352,7 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
function updateConfig(cfg) {
exposeStyleName = cfg.name;
nonce = cfg.nonce || nonce;
ffCsp = !nonce && !isExt && !chrome.app && isSecureContext;
if (!ass !== !cfg.ass) {
toggleObservers();
addRemoveElements();
Expand Down

0 comments on commit 5fdcc68

Please sign in to comment.