Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Ad-blocker-blocker on The Atlantic #6291

Closed
jonathansampson opened this issue Dec 18, 2016 · 4 comments
Closed

Ad-blocker-blocker on The Atlantic #6291

jonathansampson opened this issue Dec 18, 2016 · 4 comments

Comments

@jonathansampson
Copy link
Collaborator

jonathansampson commented Dec 18, 2016

Test plan

#8715 (comment)


Did you search for similar issues before submitting this one?
Yes

Describe the issue you encountered:
theatlantic.com forwards users of Brave to https://www.theatlantic.com/please-support-us/.

Expected behavior:
Users of Brave should be able to browse the web uninterrupted.

Brave Version: 0.12.15

Steps to reproduce:

  1. Navigate to https://www.theatlantic.com/
  2. Click article displayed most prominently on frontpage
  3. Wait a few seconds after the page loads
  4. Note the redirection to /please-support-us/

Screenshot if needed:
image

@jonathansampson jonathansampson added feature/adblock needs-investigation A bug not 100% confirmed/fixed that needs QA to better audit. labels Dec 18, 2016
@jonathansampson jonathansampson added this to the 0.13.1 milestone Dec 18, 2016
@bridiver
Copy link
Collaborator

redirects are super easy to block, but I'm not able to replicate this on master.

@jonathansampson
Copy link
Collaborator Author

Mentioned by a user on Twitter: https://twitter.com/CasinelliG/status/821189349655998464

@jonathansampson
Copy link
Collaborator Author

jonathansampson commented Jan 17, 2017

