@@ -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