Skip to content

Commit 658da08

Browse files
Release build 4.22.0 [ci release]
1 parent 260329a commit 658da08

File tree

15 files changed

+1128
-24
lines changed

15 files changed

+1128
-24
lines changed

Sources/ContentScopeScripts/dist/contentScope.js

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,33 @@
3535
};
3636
}
3737

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+
3865
/**
3966
* Wrap a get/set or value property descriptor. Only for data properties. For methods, use wrapMethod(). For constructors, use wrapConstructor().
4067
* @param {any} object - object whose property we are wrapping (most commonly a prototype)
@@ -418,9 +445,13 @@
418445
if (!shouldStackCheck || !taintedOrigins()) {
419446
return false
420447
}
448+
const currentTaintedOrigins = taintedOrigins();
449+
if (!currentTaintedOrigins || currentTaintedOrigins.size === 0) {
450+
return false
451+
}
421452
const stackOrigins = getStackTraceOrigins(getStack());
422453
for (const stackOrigin of stackOrigins) {
423-
if (taintedOrigins()?.has(stackOrigin)) {
454+
if (currentTaintedOrigins.has(stackOrigin)) {
424455
return true
425456
}
426457
}
@@ -2170,6 +2201,23 @@
21702201
return super[method](...args)
21712202
}
21722203

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+
21732221
/* Native DOM element methods we're capturing to supplant values into the constructed node or store data for. */
21742222