Here's the blocker-blocker:

    /**
     * Route blockers
     */
     (function(){
        function redirect() {

            // Chrome 54-57 has a bug with its extensions that breaks
            // whitelisting on the first pageview when sent through
            // a shortened url. We can't detect shorturls reliable,
            // so let it slide.
            var chromeFreePV = (function(){
                var host = window.location.protocol + "//" + window.location.host;
                var isFirstPV = (document.referrer.indexOf(host) !== 0);
                var isChrome = (window.navigator.userAgent.match(/Chrome\//) !== null);
                return isFirstPV && isChrome;
            })();

            var isCrawlser = (function(){
                var botsRe = "(Googlebot|Bingbot|Yahoo! Slurp|DuckDuckBot|facebookexternalhit)";
                return (window.navigator.userAgent.match(botsRe) !== null);
            }());

            if ((navigator.onLine === false) ||
                isCrawlser ||
                chromeFreePV ||
                Atlantic.User.isAdFree({strict: false}) ||
                Atlantic.Utils.readCookie("seen-blocker-wall")) {
                    return;
            }
            var next = encodeURIComponent(window.location.href);
            var url = window.location.protocol + "//" + window.location.host + "/please-support-us/?next=";
            window.location.href = url + next;
        };

        // Prevent race condition
        if (Modernizr["blocker-enabled"]) {
            redirect();
        } else {
            $(window).one("blocker-detected", redirect);
        }
     })();

It doesn't look like the Modernizr route is being used. There are, however, several triggers for the blocker-detected event in cdn.theatlantic.com/assets/static/b/advertising/ads.js:

    /**
     * When ad blocking is detected two things happen:
     *  1. The class `mdzr-no-blocker-enabled` is replaced with
     *     `mdzr-blocker-enabled` on <html />
     *  2. A trigger for "blocker-detected" is called
     */
    blockerDetection: function() {

        // If the honeypot is blocked, we know
        // immediately that ads are blocked.
        // If it's not, we're not really sure.

        var has_analytics = undefined;
        var has_ads = undefined;
        var has_adfree = this.isAdFree;
        var self = this;

        var detectAds = new $.Deferred(function(){
            var promise = this;

            // Adfree users don't need to check anything.
            if (has_adfree) {
                has_ads = false;
                promise.resolve();
                return;
            }

            if (!window.ads_enabled) {
                has_ads = false;
                promise.resolve();
            }

            $(window).on("ad-loaded, ad-empty", function(){
                has_ads = true;
                promise.resolve();
            });

            // Some scripts detect blockers on error.
            $(window).one("blocker-detected", function(){
                has_ads = false;
                promise.resolve();
            });

            // Check for evil CSS, which may be loaded
            // asynonchronously.
            setTimeout(function(){
                var div = document.createElement("div");
                div.setAttribute("style", "visibility:hidden; width: 5px; height: 5px;\
                     position: absolute; top:-5px; left:-5px");
                div.className = "ad advertisement sponsored";
                document.body.appendChild(div);
                if (getComputedStyle(div).display === "none") {
                    $(window).trigger("blocker-detected");
                }
            }, 500);

            // Check the honeypot.
            // The honeypot is also called on the page, but since whitelisting
            // isn't synchronous, we can't trust the value we send to omniture.
            // The call should be incredibly fast (cached) or blocked right away,
            // so the performance penalty is moot.
            $.ajax({
                url: Atlantic.STATIC_URL + "js/advertisement.2.js",
                dataType: "script",
                cache: true
            }).fail(function(){
                $(window).trigger("blocker-detected");
            });

            // Delayed check to catch more clever blockers
            // if it's still ambiguous.
            window.setTimeout(function(){

                // If we've already decided whether
                // ads load, or if the user is offline, stop here.
                if (this.state() === "resolved" || navigator.onLine === false) {
                    return;
                }

                self.log("No ads. Smart blocker detection kicking in.");

                // Ain't you clever.
                if (googletag.display && googletag.display.toString() === "function (){}") {
                    $(window).trigger("blocker-detected");
                }

                // For Privacy Badger
                if (googletag.display && googletag.display.name.trim() === "bound") {
                    $(window).trigger("blocker-detected");
                }

                if (googletag.display && googletag.display.name === "noopfn") {
                    $(window).trigger("blocker-detected");
                };

                // If GPT never loaded, try again.
                // We're not sure if this is a spotty connection
                // or an adblocker. Try again but rely on other clues.
                if (googletag._loadStarted_ === undefined) {
                    $.ajax({
                        url: "https://www.googletagservices.com/tag/js/gpt.js",
                        dataType: "script",
                        cache: true
                    });
                };

                // This is a bad request. However, some blockers will patch
                // in a fake image, so if it loads, ads are being blocked.
                var url = "https://securepubads.g.doubleclick.net/gampad/ads";
                var img = document.createElement("img");
                img.src = url;
                img.style = "visibility: hidden";
                img.onload = function(){
                    $(window).trigger("blocker-detected");
                };
                document.body.appendChild(img);
            }.bind(promise), 8000);

        });

        var detectAnalytics = new $.Deferred(function(){
            // Because omniture users keep the script on their own
            // servers, blocking it requires a wildcard.
            has_analytics = (window.has_omniture === true);
            this.resolve();
        });

        /**
         * When ads are confirmed, set the correct
         * classes/Modernizr values and record ja pixel.
         */
        $.when(detectAds, detectAnalytics).then(function(){
            Modernizr["blocker-enabled"] = !has_ads;
            if (has_ads === false) {
                $("html").removeClass("mdzr-no-blocker-enabled").addClass("mdzr-blocker-enabled");
                Atlantic.Utils.createCookie("had-blocker", 1, 30);
            }

            // Detective settings are required
            if (!this.options.detective && !this.options.detective.url) {
                console.error("gpt-config.detective.url needs to be set to record data.");
            }

            var has_whitelist = !!(has_ads && Atlantic.Utils.readCookie("had-blocker"));

            var img = document.createElement("img");
            img.src = (this.options.detective.url +
                '?knowledge=' + has_analytics +
                '&revenue=' + has_ads +
                '&paying=' + has_adfree +
                '&white=' + has_whitelist +
                '&cachebuster=' + Date.now());

            // Track the time if we know it
            if (has_ads) {
                var loadtime = this.loadtime;
                img.src += "&time=" + loadtime;
                window.optimizely.push(["trackEvent", "ad_supported_pageview"]);
            } else {
                window.optimizely.push(["trackEvent", "ad_blocked_pageview"]);
            }

            img.setAttribute("style",
                "position: absolute; top: -1px; left: -1px; " +
                "width:0; height:0; visibility:hidden;");
            document.body.appendChild(img);
        }.bind(this));
    }

@bridiver
Copy link
Collaborator

we can just block this window.location.protocol + "//" + window.location.host + "/please-support-us/?next= in site hacks

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.