Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save maple3142/c6593f0aff180bc0e4be5d549259da2c to your computer and use it in GitHub Desktop.

Select an option

Save maple3142/c6593f0aff180bc0e4be5d549259da2c to your computer and use it in GitHub Desktop.
polyfill of 'beforescriptexecute' event
<!DOCTYPE html>
<html>
<head>
<script>
{
"use strict";
const Event = class {
constructor(script, target) {
this.script = script;
this.target = target;
this._cancel = false;
this._replace = null;
this._stop = false;
}
preventDefault() {
this._cancel = true;
}
stopPropagation() {
this._stop = true;
}
replacePayload(payload) {
this._replace = payload;
}
};
let callbacks = [];
window.addBeforeScriptExecuteListener = (f) => {
callbacks.push(f);
};
window.removeBeforeScriptExecuteListener = (f) => {
let i = callbacks.length;
while (i--) {
if (callbacks[i] === f) {
callbacks.splice(i, 1);
}
}
};
const dispatch = (script, target) => {
if (script.tagName !== "SCRIPT") {
return;
}
const e = new Event(script, target);
if (window.onbeforescriptexecute instanceof Function) {
window.onbeforescriptexecute(e);
}
for (let i = 0; i < callbacks.length; i++) {
if (e._stop) {
break;
}
callbacks[i](e);
}
if (e._cancel) {
script.remove();
} else if (typeof e._replace === "string") {
script.textContent = e._replace;
}
};
const observer = new MutationObserver((mutations) => {
for (let i = 0; i < mutations.length; i++) {
for (let j = 0; j < mutations[i].addedNodes.length; j++) {
dispatch(mutations[i].addedNodes[j], mutations[i].target);
}
}
});
observer.observe(document, {
childList: true,
subtree: true,
});
}
//Only works for "hard coded" inline scripts, dynamically inserted scripts will execute before it can be canceled
//You can patch `Element.prototype.prepend`, `Element.prototype.append`, and related functions to interfere with
//dynamically inserted scripts
//Also textContent is not always set properly, especially when the script is big
//Here are some examples
"use strict";
window.onbeforescriptexecute = (e) => {
//You should check if textContent exists as this property is buggy sometimes
if (!e.script.textContent) {
return;
}
//Prevent execution of a script
if (e.script.textContent.includes("alert")) {
e.preventDefault();
}
//Change the code that runs
if (e.script.textContent.includes("console.log")) {
e.replacePayload("console.log(2);");
}
};
</script>
</head>
<body>
<script>alert(1);</script>
<script>console.log(1);</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment