Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: include.preload.js

Issue 29347034: Issue 1727 - Prevent circumvention via WebSocket (Closed)
Patch Set: Created June 26, 2016, 11:55 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« background.js ('K') | « background.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« background.js ('K') | « background.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld