| LEFT | RIGHT | 
|    1 /* |    1 /* | 
|    2  * This file is part of Adblock Plus <https://adblockplus.org/>, |    2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
|    3  * Copyright (C) 2006-2016 Eyeo GmbH |    3  * Copyright (C) 2006-2016 Eyeo GmbH | 
|    4  * |    4  * | 
|    5  * Adblock Plus is free software: you can redistribute it and/or modify |    5  * Adblock Plus is free software: you can redistribute it and/or modify | 
|    6  * it under the terms of the GNU General Public License version 3 as |    6  * it under the terms of the GNU General Public License version 3 as | 
|    7  * published by the Free Software Foundation. |    7  * published by the Free Software Foundation. | 
|    8  * |    8  * | 
|    9  * Adblock Plus is distributed in the hope that it will be useful, |    9  * Adblock Plus is distributed in the hope that it will be useful, | 
|   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of |   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  348  |  348  | 
|  349   observer.observe(parentNode, {childList: true}); |  349   observer.observe(parentNode, {childList: true}); | 
|  350   return observer; |  350   return observer; | 
|  351 } |  351 } | 
|  352  |  352  | 
|  353 function runInPage(fn, arg) |  353 function runInPage(fn, arg) | 
|  354 { |  354 { | 
|  355   var script = document.createElement("script"); |  355   var script = document.createElement("script"); | 
|  356   script.type = "application/javascript"; |  356   script.type = "application/javascript"; | 
|  357   script.async = false; |  357   script.async = false; | 
|  358  |  358   script.textContent = "(" + fn + ")(" + JSON.stringify(arg) + ");"; | 
|  359   // include.youtube.js passes this function a RegExp which JSON.stringify would |  | 
|  360   // convert to "{}". |  | 
|  361   if (!(arg instanceof RegExp)) |  | 
|  362     arg = JSON.stringify(arg); |  | 
|  363  |  | 
|  364   script.textContent = "(" + fn + ")(" + arg + ");"; |  | 
|  365   document.documentElement.appendChild(script); |  359   document.documentElement.appendChild(script); | 
|  366   document.documentElement.removeChild(script); |  360   document.documentElement.removeChild(script); | 
|  367 } |  361 } | 
|  368  |  362  | 
|  369 function protectStyleSheet(document, style) |  363 function protectStyleSheet(document, style) | 
|  370 { |  364 { | 
|  371   style.id = id; |  365   style.id = id; | 
|  372  |  366  | 
|  373   runInPage(function(id) |  367   runInPage(function(id) | 
|  374   { |  368   { | 
|  375     var style = document.getElementById(id) || |  369     var style = document.getElementById(id) || | 
|  376                 document.documentElement.shadowRoot.getElementById(id); |  370                 document.documentElement.shadowRoot.getElementById(id); | 
|  377     style.removeAttribute("id"); |  371     style.removeAttribute("id"); | 
|  378  |  372  | 
|  379     var disableables = [style, style.sheet]; |  373     var disableables = [style, style.sheet]; | 
|  380     for (var i = 0; i < disableables.length; i++) |  374     for (var i = 0; i < disableables.length; i++) | 
|  381       Object.defineProperty(disableables[i], "disabled", |  375       Object.defineProperty(disableables[i], "disabled", | 
|  382                             {value: false, enumerable: true}); |  376                             {value: false, enumerable: true}); | 
|  383  |  377  | 
|  384     var boundCall = Function.prototype.call.bind(Function.prototype.call); |  | 
|  385     ["deleteRule", "removeRule"].forEach(function(method) |  378     ["deleteRule", "removeRule"].forEach(function(method) | 
|  386     { |  379     { | 
|  387       var original = CSSStyleSheet.prototype[method]; |  380       var original = CSSStyleSheet.prototype[method]; | 
|  388       CSSStyleSheet.prototype[method] = function(index) |  381       CSSStyleSheet.prototype[method] = function(index) | 
|  389       { |  382       { | 
|  390         if (this != style.sheet) |  383         if (this != style.sheet) | 
|  391           boundCall(original, this, index); |  384           original.call(this, index); | 
|  392       }; |  385       }; | 
|  393     }); |  386     }); | 
|  394   }, id); |  387   }, id); | 
|  395 } |  388 } | 
|  396  |  389  | 
|  397 // Neither Chrome[1] nor Safari allow us to intercept WebSockets, and therefore |  390 // Neither Chrome[1] nor Safari allow us to intercept WebSockets, and therefore | 
|  398 // some ad networks are misusing them as a way to serve adverts and circumvent |  391 // some ad networks are misusing them as a way to serve adverts and circumvent | 
|  399 // us. As a workaround we wrap WebSocket, preventing blocked WebSocket |  392 // us. As a workaround we wrap WebSocket, preventing blocked WebSocket | 
|  400 // connections from being opened. |  393 // connections from being opened. | 
|  401 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=129353 |  394 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=129353 | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
|  417         new CustomEvent(eventName + "-" + event.detail.url, {detail: block}) |  410         new CustomEvent(eventName + "-" + event.detail.url, {detail: block}) | 
|  418       ); |  411       ); | 
|  419     }); |  412     }); | 
|  420   }); |  413   }); | 
|  421  |  414  | 
|  422   runInPage(function(eventName) |  415   runInPage(function(eventName) | 
|  423   { |  416   { | 
|  424     // As far as possible we must track everything we use that could be |  417     // As far as possible we must track everything we use that could be | 
|  425     // sabotaged by the website later in order to circumvent us. |  418     // sabotaged by the website later in order to circumvent us. | 
|  426     var RealWebSocket = WebSocket; |  419     var RealWebSocket = WebSocket; | 
|  427     var closeWebSocket = RealWebSocket.prototype.close; |  420     var closeWebSocket = Function.prototype.call.bind(RealWebSocket.prototype.cl
     ose); | 
|  428     var addEventListener = document.addEventListener.bind(document); |  421     var addEventListener = document.addEventListener.bind(document); | 
|  429     var removeEventListener = document.removeEventListener.bind(document); |  422     var removeEventListener = document.removeEventListener.bind(document); | 
|  430     var dispatchEvent = document.dispatchEvent.bind(document); |  423     var dispatchEvent = document.dispatchEvent.bind(document); | 
|  431     var CustomEvent = window.CustomEvent; |  424     var CustomEvent = window.CustomEvent; | 
|  432     var boundCall = Function.prototype.call.bind(Function.prototype.call); |  | 
|  433     var functionToString = Function.prototype.toString; |  | 
|  434     // (Safari 9 considers WebSocket to be an object rather than a function.) |  | 
|  435     var webSocketString = RealWebSocket.toString(); |  | 
|  436  |  425  | 
|  437     function checkRequest(url, callback) |  426     function checkRequest(url, callback) | 
|  438     { |  427     { | 
|  439       var incomingEventName = eventName + "-" + url; |  428       var incomingEventName = eventName + "-" + url; | 
|  440       function listener(event) |  429       function listener(event) | 
|  441       { |  430       { | 
|  442         callback(event.detail); |  431         callback(event.detail); | 
|  443         removeEventListener(incomingEventName, listener); |  432         removeEventListener(incomingEventName, listener); | 
|  444       } |  433       } | 
|  445       addEventListener(incomingEventName, listener); |  434       addEventListener(incomingEventName, listener); | 
|  446  |  435  | 
|  447       dispatchEvent(new CustomEvent(eventName, { |  436       dispatchEvent(new CustomEvent(eventName, { | 
|  448         detail: {url: url} |  437         detail: {url: url} | 
|  449       })); |  438       })); | 
|  450     } |  439     } | 
|  451  |  440  | 
|  452     function wrappedToString() |  441     WebSocket = function WrappedWebSocket(url, protocols) | 
|  453     { |  442     { | 
|  454       if (this === WebSocket) |  443       // Throw correct exceptions if the constructor is used improperly. | 
|  455         return webSocketString; |  444       if (!(this instanceof WrappedWebSocket)) return RealWebSocket(); | 
|  456       if (this === wrappedToString) |  445       if (arguments.length < 1) return new RealWebSocket(); | 
|  457         return boundCall(functionToString, functionToString); |  446  | 
|  458       return boundCall(functionToString, this); |  | 
|  459     }; |  | 
|  460     Function.prototype.toString = wrappedToString; |  | 
|  461  |  | 
|  462     WebSocket = function(url, protocols) |  | 
|  463     { |  | 
|  464       var websocket = new RealWebSocket(url, protocols); |  447       var websocket = new RealWebSocket(url, protocols); | 
|  465  |  448  | 
|  466       checkRequest(websocket.url, function(blocked) |  449       checkRequest(websocket.url, function(blocked) | 
|  467       { |  450       { | 
|  468         if (blocked) |  451         if (blocked) | 
|  469           boundCall(closeWebSocket, websocket); |  452           closeWebSocket(websocket); | 
|  470       }); |  453       }); | 
|  471  |  454  | 
|  472       return websocket; |  455       return websocket; | 
|  473     }; |  456     }.bind(); | 
|  474  |  457  | 
|  475     var properties = Object.getOwnPropertyNames(RealWebSocket); |  458     Object.defineProperties(WebSocket, { | 
|  476     for (var i = 0; i < properties.length; i++) |  459       CONNECTING: {value: RealWebSocket.CONNECTING, enumerable: true}, | 
|  477     { |  460       OPEN: {value: RealWebSocket.OPEN, enumerable: true}, | 
|  478       var name = properties[i]; |  461       CLOSING: {value: RealWebSocket.CLOSING, enumerable: true}, | 
|  479       var desc = Object.getOwnPropertyDescriptor(RealWebSocket, name); |  462       CLOSED: {value: RealWebSocket.CLOSED, enumerable: true}, | 
|  480       Object.defineProperty(WebSocket, name, desc); |  463       prototype: {value: RealWebSocket.prototype} | 
|  481     } |  464     }); | 
|  482  |  465  | 
|  483     RealWebSocket.prototype.constructor = WebSocket; |  466     RealWebSocket.prototype.constructor = WebSocket; | 
|  484   }, eventName); |  467   }, eventName); | 
|  485 } |  468 } | 
|  486  |  469  | 
|  487 function init(document) |  470 function init(document) | 
|  488 { |  471 { | 
|  489   var shadow = null; |  472   var shadow = null; | 
|  490   var style = null; |  473   var style = null; | 
|  491   var observer = null; |  474   var observer = null; | 
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  656   }, true); |  639   }, true); | 
|  657  |  640  | 
|  658   return updateStylesheet; |  641   return updateStylesheet; | 
|  659 } |  642 } | 
|  660  |  643  | 
|  661 if (document instanceof HTMLDocument) |  644 if (document instanceof HTMLDocument) | 
|  662 { |  645 { | 
|  663   checkSitekey(); |  646   checkSitekey(); | 
|  664   window.updateStylesheet = init(document); |  647   window.updateStylesheet = init(document); | 
|  665 } |  648 } | 
| LEFT | RIGHT |