|
35 | 35 | };
|
36 | 36 | }
|
37 | 37 |
|
| 38 | + /** |
| 39 | + * Wrap functions to fix toString but also behave as closely to their real function as possible like .name and .length etc. |
| 40 | + * TODO: validate with firefox non runtimeChecks context and also consolidate with wrapToString |
| 41 | + * @param {*} functionValue |
| 42 | + * @param {*} realTarget |
| 43 | + * @returns {Proxy} a proxy for the function |
| 44 | + */ |
| 45 | + function wrapFunction (functionValue, realTarget) { |
| 46 | + return new Proxy(realTarget, { |
| 47 | + get (target, prop, receiver) { |
| 48 | + if (prop === 'toString') { |
| 49 | + const method = Reflect.get(target, prop, receiver).bind(target); |
| 50 | + Object.defineProperty(method, 'toString', { |
| 51 | + value: functionToString.bind(functionToString), |
| 52 | + enumerable: false |
| 53 | + }); |
| 54 | + return method |
| 55 | + } |
| 56 | + return Reflect.get(target, prop, receiver) |
| 57 | + }, |
| 58 | + apply (target, thisArg, argumentsList) { |
| 59 | + // This is where we call our real function |
| 60 | + return Reflect.apply(functionValue, thisArg, argumentsList) |
| 61 | + } |
| 62 | + }) |
| 63 | + } |
| 64 | + |
38 | 65 | /**
|
39 | 66 | * Wrap a get/set or value property descriptor. Only for data properties. For methods, use wrapMethod(). For constructors, use wrapConstructor().
|
40 | 67 | * @param {any} object - object whose property we are wrapping (most commonly a prototype)
|
|
418 | 445 | if (!shouldStackCheck || !taintedOrigins()) {
|
419 | 446 | return false
|
420 | 447 | }
|
| 448 | + const currentTaintedOrigins = taintedOrigins(); |
| 449 | + if (!currentTaintedOrigins || currentTaintedOrigins.size === 0) { |
| 450 | + return false |
| 451 | + } |
421 | 452 | const stackOrigins = getStackTraceOrigins(getStack());
|
422 | 453 | for (const stackOrigin of stackOrigins) {
|
423 |
| - if (taintedOrigins()?.has(stackOrigin)) { |
| 454 | + if (currentTaintedOrigins.has(stackOrigin)) { |
424 | 455 | return true
|
425 | 456 | }
|
426 | 457 | }
|
|
2170 | 2201 | return super[method](...args)
|
2171 | 2202 | }
|
2172 | 2203 |
|
| 2204 | + _callSetter (prop, value) { |
| 2205 | + const el = this._getElement(); |
| 2206 | + if (el) { |
| 2207 | + el[prop] = value; |
| 2208 | + return |
| 2209 | + } |
| 2210 | + super[prop] = value; |
| 2211 | + } |
| 2212 | + |
| 2213 | + _callGetter (prop) { |
| 2214 | + const el = this._getElement(); |
| 2215 | + if (el) { |
| 2216 | + return el[prop] |
| 2217 | + } |
| 2218 | + return super[prop] |
| 2219 | + } |
| 2220 | + |
2173 | 2221 | /* Native DOM element methods we're capturing to supplant values into the constructed node or store data for. */
|
2174 | 2222 |
|
2175 | 2223 | set src (value) {
|
|
2343 | 2391 | });
|
2344 | 2392 | }
|
2345 | 2393 |
|
| 2394 | + function isRuntimeElement (element) { |
| 2395 | + try { |
| 2396 | + return element instanceof DDGRuntimeChecks |
| 2397 | + } catch {} |
| 2398 | + return false |
| 2399 | + } |
| 2400 | + |
| 2401 | + function overloadGetOwnPropertyDescriptor () { |
| 2402 | + const capturedDescriptors = { |
| 2403 | + HTMLScriptElement: Object.getOwnPropertyDescriptors(HTMLScriptElement), |
| 2404 | + HTMLScriptElementPrototype: Object.getOwnPropertyDescriptors(HTMLScriptElement.prototype) |
| 2405 | + }; |
| 2406 | + /** |
| 2407 | + * @param {any} value |
| 2408 | + * @returns {string | undefined} |
| 2409 | + */ |
| 2410 | + function getInterfaceName (value) { |
| 2411 | + let interfaceName; |
| 2412 | + if (value === HTMLScriptElement) { |
| 2413 | + interfaceName = 'HTMLScriptElement'; |
| 2414 | + } |
| 2415 | + if (value === HTMLScriptElement.prototype) { |
| 2416 | + interfaceName = 'HTMLScriptElementPrototype'; |
| 2417 | + } |
| 2418 | + return interfaceName |
| 2419 | + } |
| 2420 | + // TODO: Consoldiate with wrapProperty code |
| 2421 | + function getInterfaceDescriptor (interfaceValue, interfaceName, propertyName) { |
| 2422 | + const capturedInterface = capturedDescriptors[interfaceName] && capturedDescriptors[interfaceName][propertyName]; |
| 2423 | + const capturedInterfaceOut = { ...capturedInterface }; |
| 2424 | + if (capturedInterface.get) { |
| 2425 | + capturedInterfaceOut.get = wrapFunction(function () { |
| 2426 | + let method = capturedInterface.get; |
| 2427 | + if (isRuntimeElement(this)) { |
| 2428 | + method = () => this._callGetter(propertyName); |
| 2429 | + } |
| 2430 | + return method.call(this) |
| 2431 | + }, capturedInterface.get); |
| 2432 | + } |
| 2433 | + if (capturedInterface.set) { |
| 2434 | + capturedInterfaceOut.set = wrapFunction(function (value) { |
| 2435 | + let method = capturedInterface; |
| 2436 | + if (isRuntimeElement(this)) { |
| 2437 | + method = (value) => this._callSetter(propertyName, value); |
| 2438 | + } |
| 2439 | + return method.call(this, [value]) |
| 2440 | + }, capturedInterface.set); |
| 2441 | + } |
| 2442 | + return capturedInterfaceOut |
| 2443 | + } |
| 2444 | + const proxy = new DDGProxy(featureName, Object, 'getOwnPropertyDescriptor', { |
| 2445 | + apply (fn, scope, args) { |
| 2446 | + const interfaceValue = args[0]; |
| 2447 | + const interfaceName = getInterfaceName(interfaceValue); |
| 2448 | + const propertyName = args[1]; |
| 2449 | + const capturedInterface = capturedDescriptors[interfaceName] && capturedDescriptors[interfaceName][propertyName]; |
| 2450 | + if (interfaceName && capturedInterface) { |
| 2451 | + return getInterfaceDescriptor(interfaceValue, interfaceName, propertyName) |
| 2452 | + } |
| 2453 | + return Reflect$1.apply(fn, scope, args) |
| 2454 | + } |
| 2455 | + }); |
| 2456 | + proxy.overload(); |
| 2457 | + const proxy2 = new DDGProxy(featureName, Object, 'getOwnPropertyDescriptors', { |
| 2458 | + apply (fn, scope, args) { |
| 2459 | + const interfaceValue = args[0]; |
| 2460 | + const interfaceName = getInterfaceName(interfaceValue); |
| 2461 | + const capturedInterface = capturedDescriptors[interfaceName]; |
| 2462 | + if (interfaceName && capturedInterface) { |
| 2463 | + const out = {}; |
| 2464 | + for (const propertyName of Object.getOwnPropertyNames(capturedInterface)) { |
| 2465 | + out[propertyName] = getInterfaceDescriptor(interfaceValue, interfaceName, propertyName); |
| 2466 | + } |
| 2467 | + return out |
| 2468 | + } |
| 2469 | + return Reflect$1.apply(fn, scope, args) |
| 2470 | + } |
| 2471 | + }); |
| 2472 | + proxy2.overload(); |
| 2473 | + } |
| 2474 | + |
2346 | 2475 | function overrideCreateElement (debug) {
|
2347 | 2476 | const proxy = new DDGProxy(featureName, Document.prototype, 'createElement', {
|
2348 | 2477 | apply (fn, scope, args) {
|
|
2446 | 2575 | if (this.getFeatureSettingEnabled('overloadReplaceChild')) {
|
2447 | 2576 | overloadReplaceChild();
|
2448 | 2577 | }
|
| 2578 | + if (this.getFeatureSettingEnabled('overloadGetOwnPropertyDescriptor')) { |
| 2579 | + overloadGetOwnPropertyDescriptor(); |
| 2580 | + } |
2449 | 2581 | }
|
2450 | 2582 |
|
2451 | 2583 | injectGenericOverloads () {
|
|
2474 | 2606 | ['innerHeight', 'innerWidth', 'outerHeight', 'outerWidth', 'Screen.prototype.height', 'Screen.prototype.width'].forEach(sizing => {
|
2475 | 2607 | if (sizing in genericOverloads) {
|
2476 | 2608 | const sizingConfig = genericOverloads[sizing];
|
| 2609 | + if (isBeingFramed() && !sizingConfig.applyToFrames) return |
2477 | 2610 | this.overloadScreenSizes(sizingConfig, breakpoints, screenSize, sizing, sizingConfig.offset || 0);
|
2478 | 2611 | }
|
2479 | 2612 | });
|
|
2661 | 2794 | receiver = globalThis.screen;
|
2662 | 2795 | break
|
2663 | 2796 | }
|
2664 |
| - const defaultVal = Reflect$1.get(scope, overrideKey, receiver); |
| 2797 | + const defaultGetter = Object.getOwnPropertyDescriptor(scope, overrideKey)?.get; |
| 2798 | + // Should never happen |
| 2799 | + if (!defaultGetter) { |
| 2800 | + return |
| 2801 | + } |
2665 | 2802 | defineProperty(scope, overrideKey, {
|
2666 | 2803 | get () {
|
| 2804 | + const defaultVal = Reflect$1.apply(defaultGetter, receiver, []); |
2667 | 2805 | if (getTaintFromScope(this, arguments, config.stackCheck)) {
|
2668 | 2806 | return returnVal
|
2669 | 2807 | }
|
|
0 commit comments