Skip to content

Commit

Permalink
fix(emulate-browsers): fix cross frame tostring
Browse files Browse the repository at this point in the history
  • Loading branch information
blakebyrnes committed Dec 22, 2020
1 parent b339758 commit 27a69d9
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 3 deletions.
13 changes: 10 additions & 3 deletions emulate-browsers/base/injected-scripts/_proxyUtils.ts
@@ -1,7 +1,7 @@
/////// MASK TO STRING ////////////////////////////////////////////////////////////////////////////////////////////////

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

Expand All @@ -11,9 +11,16 @@ Function.prototype.toString = new Proxy(Function.prototype.toString, {
if (overriddenFns.has(thisArg)) {
return overriddenFns.get(thisArg);
}
if (target === Function.prototype.toString) {
return nativeToStringFunctionString;
// from puppeteer-stealth: Check if the toString prototype of the context is the same as the global prototype,
// if not indicates that we are doing a check across different windows
const hasSameProto = Object.getPrototypeOf(Function.prototype.toString).isPrototypeOf(
thisArg.toString,
);
if (hasSameProto === false) {
// Pass the call on to the local Function.prototype.toString instead
return thisArg.toString(...(args ?? []));
}

return target.apply(thisArg, args);
},
});
Expand Down
21 changes: 21 additions & 0 deletions emulate-browsers/base/test/iframe.test.ts
Expand Up @@ -26,6 +26,27 @@ test('should have a chrome object on iframes', async () => {
expect(frameType).toBe('object');
});

test('should not break toString across frames', async () => {
const page = await createPage();

const toStrings = await page.evaluate(`(() => {
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const contentWindow = iframe.contentWindow;
const fnCallWithFrame = contentWindow.Function.prototype.toString.call(Function.prototype.toString);
const fnToString = Function.toString + '';
return {
fnToString,
fnCallWithFrame
}
})();`);

const { fnToString, fnCallWithFrame } = toStrings as any;
expect(fnToString).toBe(fnCallWithFrame);
});

test('should not break iframe functions', async () => {
const page = await createPage();

Expand Down

0 comments on commit 27a69d9

Please sign in to comment.