21752223
set src (value) {
@@ -2343,6 +2391,87 @@
23432391
});
23442392
}
23452393

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+
23462475
function overrideCreateElement (debug) {
23472476
const proxy = new DDGProxy(featureName, Document.prototype, 'createElement', {
23482477
apply (fn, scope, args) {
@@ -2446,6 +2575,9 @@
24462575
if (this.getFeatureSettingEnabled('overloadReplaceChild')) {
24472576
overloadReplaceChild();
24482577
}
2578+
if (this.getFeatureSettingEnabled('overloadGetOwnPropertyDescriptor')) {
2579+
overloadGetOwnPropertyDescriptor();
2580+
}
24492581
}
24502582

24512583
injectGenericOverloads () {
@@ -2474,6 +2606,7 @@
24742606
['innerHeight', 'innerWidth', 'outerHeight', 'outerWidth', 'Screen.prototype.height', 'Screen.prototype.width'].forEach(sizing => {
24752607
if (sizing in genericOverloads) {
24762608
const sizingConfig = genericOverloads[sizing];
2609+
if (isBeingFramed() && !sizingConfig.applyToFrames) return
24772610
this.overloadScreenSizes(sizingConfig, breakpoints, screenSize, sizing, sizingConfig.offset || 0);
24782611
}
24792612
});
@@ -2661,9 +2794,14 @@
26612794
receiver = globalThis.screen;
26622795
break
26632796
}
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+
}
26652802
defineProperty(scope, overrideKey, {
26662803
get () {
2804+
const defaultVal = Reflect$1.apply(defaultGetter, receiver, []);
26672805
if (getTaintFromScope(this, arguments, config.stackCheck)) {
26682806
return returnVal
26692807
}

build/android/contentScope.js

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,33 @@
3535
};
3636
}
3737

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+
3865
/**
3966
* Wrap a get/set or value property descriptor. Only for data properties. For methods, use wrapMethod(). For constructors, use wrapConstructor().
4067
* @param {any} object - object whose property we are wrapping (most commonly a prototype)
@@ -423,9 +450,13 @@
423450
if (!shouldStackCheck || !taintedOrigins()) {
424451
return false
425452
}
453+
const currentTaintedOrigins = taintedOrigins();
454+
if (!currentTaintedOrigins || currentTaintedOrigins.size === 0) {
455+
return false
456+
}
426457
const stackOrigins = getStackTraceOrigins(getStack());
427458
for (const stackOrigin of stackOrigins) {
428-
if (taintedOrigins()?.has(stackOrigin)) {
459+
if (currentTaintedOrigins.has(stackOrigin)) {
429460
return true
430461
}
431462
}
@@ -3236,6 +3267,23 @@
32363267
return super[method](...args)
32373268
}
32383269

3270+
_callSetter (prop, value) {
3271+
const el = this._getElement();
3272+
if (el) {
3273+
el[prop] = value;
3274+
return
3275+
}
3276+
super[prop] = value;
3277+
}
3278+
3279+
_callGetter (prop) {
3280+
const el = this._getElement();
3281+
if (el) {
3282+
return el[prop]
3283+
}
3284+
return super[prop]
3285+
}
3286+
32393287
/* Native DOM element methods we're capturing to supplant values into the constructed node or store data for. */
32403288

32413289
set src (value) {
@@ -3409,6 +3457,87 @@
34093457
});
34103458
}
34113459

3460+
function isRuntimeElement (element) {
3461+
try {
3462+
return element instanceof DDGRuntimeChecks
3463+
} catch {}
3464+
return false
3465+
}
3466+
3467+
function overloadGetOwnPropertyDescriptor () {
3468+
const capturedDescriptors = {
3469+
HTMLScriptElement: Object.getOwnPropertyDescriptors(HTMLScriptElement),
3470+
HTMLScriptElementPrototype: Object.getOwnPropertyDescriptors(HTMLScriptElement.prototype)
3471+
};
3472+
/**
3473+
* @param {any} value
3474+
* @returns {string | undefined}
3475+
*/
3476+
function getInterfaceName (value) {
3477+
let interfaceName;
3478+
if (value === HTMLScriptElement) {
3479+
interfaceName = 'HTMLScriptElement';
3480+
}
3481+
if (value === HTMLScriptElement.prototype) {
3482+
interfaceName = 'HTMLScriptElementPrototype';
3483+
}
3484+
return interfaceName
3485+
}
3486+
// TODO: Consoldiate with wrapProperty code
3487+
function getInterfaceDescriptor (interfaceValue, interfaceName, propertyName) {
3488+
const capturedInterface = capturedDescriptors[interfaceName] && capturedDescriptors[interfaceName][propertyName];
3489+
const capturedInterfaceOut = { ...capturedInterface };
3490+
if (capturedInterface.get) {
3491+
capturedInterfaceOut.get = wrapFunction(function () {
3492+
let method = capturedInterface.get;
3493+
if (isRuntimeElement(this)) {
3494+
method = () => this._callGetter(propertyName);
3495+
}
3496+
return method.call(this)
3497+
}, capturedInterface.get);
3498+
}
3499+
if (capturedInterface.set) {
3500+
capturedInterfaceOut.set = wrapFunction(function (value) {
3501+
let method = capturedInterface;
3502+
if (isRuntimeElement(this)) {
3503+
method = (value) => this._callSetter(propertyName, value);
3504+
}
3505+
return method.call(this, [value])
3506+
}, capturedInterface.set);
3507+
}
3508+
return capturedInterfaceOut
3509+
}
3510+
const proxy = new DDGProxy(featureName, Object, 'getOwnPropertyDescriptor', {
3511+
apply (fn, scope, args) {
3512+
const interfaceValue = args[0];
3513+
const interfaceName = getInterfaceName(interfaceValue);
3514+
const propertyName = args[1];
3515+
const capturedInterface = capturedDescriptors[interfaceName] && capturedDescriptors[interfaceName][propertyName];
3516+
if (interfaceName && capturedInterface) {
3517+
return getInterfaceDescriptor(interfaceValue, interfaceName, propertyName)
3518+
}
3519+
return Reflect$1.apply(fn, scope, args)
3520+
}
3521+
});
3522+
proxy.overload();
3523+
const proxy2 = new DDGProxy(featureName, Object, 'getOwnPropertyDescriptors', {
3524+
apply (fn, scope, args) {
3525+
const interfaceValue = args[0];
3526+
const interfaceName = getInterfaceName(interfaceValue);
3527+
const capturedInterface = capturedDescriptors[interfaceName];
3528+
if (interfaceName && capturedInterface) {
3529+
const out = {};
3530+
for (const propertyName of Object.getOwnPropertyNames(capturedInterface)) {
3531+
out[propertyName] = getInterfaceDescriptor(interfaceValue, interfaceName, propertyName);
3532+
}
3533+
return out
3534+
}
3535+
return Reflect$1.apply(fn, scope, args)
3536+
}
3537+
});
3538+
proxy2.overload();
3539+
}
3540+
34123541
function overrideCreateElement (debug) {
34133542
const proxy = new DDGProxy(featureName, Document.prototype, 'createElement', {
34143543
apply (fn, scope, args) {
@@ -3512,6 +3641,9 @@
35123641
if (this.getFeatureSettingEnabled('overloadReplaceChild')) {
35133642
overloadReplaceChild();
35143643
}
3644+
if (this.getFeatureSettingEnabled('overloadGetOwnPropertyDescriptor')) {
3645+
overloadGetOwnPropertyDescriptor();
3646+
}
35153647
}
35163648

35173649
injectGenericOverloads () {
@@ -3540,6 +3672,7 @@
35403672
['innerHeight', 'innerWidth', 'outerHeight', 'outerWidth', 'Screen.prototype.height', 'Screen.prototype.width'].forEach(sizing => {
35413673
if (sizing in genericOverloads) {
35423674
const sizingConfig = genericOverloads[sizing];
3675+
if (isBeingFramed() && !sizingConfig.applyToFrames) return
35433676
this.overloadScreenSizes(sizingConfig, breakpoints, screenSize, sizing, sizingConfig.offset || 0);
35443677
}
35453678
});
@@ -3727,9 +3860,14 @@
37273860
receiver = globalThis.screen;
37283861
break
37293862
}
3730-
const defaultVal = Reflect$1.get(scope, overrideKey, receiver);
3863+
const defaultGetter = Object.getOwnPropertyDescriptor(scope, overrideKey)?.get;
3864+
// Should never happen
3865+
if (!defaultGetter) {
3866+
return
3867+
}
37313868
defineProperty(scope, overrideKey, {
37323869
get () {
3870+
const defaultVal = Reflect$1.apply(defaultGetter, receiver, []);
37333871
if (getTaintFromScope(this, arguments, config.stackCheck)) {
37343872
return returnVal
37353873
}

0 commit comments

Comments
 (0)