John
John

Reputation: 21

How can I prevent an anti-adblock script from changing the 'src' attribute of an iframe element asychronously?

A site I visit has this script:

<script type="text/javascript">
        (function () {
            var ca = document.createElement('script');
            ca.type = 'text/javascript';
            ca.async = true;
            var s = document.getElementsByTagName('script')[0];
            ca.src = 'http://serve.popads.net/checkInventory.php';
            ca.onerror = function () {
                setTimeout(function () {
                    $('.embed-player').attr('src', "/adblock.html")
                }, 8000);
            }
            s.parentNode.insertBefore(ca, s);
        })();
    </script>

and another one as follows that is probably related:

        function adBlockDetected() {
            $('#block').modal({
                'backdrop': 'static',
                'keyboard': false,
            })
        }
        if (window.canRunAds === undefined) {
            adBlockDetected()
        }

I'm trying to see the content inside an iframe:

<iframe src="https://example.com" frameborder="0" class="embed-player" scrolling="no" allowfullscreen="true" webkitallowfullscreen="true" mozallowfullscreen="true" rel="nofollow"></iframe>

but the src attribute keeps getting updated asynchronously by the first script above - with a warning message asking me to turn off my adblocker if want to use the site.

I wrote this Tampermonkey script to update the page document in my browser:

(function() {
    'use strict';

    var embedSrc = $('.embed-player').attr('src');

    setTimeout(function () {
        $('.embed-player').attr('src', embedSrc)
    }, 16000);


})();

THIS WORKS! . . . BUT . . .

The problem is that I had to set a very high timeout value of 16000 ms to counteract the 8000 ms value used on the page - because sometimes the page's own async call comes back later than expected.

This leads to the annoyance of having to wait for both async calls to complete before I can view the content of the page.

Is there a more effective approach than the one I'm using?

BTW: I already have Reek's Anti-Adblock Killer Tampermonkey script and UBlock Origin filter installed - but for some reason the script on this site is bypassing that code (I've checked and it works on most other sites). It throws a console error: Execution of script 'Anti-Adblock Killer | Reek' failed! Cannot assign to read only property 'adblock2' of object '#<Window>'

Upvotes: 1

Views: 2956

Answers (2)

greiner
greiner

Reputation: 596

Instead of working around the symptom, I'd suggest fixing what's causing it to change the attribute.

The request for "checkInventory.php" appears to merely be used as bait in this case. So what you could do is simply add the exception rule @@||serve.popads.net/checkInventory.php^ to your ad blocker so that the error doesn't occur in the first place.

Upvotes: -1

Oriol
Oriol

Reputation: 288620

There are several ways to hijack that code before it runs.

For example, you can prevent setting onerror properties on script elements:

Object.defineProperty(HTMLScriptElement.prototype, 'onerror', {
  setter: function() {}
});

If you don't want to affect other scripts,

var onerror = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'onerror');
Object.defineProperty(HTMLScriptElement.prototype, 'onerror', {
  get: onerror.get,
  setter: function() {
    if(this.src !== 'http://serve.popads.net/checkInventory.php') {
      return onerror.set.apply(this, arguments);
    }
  }
});

Or you could add a capture event listener which prevents the event from reaching the script

document.addEventListener('error', function(e) {
  if(e.target.tagName.toLowerCase() === 'script' &&
     e.target.src === 'http://serve.popads.net/checkInventory.php'
  ) {
    e.stopPropagation();
  }
}, true);

You could also hijack $.fn.attr to prevent it from changing src to "/adblock.html":

var $attr = $.fn.attr;
$.fn.attr = function(attr, value) {
  if(attr === "src" && value === "/adblock.html") {
    return this;
  }
  return $attr.apply(this, arguments);
}

If your code runs after the code you want to hijack, as Bergi says it might be simpler to remove the event handler:

iframe.onerror = null;

Upvotes: 4

Related Questions