Skip to content

Commit

Permalink
Release build 4.7.0 [ci release]
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanKingston authored and github-actions[bot] committed Mar 28, 2023
1 parent 43ab6ed commit d2b87dc
Show file tree
Hide file tree
Showing 15 changed files with 1,260 additions and 405 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:

- name: Collect commit ranges
run: |
echo "$(git log main --since "$(git show -s --format=%ci $(git rev-list --tags --max-count=1))" --pretty='format:- %s')" > ${{ github.workspace }}-CHANGELOG.txt
echo "# ${{ github.event.inputs.version }} release\n\n$(git log main --since "$(git show -s --format=%ci $(git rev-list --tags --max-count=1))" --pretty='format:- %s')" > ${{ github.workspace }}-CHANGELOG.txt
- name: Create Release
uses: softprops/action-gh-release@v1
Expand Down
163 changes: 135 additions & 28 deletions Sources/ContentScopeScripts/dist/contentScope.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,15 @@
return processAttr(configSetting, defaultValue)
}

const functionMap = {
/** Useful for debugging APIs in the wild, shouldn't be used */
debug: (...args) => {
console.log('debugger', ...args);
// eslint-disable-next-line no-debugger
debugger
}
};

/**
* Handles the processing of a config setting.
* @param {*} configSetting
Expand All @@ -313,6 +322,12 @@
return defaultValue
}

if (configSetting.type === 'function') {
if (configSetting.functionName && functionMap[configSetting.functionName]) {
return functionMap[configSetting.functionName]
}
}

if (configSetting.type === 'undefined') {
return undefined
}
Expand Down Expand Up @@ -8657,12 +8672,15 @@
init: init$3
});

/* global TrustedScriptURL, TrustedScript */

let stackDomains = [];
let matchAllStackDomains = false;
let taintCheck = false;
let initialCreateElement;
let tagModifiers = {};
let shadowDomEnabled = false;
let scriptOverload = {};

/**
* @param {string} tagName
Expand All @@ -8681,6 +8699,15 @@
const featureName = 'runtimeChecks';
const taintSymbol = Symbol(featureName);
const supportedSinks = ['src'];
// Store the original methods so we can call them without any side effects
const defaultElementMethods = {
setAttribute: HTMLElement.prototype.setAttribute,
getAttribute: HTMLElement.prototype.getAttribute,
removeAttribute: HTMLElement.prototype.removeAttribute,
remove: HTMLElement.prototype.remove,
removeChild: HTMLElement.prototype.removeChild
};
const supportedTrustedTypes = 'TrustedScriptURL' in window;

class DDGRuntimeChecks extends HTMLElement {
#tagName
Expand Down Expand Up @@ -8757,6 +8784,84 @@
});
}

computeScriptOverload (el) {
// Short circuit if we don't have any script text
if (el.textContent === '') return
// Short circuit if we're in a trusted script environment
// @ts-expect-error TrustedScript is not defined in the TS lib
if (supportedTrustedTypes && el.textContent instanceof TrustedScript) return

const config = scriptOverload;
const processedConfig = {};
for (const [key, value] of Object.entries(config)) {
processedConfig[key] = processAttr(value);
}
// Don't do anything if the config is empty
if (Object.keys(processedConfig).length === 0) return

/**
* @param {*} scope
* @param {Record<string, any>} outputs
* @returns {Proxy}
*/
function constructProxy (scope, outputs) {
return new Proxy(scope, {
get (target, property, receiver) {
const targetObj = target[property];
if (typeof targetObj === 'function') {
return (...args) => {
return Reflect.apply(target[property], target, args)
}
} else {
if (typeof property === 'string' && property in outputs) {
return Reflect.get(outputs, property, receiver)
}
return Reflect.get(target, property, receiver)
}
}
})
}

let prepend = '';
const aggregatedLookup = new Map();
/* Convert the config into a map of scopePath -> { key: value } */
for (const [key, value] of Object.entries(processedConfig)) {
const path = key.split('.');
const scopePath = path.slice(0, -1).join('.');
const pathOut = path[path.length - 1];
if (aggregatedLookup.has(scopePath)) {
aggregatedLookup.get(scopePath)[pathOut] = value;
} else {
aggregatedLookup.set(scopePath, {
[pathOut]: value
});
}
}

