// ==UserScript==
// @name WebSuckIt!
// @namespace lainscripts_websuckit
// @version 4.6
// @description Ugh, these Webs these Sockets... Nobody need them.
// @author lainverse
// @match *://*/*
// @grant unsafeWindow
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
var win = unsafeWindow||window;
var scriptText = '';
function WebSocketWrapper() {
// check if the browser supports Proxy and WebSocket
if (typeof Proxy !== 'function' ||
typeof WebSocket !== 'function') {
return;
}
var to_block = [
'||adlabs.ru',
'||bgrndi.com^',
'||brokeloy.com^',
'||dreadfula.ru^',
'||et-code.ru^',
'||free-torrent.org^',
'||free-torrent.pw^',
'||free-torrents.org^',
'||free-torrents.pw^',
'||game-torrent.info^',
'||gocdn.ru^',
'||hghit.com^',
'||kinotochka.net^',
'||kuveres.com^',
'||lepubs.com^',
'||luxup.ru^',
'||mail.ru^',
'||marketgid.com^',
'||mxtads.com^',
'||oconner.biz^',
'||poolnoodle.tech',
'||psma01.com^',
'||psma02.com^',
'||psma03.com^',
'||recreativ.ru^',
'||regpole.com^',
'||skidl.ru^',
'||torvind.com^',
'||trafmag.com^',
'||xxuhter.ru^',
'||yuiout.online^'
];
var masks = [];
to_block.forEach(function(m){
masks.push(new RegExp(
m.replace(/([\\\/\[\].*+?(){}$])/g, '\\$1')
.replace(/\^(?!$)/g,'\\.?[^\\w%._-]')
.replace(/\^$/,'\\.?([^\\w%._-]|$)')
.replace(/^\|\|/,'^wss?:\\/+([^\/.]+\\.)*'),
'i'));
});
var realWS = win.WebSocket,
closingFunctions = ['close', 'send'];
function wsGetter(tgt, nm) {
console.log('[WSI] Registered call to property "', nm, '"');
try {
if (typeof realWS.prototype[nm] === 'function') {
if (closingFunctions.indexOf(nm) > -1) {
tgt.readyState = realWS.CLOSED;
}
return function(){return;};
}
if (typeof realWS.prototype[nm] === 'number') {
return realWS[nm];
}
} catch(ignore) {}
return tgt[nm];
}
win.WebSocket = (new Proxy(realWS, {
construct: function(target, args) {
var url = args[0];
console.log('[WSI] Opening socket on', url, '\u2026');
var i = masks.length;
while(i--) {
if (masks[i].test(url)) {
console.log("[WSI] Blocked.");
return new Proxy({url: url, readyState: realWS.OPEN}, {
get: wsGetter
});
}
}
return new target(args[0], args[1]);
}
}));
}
function WorkerWrapper(){
var wr = win.Worker;
win.Worker = function(resourceURI) {
var _promise = new Promise(function(resolve,reject){
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", function() {
resolve(
new wr(
URL.createObjectURL(
new Blob(['(function(){var win = self;'+
WebSocketWrapper.toString()+
' WebSocketWrapper();})();'+this.result])
)
)
);
});
reader.readAsText(this.response);
}
};
xhr.send();
});
var _worker = null,
_terminate = false,
_onerror = null,
_onmessage = null,
_messages = [],
_events = [];
var setWorker = function(val) {
_worker = val;
_worker.onerror = _onerror;
_worker.onmessage = _onmessage;
if (_terminate) {
_worker.terminate();
}
while(_messages.length) {
_worker.postMessage(_messages.shift());
}
while(_events.length) {
_worker.addEventListener.apply(_worker, _events.pop());
}
};
_promise.then(setWorker);
this.terminate = function(){
_terminate = true;
if (_worker) {
_worker.terminate();
}
};
Object.defineProperty(this, 'onmessage', {
get:function(){
return _onmessage;
},
set:function(val){
_onmessage = val;
if (_worker) {
_worker.onmessage = val;
}
}
});
Object.defineProperty(this, 'onerror', {
get:function(){
return _onerror;
},
set:function(val){
_onerror = val;
if (_worker) {
_worker.onmessage = val;
}
}
});
this.postMessage = function(message){
if (_worker) {
_worker.postMessage(message);
} else {
_messages.push(message);
}
};
this.terminate = function() {
_terminate = true;
if (_worker) {
_worker.terminate();
}
};
this.addEventListener = function(){
if (_worker) {
_worker.addEventListener.apply(_worker, arguments);
} else {
_events.push(arguments);
}
};
this.removeEventListener = function(){
if (_worker) {
_worker.removeEventListener.apply(_worker, arguments);
} // I don't think I should care to remove events here,
// normally it shouldn't be invoked before _worker is created
};
};
}
function CreateElementWrapper() {
var _ce = document.createElement.bind(document),
dataText = /^data:text/i,
key = '"'+Math.random().toString(36).substr(2)+'";',
eskey = escape(key);
document.createElement = function(name, opts) {
if (name && name.toUpperCase &&
name.toUpperCase() === 'IFRAME') {
var ifr = _ce.apply(document, arguments);
ifr.addEventListener('load', function(e) {
var f = e.target;
if(dataText.test(f.src) && f.src.indexOf(eskey) < 0) {
f.src = f.src.replace(',',','+escape('<scr'+'ipt>'+key+scriptText+'</scr'+'ipt>'));
}
},false);
return ifr;
}
return _ce.apply(document, arguments);
};
}
function GenerateScriptText() {
scriptText = '(function(){var win = self||window, scriptText = "";'+
WebSocketWrapper.toString()+
WorkerWrapper.toString()+
CreateElementWrapper.toString()+
GenerateScriptText.toString()+
'GenerateScriptText();'+
'WebSocketWrapper();'+
'WorkerWrapper();'+
'CreateElementWrapper();'+
'})();'+
'var s = document.currentScript; if (s) {s.parentNode.removeChild(s);}';
}
GenerateScriptText();
scriptText = scriptText.replace(/\/\/[^\r\n]*/g,'').replace(/[\s\r\n]+/g,' ');
if (/firefox/i.test(navigator.userAgent)) {
var script = document.createElement('script');
script.appendChild(document.createTextNode(scriptText));
(document.head || document.body || document.documentElement).appendChild(script);
return; //we don't want to call functions on page from here in Fx, so exit
}
WebSocketWrapper();
WorkerWrapper();
CreateElementWrapper();
})();