Skip to content

Commit 41d77b6

Browse files
Create isolated globals (#554)
* Change to throw away iframe for capturing globals * Fix iterators
1 parent 472a32a commit 41d77b6

File tree

1 file changed

+45
-11
lines changed

1 file changed

+45
-11
lines changed

src/captured-globals.js

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,50 @@
1+
/* global mozProxies */
2+
import { getInjectionElement } from './utils.js'
3+
export const hasMozProxies = typeof mozProxies !== 'undefined' ? mozProxies : false
4+
5+
let dummyWindow
6+
if ('document' in globalThis &&
7+
// Prevent infinate recursion of injection into Chrome
8+
globalThis.location.href !== 'about:blank') {
9+
const injectionElement = getInjectionElement()
10+
// injectionElement is null in some playwright context tests
11+
if (injectionElement) {
12+
dummyWindow = document.createElement('iframe')
13+
dummyWindow.style.display = 'none'
14+
injectionElement.appendChild(dummyWindow)
15+
}
16+
}
17+
18+
let dummyContentWindow = dummyWindow?.contentWindow
19+
if (hasMozProxies) {
20+
// @ts-expect-error - mozProxies is not defined on window
21+
dummyContentWindow = dummyContentWindow.wrappedJSObject
22+
}
23+
// @ts-expect-error - Symbol is not defined on window
24+
const dummySymbol = dummyContentWindow?.Symbol
25+
const iteratorSymbol = dummySymbol?.iterator
26+
127
// Capture prototype to prevent overloading
2-
function captureGlobals (object) {
3-
const newGlobal = object
4-
for (const key in object) {
5-
const value = object[key]
6-
newGlobal[key] = value
28+
function captureGlobal (globalName) {
29+
const global = dummyWindow?.contentWindow?.[globalName]
30+
31+
// if we were unable to create a dummy window, return the global
32+
// this still has the advantage of preventing aliasing of the global through shawdowing
33+
if (!global) {
34+
return globalThis[globalName]
735
}
8-
for (const key in object.prototype) {
9-
const value = object.prototype[key]
10-
newGlobal.prototype[key] = value
36+
37+
// Alias the iterator symbol to the local symbol so for loops work
38+
if (iteratorSymbol &&
39+
global?.prototype &&
40+
iteratorSymbol in global.prototype) {
41+
global.prototype[Symbol.iterator] = global.prototype[iteratorSymbol]
1142
}
12-
return newGlobal
43+
return global
1344
}
1445

15-
export const Set = captureGlobals(globalThis.Set)
16-
export const Reflect = captureGlobals(globalThis.Reflect)
46+
export const Set = captureGlobal('Set')
47+
export const Reflect = captureGlobal('Reflect')
48+
49+
// Clean up the dummy window
50+
dummyWindow?.remove()

0 commit comments

Comments
 (0)