| 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-present eyeo GmbH | 3  * Copyright (C) 2006-present 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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 65         contentWindow[eventName] = checkRequest; | 65         contentWindow[eventName] = checkRequest; | 
| 66         contentWindow.eval( | 66         contentWindow.eval( | 
| 67           "(" + injectedToString() + ")('" + eventName + "', true);" | 67           "(" + injectedToString() + ")('" + eventName + "', true);" | 
| 68         ); | 68         ); | 
| 69         delete contentWindow[eventName]; | 69         delete contentWindow[eventName]; | 
| 70       } | 70       } | 
| 71       catch (e) {} | 71       catch (e) {} | 
| 72     } | 72     } | 
| 73   } | 73   } | 
| 74 | 74 | 
| 75   function wrapAPIForIFrame(object, api) | 75   function injectIntoAllFrames() | 
|  | 76   { | 
|  | 77     for (let i = 0; i < window.length; i++) | 
|  | 78       injectIntoContentWindow(window[i]); | 
|  | 79   } | 
|  | 80 | 
|  | 81   function wrapAPIForInjection(object, api, callback) | 
| 76   { | 82   { | 
| 77     let func = object[api]; | 83     let func = object[api]; | 
| 78     object[api] = function(...args) | 84     if (!func || typeof func != "function") | 
| 79     { | 85       return; | 
| 80       let returnValue = func.apply(this, args); | 86     let applyFunc = Function.prototype.apply.bind(func); | 
| 81       for (let i = 0; i < window.length; i++) | 87     Object.defineProperty(object, api, { | 
| 82         injectIntoContentWindow(window[i]); | 88       value(...args) | 
| 83       return returnValue; | 89       { | 
| 84     }; | 90         let returnValue = applyFunc(this, args); | 
| 85   } | 91         callback(returnValue); | 
| 86 | 92         return returnValue; | 
| 87   function wrapPropertyAPIForIFrame(object, api) | 93       } | 
|  | 94     }); | 
|  | 95   } | 
|  | 96 | 
|  | 97   function wrapPropertyAPIForInjection(object, api, method, callback) | 
| 88   { | 98   { | 
| 89     let descriptor = Object.getOwnPropertyDescriptor(object, api); | 99     let descriptor = Object.getOwnPropertyDescriptor(object, api); | 
| 90     wrapAPIForIFrame(descriptor, "set"); | 100     // Apparently HTMLObjectElement.prototype.contentWindow does not exist in | 
|  | 101     // older versions of Chrome such as 42. | 
|  | 102     if (!descriptor) | 
|  | 103       return; | 
|  | 104     wrapAPIForInjection(descriptor, method, callback); | 
| 91     Object.defineProperty(object, api, descriptor); | 105     Object.defineProperty(object, api, descriptor); | 
| 92   } | 106   } | 
| 93 | 107 | 
| 94   wrapAPIForIFrame(Node.prototype, "appendChild"); | 108   wrapAPIForInjection(Node.prototype, "appendChild", injectIntoAllFrames); | 
| 95   wrapAPIForIFrame(Node.prototype, "insertBefore"); | 109   wrapAPIForInjection(Node.prototype, "insertBefore", injectIntoAllFrames); | 
| 96   wrapAPIForIFrame(Node.prototype, "replaceChild"); | 110   wrapAPIForInjection(Node.prototype, "replaceChild", injectIntoAllFrames); | 
| 97 | 111 | 
| 98   wrapPropertyAPIForIFrame(Element.prototype, "innerHTML"); | 112   wrapPropertyAPIForInjection(Element.prototype, | 
| 99 | 113                               "innerHTML", "set", injectIntoAllFrames); | 
| 100   for (let element of [HTMLFrameElement, HTMLIFrameElement, HTMLObjectElement]) | 114 | 
| 101   { | 115   wrapPropertyAPIForInjection(HTMLObjectElement.prototype, | 
| 102     let contentDocumentDesc = Object.getOwnPropertyDescriptor( | 116                               "contentWindow", "get", injectIntoContentWindow); | 
| 103       element.prototype, "contentDocument" | 117   wrapPropertyAPIForInjection( | 
| 104     ); | 118     HTMLObjectElement.prototype, | 
| 105     let contentWindowDesc = Object.getOwnPropertyDescriptor( | 119     "contentDocument", "get", | 
| 106       element.prototype, "contentWindow" | 120     contentDocument => | 
| 107     ); | 121     { | 
| 108 | 122       if (contentDocument) | 
| 109     // Apparently in HTMLObjectElement.prototype.contentWindow does not exist | 123         injectIntoContentWindow(contentDocument.defaultView); | 
| 110     // in older versions of Chrome such as 42. | 124     } | 
| 111     if (!contentWindowDesc) | 125   ); | 
| 112       continue; |  | 
| 113 |  | 
| 114     let getContentDocument = Function.prototype.call.bind( |  | 
| 115       contentDocumentDesc.get |  | 
| 116     ); |  | 
| 117     let getContentWindow = Function.prototype.call.bind( |  | 
| 118       contentWindowDesc.get |  | 
| 119     ); |  | 
| 120 |  | 
| 121     contentWindowDesc.get = function() |  | 
| 122     { |  | 
| 123       let contentWindow = getContentWindow(this); |  | 
| 124       injectIntoContentWindow(contentWindow); |  | 
| 125       return contentWindow; |  | 
| 126     }; |  | 
| 127     contentDocumentDesc.get = function() |  | 
| 128     { |  | 
| 129       injectIntoContentWindow(getContentWindow(this)); |  | 
| 130       return getContentDocument(this); |  | 
| 131     }; |  | 
| 132     Object.defineProperty(element.prototype, "contentWindow", |  | 
| 133                           contentWindowDesc); |  | 
| 134     Object.defineProperty(element.prototype, "contentDocument", |  | 
| 135                           contentDocumentDesc); |  | 
| 136   } |  | 
| 137 | 126 | 
| 138   /* | 127   /* | 
| 139    * Shadow root getter wrapper | 128    * Shadow root getter wrapper | 
| 140    * | 129    * | 
| 141    * After creating our shadowRoot we must wrap the getter to prevent the | 130    * After creating our shadowRoot we must wrap the getter to prevent the | 
| 142    * website from accessing it (#4191, #4298). This is required as a | 131    * website from accessing it (#4191, #4298). This is required as a | 
| 143    * workaround for the lack of user style support in Chrome. | 132    * workaround for the lack of user style support in Chrome. | 
| 144    * See https://bugs.chromium.org/p/chromium/issues/detail?id=632009&desc=2 | 133    * See https://bugs.chromium.org/p/chromium/issues/detail?id=632009&desc=2 | 
| 145    */ | 134    */ | 
| 146   if ("shadowRoot" in Element.prototype) | 135   if ("shadowRoot" in Element.prototype) | 
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 243 | 232 | 
| 244   /* | 233   /* | 
| 245    * RTCPeerConnection wrapper | 234    * RTCPeerConnection wrapper | 
| 246    * | 235    * | 
| 247    * The webRequest API in Chrome does not yet allow the blocking of | 236    * The webRequest API in Chrome does not yet allow the blocking of | 
| 248    * WebRTC connections. | 237    * WebRTC connections. | 
| 249    * See https://bugs.chromium.org/p/chromium/issues/detail?id=707683 | 238    * See https://bugs.chromium.org/p/chromium/issues/detail?id=707683 | 
| 250    */ | 239    */ | 
| 251   let RealRTCPeerConnection = window.RTCPeerConnection || | 240   let RealRTCPeerConnection = window.RTCPeerConnection || | 
| 252                                 window.webkitRTCPeerConnection; | 241                                 window.webkitRTCPeerConnection; | 
| 253   let closeRTCPeerConnection = Function.prototype.call.bind( | 242 | 
| 254     RealRTCPeerConnection.prototype.close | 243   // Firefox has the option (media.peerconnection.enabled) to disable WebRTC | 
| 255   ); | 244   // in which case RealRTCPeerConnection is undefined. | 
| 256   let RealArray = Array; | 245   if (typeof RealRTCPeerConnection != "undefined") | 
| 257   let RealString = String; | 246   { | 
| 258   let {create: createObject, defineProperty} = Object; | 247     let closeRTCPeerConnection = Function.prototype.call.bind( | 
| 259 | 248       RealRTCPeerConnection.prototype.close | 
| 260   function normalizeUrl(url) | 249     ); | 
| 261   { | 250     let RealArray = Array; | 
| 262     if (typeof url != "undefined") | 251     let RealString = String; | 
| 263       return RealString(url); | 252     let {create: createObject, defineProperty} = Object; | 
| 264   } | 253 | 
| 265 | 254     let normalizeUrl = url => | 
| 266   function safeCopyArray(originalArray, transform) | 255     { | 
| 267   { | 256       if (typeof url != "undefined") | 
| 268     if (originalArray == null || typeof originalArray != "object") | 257         return RealString(url); | 
| 269       return originalArray; | 258     }; | 
| 270 | 259 | 
| 271     let safeArray = RealArray(originalArray.length); | 260     let safeCopyArray = (originalArray, transform) => | 
| 272     for (let i = 0; i < safeArray.length; i++) | 261     { | 
| 273     { | 262       if (originalArray == null || typeof originalArray != "object") | 
| 274       defineProperty(safeArray, i, { | 263         return originalArray; | 
|  | 264 | 
|  | 265       let safeArray = RealArray(originalArray.length); | 
|  | 266       for (let i = 0; i < safeArray.length; i++) | 
|  | 267       { | 
|  | 268         defineProperty(safeArray, i, { | 
|  | 269           configurable: false, enumerable: false, writable: false, | 
|  | 270           value: transform(originalArray[i]) | 
|  | 271         }); | 
|  | 272       } | 
|  | 273       defineProperty(safeArray, "length", { | 
| 275         configurable: false, enumerable: false, writable: false, | 274         configurable: false, enumerable: false, writable: false, | 
| 276         value: transform(originalArray[i]) | 275         value: safeArray.length | 
| 277       }); | 276       }); | 
| 278     } | 277       return safeArray; | 
| 279     defineProperty(safeArray, "length", { | 278     }; | 
| 280       configurable: false, enumerable: false, writable: false, | 279 | 
| 281       value: safeArray.length | 280     // It would be much easier to use the .getConfiguration method to obtain | 
| 282     }); | 281     // the normalized and safe configuration from the RTCPeerConnection | 
| 283     return safeArray; | 282     // instance. Unfortunately its not implemented as of Chrome unstable 59. | 
| 284   } | 283     // See https://www.chromestatus.com/feature/5271355306016768 | 
| 285 | 284     let protectConfiguration = configuration => | 
| 286   // It would be much easier to use the .getConfiguration method to obtain | 285     { | 
| 287   // the normalized and safe configuration from the RTCPeerConnection | 286       if (configuration == null || typeof configuration != "object") | 
| 288   // instance. Unfortunately its not implemented as of Chrome unstable 59. | 287         return configuration; | 
| 289   // See https://www.chromestatus.com/feature/5271355306016768 | 288 | 
| 290   function protectConfiguration(configuration) | 289       let iceServers = safeCopyArray( | 
| 291   { | 290         configuration.iceServers, | 
| 292     if (configuration == null || typeof configuration != "object") | 291         iceServer => | 
| 293       return configuration; | 292         { | 
| 294 | 293           let {url, urls} = iceServer; | 
| 295     let iceServers = safeCopyArray( | 294 | 
| 296       configuration.iceServers, | 295           // RTCPeerConnection doesn't iterate through pseudo Arrays of urls. | 
| 297       iceServer => | 296           if (typeof urls != "undefined" && !(urls instanceof RealArray)) | 
| 298       { | 297             urls = [urls]; | 
| 299         let {url, urls} = iceServer; | 298 | 
| 300 | 299           return createObject(iceServer, { | 
| 301         // RTCPeerConnection doesn't iterate through pseudo Arrays of urls. | 300             url: { | 
| 302         if (typeof urls != "undefined" && !(urls instanceof RealArray)) | 301               configurable: false, enumerable: false, writable: false, | 
| 303           urls = [urls]; | 302               value: normalizeUrl(url) | 
| 304 | 303             }, | 
| 305         return createObject(iceServer, { | 304             urls: { | 
| 306           url: { | 305               configurable: false, enumerable: false, writable: false, | 
| 307             configurable: false, enumerable: false, writable: false, | 306               value: safeCopyArray(urls, normalizeUrl) | 
| 308             value: normalizeUrl(url) | 307             } | 
| 309           }, | 308           }); | 
| 310           urls: { | 309         } | 
| 311             configurable: false, enumerable: false, writable: false, | 310       ); | 
| 312             value: safeCopyArray(urls, normalizeUrl) | 311 | 
|  | 312       return createObject(configuration, { | 
|  | 313         iceServers: { | 
|  | 314           configurable: false, enumerable: false, writable: false, | 
|  | 315           value: iceServers | 
|  | 316         } | 
|  | 317       }); | 
|  | 318     }; | 
|  | 319 | 
|  | 320     let checkUrl = (peerconnection, url) => | 
|  | 321     { | 
|  | 322       checkRequest("webrtc", url, blocked => | 
|  | 323       { | 
|  | 324         if (blocked) | 
|  | 325         { | 
|  | 326           // Calling .close() throws if already closed. | 
|  | 327           try | 
|  | 328           { | 
|  | 329             closeRTCPeerConnection(peerconnection); | 
| 313           } | 330           } | 
| 314         }); | 331           catch (e) {} | 
| 315       } | 332         } | 
| 316     ); | 333       }); | 
| 317 | 334     }; | 
| 318     return createObject(configuration, { | 335 | 
| 319       iceServers: { | 336     let checkConfiguration = (peerconnection, configuration) => | 
| 320         configurable: false, enumerable: false, writable: false, | 337     { | 
| 321         value: iceServers | 338       if (configuration && configuration.iceServers) | 
| 322       } | 339       { | 
| 323     }); | 340         for (let i = 0; i < configuration.iceServers.length; i++) | 
| 324   } |  | 
| 325 |  | 
| 326   function checkUrl(peerconnection, url) |  | 
| 327   { |  | 
| 328     checkRequest("webrtc", url, blocked => |  | 
| 329     { |  | 
| 330       if (blocked) |  | 
| 331       { |  | 
| 332         // Calling .close() throws if already closed. |  | 
| 333         try |  | 
| 334         { | 341         { | 
| 335           closeRTCPeerConnection(peerconnection); | 342           let iceServer = configuration.iceServers[i]; | 
| 336         } | 343           if (iceServer) | 
| 337         catch (e) {} |  | 
| 338       } |  | 
| 339     }); |  | 
| 340   } |  | 
| 341 |  | 
| 342   function checkConfiguration(peerconnection, configuration) |  | 
| 343   { |  | 
| 344     if (configuration && configuration.iceServers) |  | 
| 345     { |  | 
| 346       for (let i = 0; i < configuration.iceServers.length; i++) |  | 
| 347       { |  | 
| 348         let iceServer = configuration.iceServers[i]; |  | 
| 349         if (iceServer) |  | 
| 350         { |  | 
| 351           if (iceServer.url) |  | 
| 352             checkUrl(peerconnection, iceServer.url); |  | 
| 353 |  | 
| 354           if (iceServer.urls) |  | 
| 355           { | 344           { | 
| 356             for (let j = 0; j < iceServer.urls.length; j++) | 345             if (iceServer.url) | 
| 357               checkUrl(peerconnection, iceServer.urls[j]); | 346               checkUrl(peerconnection, iceServer.url); | 
|  | 347 | 
|  | 348             if (iceServer.urls) | 
|  | 349             { | 
|  | 350               for (let j = 0; j < iceServer.urls.length; j++) | 
|  | 351                 checkUrl(peerconnection, iceServer.urls[j]); | 
|  | 352             } | 
| 358           } | 353           } | 
| 359         } | 354         } | 
| 360       } | 355       } | 
|  | 356     }; | 
|  | 357 | 
|  | 358     // Chrome unstable (tested with 59) has already implemented | 
|  | 359     // setConfiguration, so we need to wrap that if it exists too. | 
|  | 360     // https://www.chromestatus.com/feature/5596193748942848 | 
|  | 361     if (RealRTCPeerConnection.prototype.setConfiguration) | 
|  | 362     { | 
|  | 363       let realSetConfiguration = Function.prototype.call.bind( | 
|  | 364         RealRTCPeerConnection.prototype.setConfiguration | 
|  | 365       ); | 
|  | 366 | 
|  | 367       RealRTCPeerConnection.prototype.setConfiguration = function(configuration) | 
|  | 368       { | 
|  | 369         configuration = protectConfiguration(configuration); | 
|  | 370 | 
|  | 371         // Call the real method first, so that validates the configuration for | 
|  | 372         // us. Also we might as well since checkRequest is asynchronous anyway. | 
|  | 373         realSetConfiguration(this, configuration); | 
|  | 374         checkConfiguration(this, configuration); | 
|  | 375       }; | 
| 361     } | 376     } | 
| 362   } | 377 | 
| 363 | 378     let WrappedRTCPeerConnection = function(...args) | 
| 364   // Chrome unstable (tested with 59) has already implemented | 379     { | 
| 365   // setConfiguration, so we need to wrap that if it exists too. | 380       if (!(this instanceof WrappedRTCPeerConnection)) | 
| 366   // https://www.chromestatus.com/feature/5596193748942848 | 381         return RealRTCPeerConnection(); | 
| 367   if (RealRTCPeerConnection.prototype.setConfiguration) | 382 | 
| 368   { | 383       let configuration = protectConfiguration(args[0]); | 
| 369     let realSetConfiguration = Function.prototype.call.bind( | 384 | 
| 370       RealRTCPeerConnection.prototype.setConfiguration | 385       // Since the old webkitRTCPeerConnection constructor takes an optional | 
| 371     ); | 386       // second argument we need to take care to pass that through. Necessary | 
| 372 | 387       // for older versions of Chrome such as 49. | 
| 373     RealRTCPeerConnection.prototype.setConfiguration = function(configuration) | 388       let constraints = undefined; | 
| 374     { | 389       if (args.length > 1) | 
| 375       configuration = protectConfiguration(configuration); | 390         constraints = args[1]; | 
| 376 | 391 | 
| 377       // Call the real method first, so that validates the configuration for | 392       let peerconnection = new RealRTCPeerConnection(configuration, | 
| 378       // us. Also we might as well since checkRequest is asynchronous anyway. | 393                                                      constraints); | 
| 379       realSetConfiguration(this, configuration); | 394       checkConfiguration(peerconnection, configuration); | 
| 380       checkConfiguration(this, configuration); | 395       return peerconnection; | 
| 381     }; | 396     }; | 
| 382   } | 397 | 
| 383 | 398     WrappedRTCPeerConnection.prototype = RealRTCPeerConnection.prototype; | 
| 384   function WrappedRTCPeerConnection(...args) | 399 | 
| 385   { | 400     let boundWrappedRTCPeerConnection = WrappedRTCPeerConnection.bind(); | 
| 386     if (!(this instanceof WrappedRTCPeerConnection)) | 401     copyProperties(RealRTCPeerConnection, boundWrappedRTCPeerConnection, | 
| 387       return RealRTCPeerConnection(); | 402                    ["generateCertificate", "name", "prototype"]); | 
| 388 | 403     RealRTCPeerConnection.prototype.constructor = boundWrappedRTCPeerConnection; | 
| 389     let configuration = protectConfiguration(args[0]); | 404 | 
| 390 | 405     if ("RTCPeerConnection" in window) | 
| 391     // Since the old webkitRTCPeerConnection constructor takes an optional | 406       window.RTCPeerConnection = boundWrappedRTCPeerConnection; | 
| 392     // second argument we need to take care to pass that through. Necessary | 407     if ("webkitRTCPeerConnection" in window) | 
| 393     // for older versions of Chrome such as 49. | 408       window.webkitRTCPeerConnection = boundWrappedRTCPeerConnection; | 
| 394     let constraints = undefined; | 409   } | 
| 395     if (args.length > 1) |  | 
| 396       constraints = args[1]; |  | 
| 397 |  | 
| 398     let peerconnection = new RealRTCPeerConnection(configuration, constraints); |  | 
| 399     checkConfiguration(peerconnection, configuration); |  | 
| 400     return peerconnection; |  | 
| 401   } |  | 
| 402 |  | 
| 403   WrappedRTCPeerConnection.prototype = RealRTCPeerConnection.prototype; |  | 
| 404 |  | 
| 405   let boundWrappedRTCPeerConnection = WrappedRTCPeerConnection.bind(); |  | 
| 406   copyProperties(RealRTCPeerConnection, boundWrappedRTCPeerConnection, |  | 
| 407                  ["generateCertificate", "name", "prototype"]); |  | 
| 408   RealRTCPeerConnection.prototype.constructor = boundWrappedRTCPeerConnection; |  | 
| 409 |  | 
| 410   if ("RTCPeerConnection" in window) |  | 
| 411     window.RTCPeerConnection = boundWrappedRTCPeerConnection; |  | 
| 412   if ("webkitRTCPeerConnection" in window) |  | 
| 413     window.webkitRTCPeerConnection = boundWrappedRTCPeerConnection; |  | 
| 414 } | 410 } | 
| 415 | 411 | 
| 416 if (document instanceof HTMLDocument) | 412 if (document instanceof HTMLDocument) | 
| 417 { | 413 { | 
| 418   let sandbox = window.frameElement && | 414   let sandbox = window.frameElement && | 
| 419                 window.frameElement.getAttribute("sandbox"); | 415                 window.frameElement.getAttribute("sandbox"); | 
| 420 | 416 | 
| 421   if (typeof sandbox != "string" || /(^|\s)allow-scripts(\s|$)/i.test(sandbox)) | 417   if (typeof sandbox != "string" || /(^|\s)allow-scripts(\s|$)/i.test(sandbox)) | 
| 422   { | 418   { | 
| 423     let script = document.createElement("script"); | 419     let script = document.createElement("script"); | 
| 424     script.type = "application/javascript"; | 420     script.type = "application/javascript"; | 
| 425     script.async = false; | 421     script.async = false; | 
| 426     script.textContent = "(" + injected + ")('" + randomEventName + "');"; | 422     // Firefox 58 only bypasses site CSPs when assigning to 'src'. | 
|  | 423     let url = URL.createObjectURL(new Blob([ | 
|  | 424       "(" + injected + ")('" + randomEventName + "');" | 
|  | 425     ])); | 
|  | 426     script.src = url; | 
| 427     document.documentElement.appendChild(script); | 427     document.documentElement.appendChild(script); | 
| 428     document.documentElement.removeChild(script); | 428     document.documentElement.removeChild(script); | 
|  | 429     URL.revokeObjectURL(url); | 
| 429   } | 430   } | 
| 430 } | 431 } | 
| LEFT | RIGHT | 
|---|