Firefox currently supports the beforescriptexecute event (as of Version 4, released on March 22, 2011)?.
With that event and the // @run-at document-start
directive, Firefox and Greasemonkey now seem to do a good job intercepting specific <script>
tags.
This is still not possible for Chrome+Tampermonkey. For anything but Firefox+Greasemonkey, you will need to use techniques as shown in the other answers, below, of write a full browser extension.
The checkForBadJavascripts
function encapsulates this. For example, suppose the page had a <script>
tag like so:
<script>
alert ("Sorry, Sucka! You've got no money left.");
</script>
You could use checkForBadJavascripts
like so:
checkForBadJavascripts ( [
[ false,
/Sorry, Sucka/,
function () {
addJS_Node ('alert ("Hooray, you're a millionaire.");');
}
]
] );
to get a much nicer message. (^_^)
See the inline documentation, in checkForBadJavascripts, for more.
To see a demonstration in a complete script, first visit this page at jsBin. You will see 3 lines of text, two of them added by JS.
Now, install this script (View source; it's also below.) and revisit the page. You will see that the GM-script deleted one bad tag and replaced another with our "good" JS.
? Note that only Firefox supports the beforescriptexecute
event. And it was removed from the HTML5 spec with no equivalent capability specified.
Complete GM script example (The same as the one at GitHub and jsBin):
Given this HTML:
<body onload="init()">
<script type="text/javascript" src="http://jsbin.com/evilExternalJS/js"></script>
<script type="text/javascript" language="javascript">
function init () {
var newParagraph = document.createElement ('p');
newParagraph.textContent = "I was added by the old, evil init() function!";
document.body.appendChild (newParagraph);
}
</script>
<p>I'm some initial text.</p>
</body>
Use this Greasemonkey script:
// ==UserScript==
// @name _Replace evil Javascript
// @include http://jsbin.com/ogudon*
// @run-at document-start
// ==/UserScript==
/****** New "init" function that we will use
instead of the old, bad "init" function.
*/
function init () {
var newParagraph = document.createElement ('p');
newParagraph.textContent = "I was added by the new, good init() function!";
document.body.appendChild (newParagraph);
}
/*--- Check for bad scripts to intercept and specify any actions to take.
*/
checkForBadJavascripts ( [
[false, /old, evil init()/, function () {addJS_Node (init);} ],
[true, /evilExternalJS/i, null ]
] );
function checkForBadJavascripts (controlArray) {
/*--- Note that this is a self-initializing function. The controlArray
parameter is only active for the FIRST call. After that, it is an
event listener.
The control array row is defines like so:
[bSearchSrcAttr, identifyingRegex, callbackFunction]
Where:
bSearchSrcAttr True to search the SRC attribute of a script tag
false to search the TEXT content of a script tag.
identifyingRegex A valid regular expression that should be unique
to that particular script tag.
callbackFunction An optional function to execute when the script is
found. Use null if not needed.
*/
if ( ! controlArray.length) return null;
checkForBadJavascripts = function (zEvent) {
for (var J = controlArray.length - 1; J >= 0; --J) {
var bSearchSrcAttr = controlArray[J][0];
var identifyingRegex = controlArray[J][1];
if (bSearchSrcAttr) {
if (identifyingRegex.test (zEvent.target.src) ) {
stopBadJavascript (J);
return false;
}
}
else {
if (identifyingRegex.test (zEvent.target.textContent) ) {
stopBadJavascript (J);
return false;
}
}
}
function stopBadJavascript (controlIndex) {
zEvent.stopPropagation ();
zEvent.preventDefault ();
var callbackFunction = controlArray[J][2];
if (typeof callbackFunction == "function")
callbackFunction ();
//--- Remove the node just to clear clutter from Firebug inspection.
zEvent.target.parentNode.removeChild (zEvent.target);
//--- Script is intercepted, remove it from the list.
controlArray.splice (J, 1);
if ( ! controlArray.length) {
//--- All done, remove the listener.
window.removeEventListener (
'beforescriptexecute', checkForBadJavascripts, true
);
}
}
}
/*--- Use the "beforescriptexecute" event to monitor scipts as they are loaded.
See https://developer.mozilla.org/en/DOM/element.onbeforescriptexecute
Note that it does not work on acripts that are dynamically created.
*/
window.addEventListener ('beforescriptexecute', checkForBadJavascripts, true);
return checkForBadJavascripts;
}
function addJS_Node (text, s_URL, funcToRun) {
var D = document;
var scriptNode = D.createElement ('script');
scriptNode.type = "text/javascript";
if (text) scriptNode.textContent = text;
if (s_URL) scriptNode.src = s_URL;
if (funcToRun) scriptNode.textContent = '(' + funcToRun.toString() + ')()';
var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
//--- Don't error check here. if DOM not available, should throw error.
targ.appendChild (scriptNode);
}