Left: | ||
Right: |
OLD | NEW |
---|---|
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 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
344 if (style.parentNode != parentNode) | 344 if (style.parentNode != parentNode) |
345 parentNode.appendChild(style); | 345 parentNode.appendChild(style); |
346 }); | 346 }); |
347 | 347 |
348 observer.observe(parentNode, {childList: true}); | 348 observer.observe(parentNode, {childList: true}); |
349 return observer; | 349 return observer; |
350 } | 350 } |
351 | 351 |
352 function protectStyleSheet(document, style) | 352 function protectStyleSheet(document, style) |
353 { | 353 { |
354 var id = Math.random().toString(36).substr(2) | 354 var id = Math.random().toString(36).substr(2); |
355 style.id = id; | 355 style.id = id; |
356 | 356 |
357 var code = [ | 357 var code = [ |
358 "(function()", | 358 "(function()", |
359 "{", | 359 "{", |
360 ' var style = document.getElementById("' + id + '") ||', | 360 ' var style = document.getElementById("' + id + '") ||', |
361 ' document.documentElement.shadowRoot.getElementById("' + id + '");', | 361 ' document.documentElement.shadowRoot.getElementById("' + id + '");', |
362 ' style.removeAttribute("id");' | 362 ' style.removeAttribute("id");' |
363 ]; | 363 ]; |
364 | 364 |
(...skipping 22 matching lines...) Expand all Loading... | |
387 | 387 |
388 code.push("})();"); | 388 code.push("})();"); |
389 | 389 |
390 var script = document.createElement("script"); | 390 var script = document.createElement("script"); |
391 script.async = false; | 391 script.async = false; |
392 script.textContent = code.join("\n"); | 392 script.textContent = code.join("\n"); |
393 document.documentElement.appendChild(script); | 393 document.documentElement.appendChild(script); |
394 document.documentElement.removeChild(script); | 394 document.documentElement.removeChild(script); |
395 } | 395 } |
396 | 396 |
397 // 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 | |
399 // us. As a workaround we wrap WebSocket, closing connections that would have | |
400 // otherwise been blocked. | |
401 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=129353 | |
402 function wrapWebSocket() | |
403 { | |
404 if (typeof WebSocket == "undefined") | |
405 return; | |
406 | |
407 var eventName = "abpws-" + Math.random().toString().substr(2); | |
408 | |
409 document.addEventListener(eventName, function(event) | |
410 { | |
411 ext.backgroundPage.sendMessage({ | |
412 type: "websocket-request", | |
413 url: event.detail.url | |
414 }, function (block) | |
415 { | |
416 document.dispatchEvent( | |
417 new CustomEvent(eventName + "-" + event.detail.url, {detail: block}) | |
418 ); | |
419 }); | |
420 }); | |
421 | |
422 function wrapper(eventName) | |
423 { | |
424 var originalWebSocket = WebSocket; | |
425 var readyStates = { | |
426 CLOSED: {value: 3, enumerable: true}, | |
427 CLOSING: {value: 2, enumerable: true}, | |
428 OPEN: {value: 1, enumerable: true}, | |
429 CONNECTING: {value: 0, enumerable: true} | |
430 }; | |
431 | |
432 WebSocket = function(url, protocol) | |
433 { | |
434 var websocket = new originalWebSocket(url, protocol); | |
435 var properties = Object.create(null); | |
436 | |
437 function getSet(key) | |
438 { | |
439 return {get: function() { return websocket[key]; }, | |
440 set: function(value) { return websocket[key] = value; }, | |
441 enumerable: true}; | |
442 } | |
443 function funcWrap(key) | |
444 { | |
445 return {value: function() { websocket[key].apply(websocket, arguments); }, | |
446 enumerable: true}; | |
447 } | |
448 | |
449 var key; | |
450 for (key of ["close", "send", "addEventListener", "removeEventListener"]) | |
Sebastian Noack
2016/06/28 16:17:51
Is this script processed with jsHydra? It seems no
kzar
2016/06/29 13:40:30
Acknowledged.
| |
451 properties[key] = funcWrap(key); | |
452 for (key of ["url", "protocol", "readyState", "extensions", "bufferedAmoun t", | |
453 "binaryType", "onopen", "onclose", "onerror", "onmessage"]) | |
454 properties[key] = getSet(key); | |
455 | |
456 Object.defineProperties(this, properties); | |
457 | |
458 var incomingEventName = eventName + "-" + url; | |
459 function listener(event) | |
460 { | |
461 if (event.detail) | |
462 websocket.close(); | |
Sebastian Noack
2016/06/28 16:17:51
As Lain pointed out, this approach allows WebSocke
kzar
2016/06/28 16:32:40
I actually tested this with WireShark and I found
Sebastian Noack
2016/06/28 17:04:58
I have two concerns here:
1. It might be a potent
kzar
2016/06/29 13:40:31
OK, done.
| |
463 | |
464 document.removeEventListener(incomingEventName, listener); | |
465 } | |
466 document.addEventListener(incomingEventName, listener); | |
467 | |
468 document.dispatchEvent(new CustomEvent(eventName, { | |
469 detail: {url: url, protocol: protocol} | |
470 })); | |
471 }; | |
472 WebSocket.prototype = Object.create(window.EventTarget.prototype, readyState s); | |
473 Object.defineProperties(WebSocket, readyStates); | |
474 | |
475 var script = document.currentScript; | |
476 script.parentNode.removeChild(script); | |
477 } | |
478 | |
479 var script = document.createElement("script"); | |
480 script.textContent = "(" + wrapper.toString() + ")(\"" + eventName + "\");"; | |
Sebastian Noack
2016/06/28 16:17:51
Ideally, we inject only one script. Note that we a
kzar
2016/06/29 13:40:30
Done.
| |
481 document.documentElement.appendChild(script); | |
482 } | |
483 | |
397 function init(document) | 484 function init(document) |
398 { | 485 { |
399 var shadow = null; | 486 var shadow = null; |
400 var style = null; | 487 var style = null; |
401 var observer = null; | 488 var observer = null; |
402 var tracer = null; | 489 var tracer = null; |
403 | 490 |
491 wrapWebSocket(); | |
492 | |
404 function getPropertyFilters(callback) | 493 function getPropertyFilters(callback) |
405 { | 494 { |
406 ext.backgroundPage.sendMessage({ | 495 ext.backgroundPage.sendMessage({ |
407 type: "filters.get", | 496 type: "filters.get", |
408 what: "cssproperties" | 497 what: "cssproperties" |
409 }, callback); | 498 }, callback); |
410 } | 499 } |
411 var propertyFilters = new CSSPropertyFilters(window, getPropertyFilters, | 500 var propertyFilters = new CSSPropertyFilters(window, getPropertyFilters, |
412 addElemHideSelectors); | 501 addElemHideSelectors); |
413 | 502 |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
564 }, true); | 653 }, true); |
565 | 654 |
566 return updateStylesheet; | 655 return updateStylesheet; |
567 } | 656 } |
568 | 657 |
569 if (document instanceof HTMLDocument) | 658 if (document instanceof HTMLDocument) |
570 { | 659 { |
571 checkSitekey(); | 660 checkSitekey(); |
572 window.updateStylesheet = init(document); | 661 window.updateStylesheet = init(document); |
573 } | 662 } |
OLD | NEW |