WebSuckIt!

Ugh, these Webs these Sockets... Nobody need them.

Versión del día 25/09/2016. Echa un vistazo a la versión más reciente.

// ==UserScript==
// @name         WebSuckIt!
// @namespace    lainscripts_websuckit
// @version      2016-09-25:2
// @description  Ugh, these Webs these Sockets... Nobody need them.
// @author       lainverse
// @match        *://*/*
// @grant        unsafeWindow
// @run-at       document-start
// ==/UserScript==
(function() {
    'use strict';

    // check does browser support Proxy and WebSocket
    if (typeof Proxy !== 'function' ||
        typeof WebSocket !== 'function') {
        return;
    }

    function getWrappedCode(removeSelf) {
        var text = getWrappedCode.toString()+WSI.toString();
        text = (
            '(function(){"use strict";'+
            text.replace(/\/\/[^\r\n]*/g,'').replace(/[\s\r\n]+/g,' ')+
            '(new WSI(self||window)).init();'+
            '})();'+
            (removeSelf?'var s = document.currentScript; if (s) {s.parentNode.removeChild(s);}':'')
        );
        return text;
    }

    function WSI(win, safeWin) {
        safeWin = safeWin || win;
        var masks = [], filter;
        for (filter of [// blacklist
            '||24video.xxx^',
            '||adlabs.ru^',
            '||bgrndi.com^',
            '||brokeloy.com^',
            '||cnamerutor.ru^',
            '||docfilms.info^',
            '||dreadfula.ru^',
            '||et-code.ru^',
            '||free-torrent.org^',
            '||free-torrent.pw^',
            '||free-torrents.org^',
            '||free-torrents.pw^',
            '||game-torrent.info^',
            '||gocdn.ru^',
            '||hdkinoshka.com^',
            '||hghit.com^',
            '||kinotochka.net^',
            '||kuveres.com^',
            '||lepubs.com^',
            '||luxadv.com^',
            '||luxup.ru^',
            '||mail.ru^',
            '||marketgid.com^',
            '||mxtads.com^',
            '||oconner.biz^',
            '||abbp1.website',
            '||psma01.com^',
            '||psma02.com^',
            '||psma03.com^',
            '||recreativ.ru^',
            '||regpole.com^',
            '||ruttwind.com^',
            '||skidl.ru^',
            '||torvind.com^',
            '||trafmag.com^',
            '||xxuhter.ru^',
            '||yuiout.online^'
        ]) {
            masks.push(new RegExp(
                filter.replace(/([\\\/\[\].*+?(){}$])/g, '\\$1')
                .replace(/\^(?!$)/g,'\\.?[^\\w%._-]')
                .replace(/\^$/,'\\.?([^\\w%._-]|$)')
                .replace(/^\|\|/,'^wss?:\\/+([^\/.]+\\.)*'),
                'i'));
        }

        function isBlocked(url) {
            for (var mask of masks) {
                if (mask.test(url)) {
                    return true;
                }
            }
            return false;
        }

        function wsGetter (target, name) {
            try {
                if (typeof realWebSocket.prototype[name] === 'function') {
                    if (name === 'close' || name === 'send') { // send also closes connection
                        target.readyState = realWebSocket.CLOSED;
                    }
                    return (
                        function () {
                            console.log('[WSI] Invoked function "'+name+'"', '| Tracing', (new Error()));
                            return;
                        }
                    );
                }
                if (typeof realWebSocket.prototype[name] === 'number') {
                    return realWebSocket[name];
                }
            } catch(ignore) {}
            return target[name];
        }

        function createWebSocketWrapper(target) {
            var realWebSocket = win.WebSocket;

            return new Proxy(realWebSocket, {
                construct: function (target, args) {
                    var url = args[0];
                    console.log('[WSI] Opening socket on ' + url + ' \u2026');
                    if (isBlocked(url)) {
                        console.log("[WSI] Blocked.");
                        return new Proxy({url: url, readyState: realWebSocket.OPEN}, {
                            get: wsGetter
                        });
                    }
                    return new target(args[0], args[1]);
                }
            });
        }

        function WorkerWrapper() {
            var realWorker = win.Worker;
            function wrappedWorker(resourceURI) {
                var _worker = null,
                    _terminate = false,
                    _onerror = null,
                    _onmessage = null,
                    _messages = [],
                    _events = [],
                    _self = this;

                (new Promise(function(resolve,reject){
                    var xhrLoadEnd = function() {
                        resolve(new realWorker(URL.createObjectURL(
                            new Blob([getWrappedCode(false)+this.result])
                        )));
                    };
                    var xhr = new XMLHttpRequest();
                    xhr.open('GET', resourceURI, true);
                    xhr.responseType = 'blob';
                    xhr.onload = function(){
                        if (this.status === 200) {
                            var reader = new FileReader();
                            reader.addEventListener("loadend", xhrLoadEnd);
                            reader.readAsText(this.response);
                        }
                    };
                    xhr.send();
                })).then(function(val) {
                    _worker = val;
                    _worker.onerror = _onerror;
                    _worker.onmessage = _onmessage;
                    var _e;
                    while(_events.length) {
                        _e = _events.shift();
                        _worker[_e[0]].apply(_worker, _e[1]);
                    }
                    while(_messages.length) {
                        _worker.postMessage(_messages.shift());
                    }
                    if (_terminate) {
                        _worker.terminate();
                    }
                });

                _self.terminate = function(){
                    _terminate = true;
                    if (_worker) {
                        _worker.terminate();
                    }
                };
                Object.defineProperty(_self, 'onmessage', {
                    get:function(){
                        return _onmessage;
                    },
                    set:function(val){
                        _onmessage = val;
                        if (_worker) {
                            _worker.onmessage = val;
                        }
                    }
                });
                Object.defineProperty(_self, 'onerror', {
                    get:function(){
                        return _onerror;
                    },
                    set:function(val){
                        _onerror = val;
                        if (_worker) {
                            _worker.onmessage = val;
                        }
                    }
                });
                _self.postMessage = function(message){
                    if (_worker) {
                        _worker.postMessage(message);
                    } else {
                        _messages.push(message);
                    }
                };
                _self.terminate = function() {
                    _terminate = true;
                    if (_worker) {
                        _worker.terminate();
                    }
                };
                _self.addEventListener = function(){
                    if (_worker) {
                        _worker.addEventListener.apply(_worker, arguments);
                    } else {
                        _events.push(['addEventListener',arguments]);
                    }
                };
                _self.removeEventListener = function(){
                    if (_worker) {
                        _worker.removeEventListener.apply(_worker, arguments);
                    } else {
                        _events.push(['removeEventListener',arguments]);
                    }
                };
            }
            win.Worker = wrappedWorker.bind(safeWin);
        }

        function CreateElementWrapper() {
            var realCreateElement = document.createElement.bind(document),
                code = escape('<scr'+'ipt>'+getWrappedCode(true)+'</scr'+'ipt>');

            function frameRewrite(e) {
                var f = e.target,
                    w = f.contentWindow;
                if (f.src && /^data:text/i.test(f.src) && f.src.indexOf(code) < 0) {
                    f.src = f.src.replace(',',',' + code);
                }
                if (w && w.WebSocket) {
                    w.WebSocket = createWebSocketWrapper();
                }
            }

            function wrappedCreateElement(name) {
                if (name && name.toUpperCase &&
                    name.toUpperCase() === 'IFRAME') {
                    var ifr = realCreateElement.apply(document, arguments);
                    ifr.addEventListener('load', frameRewrite, false);
                    return ifr;
                }
                return realCreateElement.apply(document, arguments);
            }
            document.createElement = wrappedCreateElement.bind(document);

            document.addEventListener('DOMContentLoaded', function(){
                for (var ifr of document.querySelectorAll('IFRAME')) {
                    ifr.addEventListener('load', frameRewrite, false);
                }
            }, false);
        }

        this.init = function() {
            win.WebSocket = createWebSocketWrapper();
            WorkerWrapper();
            if (typeof document !== 'undefined') {
                CreateElementWrapper();
            }
        };
    }

    if (/firefox/i.test(navigator.userAgent)) {
        var script = document.createElement('script');
        script.appendChild(document.createTextNode(getWrappedCode()));
        document.head.insertBefore(script, document.head.firstChild);
        return; //we don't want to call functions on page from here in Fx, so exit
    }

    (new WSI((unsafeWindow||self||window),(self||window))).init();
})();