Scriptlets icon indicating copy to clipboard operation
Scriptlets copied to clipboard

Improve `prevent-setInterval/-setTimeout` — match decimal delay

Open AdamWr opened this issue 3 years ago • 0 comments

Currently if delay is not an integer then we cannot use matchDelay, because it will be not matched.

For example, if there is script like this:

(() => {
  const good = function () {
    alert('good');
  };

  const bad = function () {
    alert('bad');
  };

  setTimeout(good.bind(window), 100);
  setTimeout(good.bind(window), 200);
  setTimeout(bad.bind(window), 300 + Math.random());
})();

and we want to abort only bad alert. Example website - https://output.jsbin.com/todidovoyu

matchCallback cannot be used in this case, because all of these setTimeouts looks like this:

setTimeout(function () { [native code] }, [delay])
Screenshot

image

matchDelay could be used in this case, something like:

#%#//scriptlet('prevent-setTimeout', '[native code]', '300')

but as delay in setTimeout with bad alert is "randomized" then it cannot be used too.

So, I think that it would be nice if delay would be rounded, for example by using Math.floor (in case if delay is a valid number).

Maybe, also it would be a good idea to add ability to (not) match few delays (in case if delay starts with !) like for example:

example.org#%#//scriptlet('prevent-setTimeout', '[native code]', '!100 && !200')

but I'm not sure if it's needed.


Another workaround could be something like this:

(function () {
  const wrapper = (target, thisArg, args) => {
    const originalString = thisArg.toString();
    const result = Reflect.apply(target, thisArg, args);

    result.toString = function () {
      return originalString;
    };

    return result;
  };

  const handler = {
    apply: wrapper
  };
  Function.prototype.bind = new Proxy(Function.prototype.bind, handler);
})();

so instead of function () { [native code] } original function should be returned, but I'm not sure if it's good idea.

AdamWr avatar Sep 22 '22 07:09 AdamWr