for (const [key, value] of aggregatedLookup) {
const path = key.split('.');
if (path.length !== 1) {
console.error('Invalid config, currently only one layer depth is supported');
continue
}
const scopeName = path[0];
prepend += `
let ${scopeName} = constructProxy(parentScope.${scopeName}, ${JSON.stringify(value)});
`;
}
const keysOut = [...aggregatedLookup.keys()].join(',\n');
prepend += `
const window = constructProxy(parentScope, {
${keysOut}
});
const globalThis = constructProxy(parentScope, {
${keysOut}
});
`;
const innerCode = prepend + el.textContent;
el.textContent = '(function (parentScope) {' + constructProxy.toString() + ' ' + innerCode + '})(globalThis)';
}

/**
* The element has been moved to the DOM, so we can now reflect all changes to a real element.
* This is to allow us to interrogate the real element before it is moved to the DOM.
Expand All @@ -8773,7 +8878,7 @@
// Reflect all attrs to the new element
for (const attribute of this.getAttributeNames()) {
if (shouldFilterKey(this.#tagName, 'attribute', attribute)) continue
el.setAttribute(attribute, this.getAttribute(attribute));
defaultElementMethods.setAttribute.call(el, attribute, this.getAttribute(attribute));
}

// Reflect all props to the new element
Expand Down Expand Up @@ -8816,6 +8921,10 @@
el.appendChild(this.firstChild);
}

if (this.#tagName === 'script') {
this.computeScriptOverload(el);
}

// Move the new element to the DOM
try {
this.insertAdjacentElement('afterend', el);
Expand All @@ -8835,6 +8944,22 @@
return this.#el?.deref()
}

/**
* Calls a method on the real element if it exists, otherwise calls the method on the DDGRuntimeChecks element.
* @template {keyof defaultElementMethods} E
* @param {E} method
* @param {...Parameters<defaultElementMethods[E]>} args
* @return {ReturnType<defaultElementMethods[E]>}
*/
_callMethod (method, ...args) {
const el = this._getElement();
if (el) {
return defaultElementMethods[method].call(el, ...args)
}
// @ts-expect-error TS doesn't like the spread operator
return super[method](...args)
}

/* Native DOM element methods we're capturing to supplant values into the constructed node or store data for. */

set src (value) {
Expand All @@ -8852,8 +8977,7 @@
return el.src
}
// @ts-expect-error TrustedScriptURL is not defined in the TS lib
// eslint-disable-next-line no-undef
if ('TrustedScriptURL' in window && this.#sinks.src instanceof TrustedScriptURL) {
if (supportedTrustedTypes && this.#sinks.src instanceof TrustedScriptURL) {
return this.#sinks.src.toString()
}
return this.#sinks.src
Expand All @@ -8864,11 +8988,7 @@
if (supportedSinks.includes(name)) {
return this[name]
}
const el = this._getElement();
if (el) {
return el.getAttribute(name)
}
return super.getAttribute(name)
return this._callMethod('getAttribute', name, value)
}

setAttribute (name, value) {
Expand All @@ -8877,11 +8997,7 @@
this[name] = value;
return
}
const el = this._getElement();
if (el) {
return el.setAttribute(name, value)
}
return super.setAttribute(name, value)
return this._callMethod('setAttribute', name, value)
}

removeAttribute (name) {
Expand All @@ -8890,11 +9006,7 @@
delete this[name];
return
}
const el = this._getElement();
if (el) {
return el.removeAttribute(name)
}
return super.removeAttribute(name)
return this._callMethod('removeAttribute', name)
}

addEventListener (...args) {
Expand Down Expand Up @@ -8931,19 +9043,12 @@
}

remove () {
const el = this._getElement();
if (el) {
return el.remove()
}
return super.remove()
return this._callMethod('remove')
}

// @ts-expect-error TS node return here
removeChild (child) {
const el = this._getElement();
if (el) {
return el.removeChild(child)
}
return super.removeChild(child)
return this._callMethod('removeChild', child)
}
}

Expand Down Expand Up @@ -9014,6 +9119,7 @@
function load () {
// This shouldn't happen, but if it does we don't want to break the page
try {
// @ts-expect-error TS node return here
customElements.define('ddg-runtime-checks', DDGRuntimeChecks);
} catch {}
}
Expand All @@ -9035,6 +9141,7 @@
elementRemovalTimeout = getFeatureSetting(featureName, args, 'elementRemovalTimeout') || 1000;
tagModifiers = getFeatureSetting(featureName, args, 'tagModifiers') || {};
shadowDomEnabled = getFeatureSettingEnabled(featureName, args, 'shadowDom') || false;
scriptOverload = getFeatureSetting(featureName, args, 'scriptOverload') || {};

overrideCreateElement();

Expand Down
Loading

0 comments on commit d2b87dc

Please sign in to comment.