Skip to content

Commit 27a69d9

Browse files
committed
fix(emulate-browsers): fix cross frame tostring
1 parent b339758 commit 27a69d9

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

emulate-browsers/base/injected-scripts/_proxyUtils.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/////// MASK TO STRING ////////////////////////////////////////////////////////////////////////////////////////////////
22

33
// eslint-disable-next-line prefer-const -- must be let: could change for different browser (ie, Safari)
4-
let nativeToStringFunctionString = Error.toString.toString();
4+
let nativeToStringFunctionString = `${Function.toString}`;
55
// when functions are re-bound to work around the loss of scope issue in chromium, they blow up their native toString
66
const overriddenFns = new Map<Function, string>();
77

@@ -11,9 +11,16 @@ Function.prototype.toString = new Proxy(Function.prototype.toString, {
1111
if (overriddenFns.has(thisArg)) {
1212
return overriddenFns.get(thisArg);
1313
}
14-
if (target === Function.prototype.toString) {
15-
return nativeToStringFunctionString;
14+
// from puppeteer-stealth: Check if the toString prototype of the context is the same as the global prototype,
15+
// if not indicates that we are doing a check across different windows
16+
const hasSameProto = Object.getPrototypeOf(Function.prototype.toString).isPrototypeOf(
17+
thisArg.toString,
18+
);
19+
if (hasSameProto === false) {
20+
// Pass the call on to the local Function.prototype.toString instead
21+
return thisArg.toString(...(args ?? []));
1622
}
23+
1724
return target.apply(thisArg, args);
1825
},
1926
});

emulate-browsers/base/test/iframe.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,27 @@ test('should have a chrome object on iframes', async () => {
2626
expect(frameType).toBe('object');
2727
});
2828

29+
test('should not break toString across frames', async () => {
30+
const page = await createPage();
31+
32+
const toStrings = await page.evaluate(`(() => {
33+
const iframe = document.createElement('iframe');
34+
document.body.appendChild(iframe);
35+
36+
const contentWindow = iframe.contentWindow;
37+
const fnCallWithFrame = contentWindow.Function.prototype.toString.call(Function.prototype.toString);
38+
const fnToString = Function.toString + '';
39+
40+
return {
41+
fnToString,
42+
fnCallWithFrame
43+
}
44+
})();`);
45+
46+
const { fnToString, fnCallWithFrame } = toStrings as any;
47+
expect(fnToString).toBe(fnCallWithFrame);
48+
});
49+
2950
test('should not break iframe functions', async () => {
3051
const page = await createPage();
3152

0 commit comments

Comments
 (0)