🐛 keep toString always return original value for function in sandbox (#1785)
* fix: correct toString for functions * Update src/sandbox/common.ts * Update src/sandbox/common.ts * handle getter in toString descriptor * toString function predict Co-authored-by: Kuitos <kuitos.lau@gmail.com>
This commit is contained in:
parent
b86fffcdbe
commit
e807cbcfb6
|
|
@ -59,4 +59,24 @@ describe('getTargetValue', () => {
|
|||
const boundFn = getTargetValue(window, callableFunction);
|
||||
expect(boundFn.prototype).toBe(callableFunction.prototype);
|
||||
});
|
||||
|
||||
it("should work well while function's toString()'s return value keeps the same as the origin", () => {
|
||||
function callableFunction1() {}
|
||||
function callableFunction2() {}
|
||||
function callableFunction3() {}
|
||||
callableFunction2.toString = () => 'instance toString';
|
||||
Object.defineProperty(callableFunction3, 'toString', {
|
||||
get() {
|
||||
return () => 'instance toString';
|
||||
},
|
||||
});
|
||||
|
||||
const boundFn1 = getTargetValue(window, callableFunction1);
|
||||
const boundFn2 = getTargetValue(window, callableFunction2);
|
||||
const boundFn3 = getTargetValue(window, callableFunction3);
|
||||
|
||||
expect(boundFn1.toString()).toBe(callableFunction1.toString());
|
||||
expect(boundFn2.toString()).toBe(callableFunction2.toString());
|
||||
expect(boundFn3.toString()).toBe(callableFunction3.toString());
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -51,6 +51,25 @@ export function getTargetValue(target: any, value: any): any {
|
|||
Object.defineProperty(boundValue, 'prototype', { value: value.prototype, enumerable: false, writable: true });
|
||||
}
|
||||
|
||||
// Some util, like `function isNative() { return typeof Ctor === 'function' && /native code/.test(Ctor.toString()) }` relies on the original `toString()` result
|
||||
// but bound functions will always return "function() {[native code]}" for `toString`, which is misleading
|
||||
if (typeof value.toString === 'function') {
|
||||
const valueHasInstanceToString = value.hasOwnProperty('toString') && !boundValue.hasOwnProperty('toString');
|
||||
const boundValueHasPrototypeToString = boundValue.toString === Function.prototype.toString;
|
||||
|
||||
if (valueHasInstanceToString || boundValueHasPrototypeToString) {
|
||||
const originToStringDescriptor = Object.getOwnPropertyDescriptor(
|
||||
valueHasInstanceToString ? value : Function.prototype,
|
||||
'toString',
|
||||
);
|
||||
|
||||
Object.defineProperty(boundValue, 'toString', {
|
||||
...originToStringDescriptor,
|
||||
...(originToStringDescriptor?.get ? null : { value: () => value.toString() }),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
functionBoundedValueMap.set(value, boundValue);
|
||||
return boundValue;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user