Skip to content

Commit

Permalink
Account for extensions setting the globals
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanKingston committed Sep 5, 2023
1 parent 5965317 commit 39fd905
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 9 deletions.
10 changes: 10 additions & 0 deletions packages/safe-globals/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ export const Reflect = captureGlobal('Reflect')
export const Object = captureGlobal('Object')
export const RegExp = captureGlobal('RegExp')

/**
* Returns a string using the prototype of our safe iframe.
*/
export function getSafeString (stringIn) {
// eslint-disable-next-line no-new-wrappers
return new String(stringIn)
}

// Both of these aren't using our safe iframe as we need to have registered side effects on the page
// We still want to not have a tampered method though.
export const customElementsGet = globalThis.customElements?.get.bind(globalThis.customElements)
export const customElementsDefine = globalThis.customElements?.define.bind(globalThis.customElements)

Expand Down
12 changes: 9 additions & 3 deletions packages/safe-globals/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { getInjectionElement } from '../../src/utils.js'
export const hasMozProxies = typeof mozProxies !== 'undefined' ? mozProxies : false

let dummyWindow
if ('document' in globalThis &&
if (globalThis && 'document' in globalThis &&
// Prevent infinate recursion of injection into Chrome
globalThis.location.href !== 'about:blank') {
const injectionElement = getInjectionElement()
// injectionElement is null in some playwright context tests
if (injectionElement) {
dummyWindow = document.createElement('iframe')
dummyWindow = globalThis.document.createElement('iframe')
dummyWindow.style.display = 'none'
injectionElement.appendChild(dummyWindow)
}
Expand All @@ -24,13 +24,19 @@ if (hasMozProxies) {
const dummySymbol = dummyContentWindow?.Symbol
const iteratorSymbol = dummySymbol?.iterator

// Capture prototype to prevent overloading
/**
* Capture prototype to prevent overloading
* @template {string} T
* @param {T} globalName
* @returns {globalThis[T]}
*/
export function captureGlobal (globalName) {
const global = dummyWindow?.contentWindow?.[globalName]

// if we were unable to create a dummy window, return the global
// this still has the advantage of preventing aliasing of the global through shawdowing
if (!global) {
// @ts-expect-error can't index typeof T
return globalThis[globalName]
}

Expand Down
2 changes: 1 addition & 1 deletion src/content-scope-features.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ function injectFeatures (args) {
${codeFeatures.join('\n')}
})();`
script.src = 'data:text/javascript;base64,' + btoa(code)
getInjectionElement().appendChild(script)
getInjectionElement()?.appendChild(script)
script.remove()
}

Expand Down
11 changes: 6 additions & 5 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* global cloneInto, exportFunction, mozProxies */
import { Set, String, RegExp } from '@duckduckgo/safe-globals'
import { Set, getSafeString, RegExp } from '@duckduckgo/safe-globals'

// Only use globalThis for testing this breaks window.wrappedJSObject code in Firefox
// eslint-disable-next-line no-global-assign
Expand All @@ -17,10 +17,11 @@ export function registerMessageSecret (secret) {
}

/**
* @returns {HTMLElement} the element to inject the script into
* @returns {null | HTMLElement} the element to inject the script into
*/
export function getInjectionElement () {
if (!globalObj) {
// Account for test setups
if (!globalObj || !('document' in globalObj)) {
return null
}
return globalObj.document.head || globalObj.document.documentElement
Expand Down Expand Up @@ -53,7 +54,7 @@ export function createStyleElement (css) {
*/
export function injectGlobalStyles (css) {
const style = createStyleElement(css)
getInjectionElement().appendChild(style)
getInjectionElement()?.appendChild(style)
}

/**
Expand Down Expand Up @@ -335,7 +336,7 @@ export function processAttr (configSetting, defaultValue) {
}

export function getStack () {
return new String(new Error().stack)
return getSafeString(new Error().stack)
}

export function getContextId (scope) {
Expand Down

0 comments on commit 39fd905

Please sign in to comment.