Skip to content

Instantly share code, notes, and snippets.

@leumasme
Forked from maple3142/onbeforescriptexecute.js
Last active July 4, 2022 18:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leumasme/325d8450fcb85e8fcdabd3d309ee7e69 to your computer and use it in GitHub Desktop.
Save leumasme/325d8450fcb85e8fcdabd3d309ee7e69 to your computer and use it in GitHub Desktop.
polyfill of 'beforescriptexecute' event
// 'beforescriptexecute' event with loadPayloadSync
// original version: https://gist.github.com/jspenguin2017/cd568a50128c71e515738413cd09a890
;(function () {
'use strict';
class Event {
constructor(script, target) {
this.script = script;
this.target = target;
this._cancel = false;
this._stop = false;
}
preventDefault() {
this._cancel = true;
}
stopPropagation() {
this._stop = true;
}
replacePayload(payload, withwhat) {
if (withwhat == undefined) {
this.script.textContent = payload;
this.script.removeAttributeNode(this.script.getAttributeNode("src"));
} else {
this.script.textContent = this.script.textContent.replace(payload, withwhat);
}
}
loadPayloadSync() {
// Blocking-Load
if (!this.script.src) return;
let req = new XMLHttpRequest();
req.open('GET', this.script.src, false);
req.send(null);
if (req.status != 200) console.error("Failed to load script: " + this.script.src, "Status: " + req.status);
this.script.textContent = req.responseText;
this.script.removeAttributeNode(this.script.getAttributeNode("src"));
}
}
var callbacks = []
var addBeforeScriptExecuteListener = function (f) {
if (!f instanceof Function) {
throw new Error('Event handler must be a function.')
}
callbacks.push(f)
}
var removeBeforeScriptExecuteListener = function (f) {
var i = callbacks.length
while (i--) {
if (callbacks[i] === f) {
callbacks.splice(i, 1)
}
}
}
var addev = window.addEventListener.bind(window)
var rmev = window.removeEventListener.bind(window)
window.addEventListener = function () {
if (arguments[0].toLowerCase() === 'beforescriptexecute') addBeforeScriptExecuteListener(arguments[1])
else addev.apply(null, arguments)
}
window.removeEventListener = function () {
if (arguments[0].toLowerCase() === 'beforescriptexecute') removeBeforeScriptExecuteListener(arguments[1])
else rmev.apply(null, arguments)
}
function dispatch(script, target) {
var evt = new Event(script, target)
if (window.onbeforescriptexecute instanceof Function) {
try {
window.onbeforescriptexecute(evt)
} catch (err) {
console.error(err)
}
}
for (let cb of callbacks) {
if (evt._stop) {
break
}
try {
cb(evt)
} catch (err) {
console.error(err)
}
}
return evt
}
var observer = new MutationObserver(mutations => {
for (let mut of mutations) {
for (let elem of mut.addedNodes) {
if (elem.tagName !== 'SCRIPT') continue
let e = dispatch(elem, mut.target)
if (e._cancel) {
elem.remove()
}
}
}
})
observer.observe(document, {
childList: true,
subtree: true
})
})();
!function(){"use strict";class t{constructor(t,e){this.script=t,this.target=e,this._cancel=!1,this._stop=!1}preventDefault(){this._cancel=!0}stopPropagation(){this._stop=!0}replacePayload(t,e){null==e?(this.script.textContent=t,this.script.removeAttributeNode(this.script.getAttributeNode("src"))):this.script.textContent=this.script.textContent.replace(t,e)}loadPayloadSync(){if(!this.script.src)return;let t=new XMLHttpRequest;t.open("GET",this.script.src,!1),t.send(null),200!=t.status&&console.error("Failed to load script: "+this.script.src,"Status: "+t.status),this.script.textContent=t.responseText,this.script.removeAttributeNode(this.script.getAttributeNode("src"))}}var e=[],r=function(t){if(!t instanceof Function)throw new Error("Event handler must be a function.");e.push(t)},n=function(t){for(var r=e.length;r--;)e[r]===t&&e.splice(r,1)},o=window.addEventListener.bind(window),i=window.removeEventListener.bind(window);function s(r,n){var o=new t(r,n);if(window.onbeforescriptexecute instanceof Function)try{window.onbeforescriptexecute(o)}catch(t){console.error(t)}for(let t of e){if(o._stop)break;try{t(o)}catch(t){console.error(t)}}return o}window.addEventListener=function(){"beforescriptexecute"===arguments[0].toLowerCase()?r(arguments[1]):o.apply(null,arguments)},window.removeEventListener=function(){"beforescriptexecute"===arguments[0].toLowerCase()?n(arguments[1]):i.apply(null,arguments)},new MutationObserver((t=>{for(let e of t)for(let t of e.addedNodes){if("SCRIPT"!==t.tagName)continue;s(t,e.target)._cancel&&t.remove()}})).observe(document,{childList:!0,subtree:!0})}();
let score = 100;
console.log("Your score is "+score);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="onbeforescriptexecute.js"></script>
<script>
window.addEventListener('beforescriptexecute',e => {
if (e.script.textContent.includes('alert')) {
e.preventDefault()
}
else if (e.script.innerHTML.includes('hello')) {
e.replacePayload(/hello/g, 'world')
}
else if (e.script.src.includes('xxx')) {
e.replacePayload("alert('Hello')");
}
else if (e.script.src.includes("score.js")) {
e.loadPayloadSync();
e.replacePayload("100", "10000");
}
})
</script>
<script>
// won't execute
alert('hello')
</script>
<script>
// will execute, but 'hello' will be convert to 'world'
console.log('hello')
</script>
<!-- won't execute -->
<script src="xxx.js"></script>
<!-- will be patched -->
<script src="score.js"></script>
</body>
</html>
alert('This should not run!')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment