| 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 332 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  343   var observer = new MutationObserver(function() |  343   var observer = new MutationObserver(function() | 
|  344   { |  344   { | 
|  345     if (style.parentNode != parentNode) |  345     if (style.parentNode != parentNode) | 
|  346       parentNode.appendChild(style); |  346       parentNode.appendChild(style); | 
|  347   }); |  347   }); | 
|  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 injectJS(f) |  353 function runInPage(fn, arg) | 
|  354 { |  354 { | 
|  355   var args = JSON.stringify(Array.prototype.slice.call(arguments, 1)); |  | 
|  356   args = args.substring(1, args.length - 1); |  | 
|  357   var codeString = "(" + f.toString() + ")(" + args + ");"; |  | 
|  358  |  | 
|  359   var script = document.createElement("script"); |  355   var script = document.createElement("script"); | 
 |  356   script.type = "application/javascript"; | 
|  360   script.async = false; |  357   script.async = false; | 
|  361   script.textContent = codeString; |  358   script.textContent = "(" + fn + ")(" + JSON.stringify(arg) + ");"; | 
|  362   document.documentElement.appendChild(script); |  359   document.documentElement.appendChild(script); | 
|  363   document.documentElement.removeChild(script); |  360   document.documentElement.removeChild(script); | 
|  364 } |  361 } | 
|  365  |  362  | 
|  366 function protectStyleSheet(document, style) |  363 function protectStyleSheet(document, style) | 
|  367 { |  364 { | 
|  368   style.id = id; |  365   style.id = id; | 
|  369  |  366  | 
|  370   var protector = function(id) |  367   runInPage(function(id) | 
|  371   { |  368   { | 
|  372     var style = document.getElementById(id) || |  369     var style = document.getElementById(id) || | 
|  373                 document.documentElement.shadowRoot.getElementById(id); |  370                 document.documentElement.shadowRoot.getElementById(id); | 
|  374     style.removeAttribute("id"); |  371     style.removeAttribute("id"); | 
|  375  |  372  | 
|  376     var i; |  | 
|  377     var disableables = [style, style.sheet]; |  373     var disableables = [style, style.sheet]; | 
|  378     for (i = 0; i < disableables.length; i += 1) |  374     for (var i = 0; i < disableables.length; i++) | 
|  379       Object.defineProperty(disableables[i], "disabled", |  375       Object.defineProperty(disableables[i], "disabled", | 
|  380                             {value: false, enumerable: true}); |  376                             {value: false, enumerable: true}); | 
|  381  |  377  | 
|  382     var methods = ["deleteRule", "removeRule"]; |  378     ["deleteRule", "removeRule"].forEach(function(method) | 
|  383     for (i = 0; i < methods.length; i += 1) |  379     { | 
|  384     { |  380       var original = CSSStyleSheet.prototype[method]; | 
|  385       if (methods[i] in CSSStyleSheet.prototype) |  381       CSSStyleSheet.prototype[method] = function(index) | 
|  386       { |  382       { | 
|  387         (function(method) |  383         if (this != style.sheet) | 
|  388         { |  384           original.call(this, index); | 
|  389           var original = CSSStyleSheet.prototype[method]; |  385       }; | 
|  390           CSSStyleSheet.prototype[method] = function(index) |  386     }); | 
|  391           { |  387   }, id); | 
|  392             if (this != style.sheet) |  | 
|  393               original.call(this, index); |  | 
|  394           }; |  | 
|  395         }(methods[i])); |  | 
|  396       } |  | 
|  397     } |  | 
|  398   }; |  | 
|  399  |  | 
|  400   injectJS(protector, id); |  | 
|  401 } |  388 } | 
|  402  |  389  | 
|  403 // 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 | 
|  404 // 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 | 
|  405 // us. As a workaround we wrap WebSocket, preventing blocked WebSocket |  392 // us. As a workaround we wrap WebSocket, preventing blocked WebSocket | 
|  406 // connections from being opened. |  393 // connections from being opened. | 
|  407 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=129353 |  394 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=129353 | 
|  408 function wrapWebSocket() |  395 function wrapWebSocket() | 
|  409 { |  396 { | 
|  410   if (typeof WebSocket == "undefined") |  397   if (typeof WebSocket == "undefined") | 
|  411     return; |  398     return; | 
|  412  |  399  | 
|  413   var eventName = "abpws-" + id; |  400   var eventName = "abpws-" + id; | 
|  414  |  401  | 
|  415   document.addEventListener(eventName, function(event) |  402   document.addEventListener(eventName, function(event) | 
|  416   { |  403   { | 
|  417     ext.backgroundPage.sendMessage({ |  404     ext.backgroundPage.sendMessage({ | 
|  418       type: "websocket-request", |  405       type: "websocket-request", | 
|  419       url: event.detail.url |  406       url: event.detail.url | 
|  420     }, function (block) |  407     }, function (block) | 
|  421     { |  408     { | 
|  422       document.dispatchEvent( |  409       document.dispatchEvent( | 
|  423         new CustomEvent(eventName + "-" + event.detail.url, {detail: block}) |  410         new CustomEvent(eventName + "-" + event.detail.url, {detail: block}) | 
|  424       ); |  411       ); | 
|  425     }); |  412     }); | 
|  426   }); |  413   }); | 
|  427  |  414  | 
|  428   function wrapper(eventName) |  415   runInPage(function(eventName) | 
|  429   { |  416   { | 
 |  417     // As far as possible we must track everything we use that could be | 
 |  418     // sabotaged by the website later in order to circumvent us. | 
|  430     var RealWebSocket = WebSocket; |  419     var RealWebSocket = WebSocket; | 
|  431  |  420     var closeWebSocket = Function.prototype.call.bind(RealWebSocket.prototype.cl
     ose); | 
|  432     // FIXME - As far as possible we must track everything we use that could be |  421     var addEventListener = document.addEventListener.bind(document); | 
|  433     // sabotaged by the website later in order to circumvent us. |  422     var removeEventListener = document.removeEventListener.bind(document); | 
|  434  |  423     var dispatchEvent = document.dispatchEvent.bind(document); | 
|  435     function checkRequest(url, protocols, callback) |  424     var CustomEvent = window.CustomEvent; | 
 |  425  | 
 |  426     function checkRequest(url, callback) | 
|  436     { |  427     { | 
|  437       var incomingEventName = eventName + "-" + url; |  428       var incomingEventName = eventName + "-" + url; | 
|  438       function listener(event) |  429       function listener(event) | 
|  439       { |  430       { | 
|  440         callback(event.detail); |  431         callback(event.detail); | 
|  441         document.removeEventListener(incomingEventName, listener); |  432         removeEventListener(incomingEventName, listener); | 
|  442       } |  433       } | 
|  443       document.addEventListener(incomingEventName, listener); |  434       addEventListener(incomingEventName, listener); | 
|  444  |  435  | 
|  445       document.dispatchEvent(new CustomEvent(eventName, { |  436       dispatchEvent(new CustomEvent(eventName, { | 
|  446         detail: {url: url, protocols: protocols} |  437         detail: {url: url} | 
|  447       })); |  438       })); | 
|  448     } |  439     } | 
|  449  |  440  | 
|  450     WebSocket = function(url, protocols) |  441     WebSocket = function WrappedWebSocket(url, protocols) | 
|  451     { |  442     { | 
 |  443       // Throw correct exceptions if the constructor is used improperly. | 
 |  444       if (!(this instanceof WrappedWebSocket)) return RealWebSocket(); | 
 |  445       if (arguments.length < 1) return new RealWebSocket(); | 
 |  446  | 
|  452       var websocket = new RealWebSocket(url, protocols); |  447       var websocket = new RealWebSocket(url, protocols); | 
|  453  |  448  | 
|  454       checkRequest(url, protocols, function(blocked) |  449       checkRequest(websocket.url, function(blocked) | 
|  455       { |  450       { | 
|  456         if (blocked) |  451         if (blocked) | 
|  457           websocket.close(); |  452           closeWebSocket(websocket); | 
|  458       }); |  453       }); | 
|  459  |  454  | 
|  460       return websocket; |  455       return websocket; | 
|  461     }; |  456     }.bind(); | 
 |  457  | 
|  462     Object.defineProperties(WebSocket, { |  458     Object.defineProperties(WebSocket, { | 
|  463       CONNECTING: {value: 0, enumerable: true}, |  459       CONNECTING: {value: RealWebSocket.CONNECTING, enumerable: true}, | 
|  464       OPEN: {value: 1, enumerable: true}, |  460       OPEN: {value: RealWebSocket.OPEN, enumerable: true}, | 
|  465       CLOSING: {value: 2, enumerable: true}, |  461       CLOSING: {value: RealWebSocket.CLOSING, enumerable: true}, | 
|  466       CLOSED: {value: 3, enumerable: true} |  462       CLOSED: {value: RealWebSocket.CLOSED, enumerable: true}, | 
 |  463       prototype: {value: RealWebSocket.prototype} | 
|  467     }); |  464     }); | 
|  468     WebSocket.prototype = RealWebSocket.prototype; |  465  | 
|  469     RealWebSocket.prototype.constructor = WebSocket; |  466     RealWebSocket.prototype.constructor = WebSocket; | 
|  470   } |  467   }, eventName); | 
|  471  |  | 
|  472   injectJS(wrapper, eventName); |  | 
|  473 } |  468 } | 
|  474  |  469  | 
|  475 function init(document) |  470 function init(document) | 
|  476 { |  471 { | 
|  477   var shadow = null; |  472   var shadow = null; | 
|  478   var style = null; |  473   var style = null; | 
|  479   var observer = null; |  474   var observer = null; | 
|  480   var tracer = null; |  475   var tracer = null; | 
|  481  |  476  | 
|  482   wrapWebSocket(); |  477   wrapWebSocket(); | 
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  644   }, true); |  639   }, true); | 
|  645  |  640  | 
|  646   return updateStylesheet; |  641   return updateStylesheet; | 
|  647 } |  642 } | 
|  648  |  643  | 
|  649 if (document instanceof HTMLDocument) |  644 if (document instanceof HTMLDocument) | 
|  650 { |  645 { | 
|  651   checkSitekey(); |  646   checkSitekey(); | 
|  652   window.updateStylesheet = init(document); |  647   window.updateStylesheet = init(document); | 
|  653 } |  648 } | 
| LEFT | RIGHT |