0

I visit a website with a javascript file in the head of the HTML

<script>(function(d){var config={kitId:'gpn1wjb',scriptTimeout:3000,async:true},h=d.documentElement,t=setTimeout(function(){h.className=h.className.replace(/\bwf-loading\b/g,"")+" wf-inactive";},config.scriptTimeout),tk=d.createElement("script"),f=false,s=d.getElementsByTagName("script")[0],a;h.className+=" wf-loading";tk.src='//use.typekit.net/'+config.kitId+'.js';tk.async=true;tk.onload=tk.onreadystatechange=function(){a=this.readyState;if(f||a&&a!="complete"&&a!="loaded")return;f=true;clearTimeout(t);try{Typekit.load(config)}catch(e){}};s.parentNode.insertBefore(tk,s)})(document);</script>

How can I disable/remove/replace this function with Greasemonkey?

0

2 Answers 2

1

There isn't a standard way to deal with this. The function you want to disable executes as soon as the browser reads that part of the HTML, meaning you cannot remove the script node from tampermonkey even if you run the userscript at document loading start (using @run-at document-start).

You can try to exploit the fact that they call setTimeout though. The idea is to throw an error in the moment they call it, so that their code snippet does not run properly.

Code should look like this. Make sure you're accessing unsandboxed window object.

const oldSetTimeout = window.setTimeout;
// replace setTimeout with our hacked version
window.setTimeout = newSetTimeout;
/**
 *
 * @param {function} cb
 * @param {number} delay
 */
function newSetTimeout(cb, delay) {
    // Check if callback contains string we know from the sourcecode
    if (cb && cb.toString().indexOf("bwf-loading")!=-1) {
        // misdeed done, restore normal setTimeout
        window.setTimeout = oldSetTimeout;
        throw new Error("Failing set timeout to kill unwanted script.");
    }
    // otherwise act as normal setTimeout
    else {
        return oldSetTimeout.call(window, arguments);
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Did you make sure the code executes right at the document start? There's a greasemonkey setting for that.
0

Took the example from Tomas and updated it to work with Greasemonkey v4, the main change being that you need to export your function across contexts. This example changes the document.body.appendChild function which was appropriate for my usecase, but I got a few other functions working with a similar pattern too.

const overwriteAC = function(){
  // despite comments in https://stackoverflow.com/questions/48122766/function-not-defined-or-permission-denied-to-access-object-in-greasemonkey/48194770
  // `unsafeWindow.[...]` does not seem to be necessary here
  // however, on other (?) functions e.g. `document.createElement` you will need to
  // use `.bind()` as per comments here
  // https://stackoverflow.com/a/24339478/2640621
  // e.g. `const oldCreateElement = document.createElement.bind(document);`
  const oldAC = document.body.appendChild;
  const newAC = function(node) {
    if (node && "src" in node && node.src.includes("recaptcha")) {
      console.log(`Blocking ${node.src}.`);
      node.src = "";
      node.text = "";
      // `functions` returns a list, `appendChild` only takes one argument so we just pass `node` here instead
      // the first argument to `.call()` changes depending on which function you're modifying
      // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call#parameters
      oldAC.call(document.body, node);
    } else {
      oldAC.call(document.body, node);
    };
  };
  // as per https://www.greasespot.net/2017/09/greasemonkey-4-for-script-authors.html
  // and https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Sharing_objects_with_page_scripts#exportfunction
  // this is required for the page script's scope to access the `newAC()` function
  exportFunction(newAC, document.body, {defineAs:'appendChild'});
};

// this was needed for `appendChild` as `document.body` does not exist when this script starts
// not necessarily required for other functions, so you could call your `overwriteFoobar()` function
// from the root of the script without using `MutationObserver`
// https://stackoverflow.com/a/26324641/2640621
var observer = new MutationObserver(function() {
  if (document.body) {
    overwriteAC();
    observer.disconnect();
  }
});
observer.observe(document.documentElement, {childList: true});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.