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

Delta Between Two Patch Sets: lib/content/snippets.js

Issue 29886700: Issue 6969 - Implement abort-on-property-read snippet (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Left Patch Set: eslint fixes Created Sept. 20, 2018, 10:26 p.m.
Right Patch Set: Another round of changes Created Oct. 31, 2018, 8:43 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 */ 45 */
46 function toRegExp(pattern) 46 function toRegExp(pattern)
47 { 47 {
48 if (pattern.length >= 2 && pattern[0] == "/" && 48 if (pattern.length >= 2 && pattern[0] == "/" &&
49 pattern[pattern.length - 1] == "/") 49 pattern[pattern.length - 1] == "/")
50 { 50 {
51 return new RegExp(pattern.substring(1, pattern.length - 1)); 51 return new RegExp(pattern.substring(1, pattern.length - 1));
52 } 52 }
53 53
54 return new RegExp(regexEscape(pattern)); 54 return new RegExp(regexEscape(pattern));
55 }
56
57 /**
58 * Returns the value of the <code>cssText</code> property of the object
59 * returned by <code>getComputedStyle</code> for the given element. If the
60 * value of the <code>cssText</code> property is blank, this function computes
61 * the value out of the properties available in the object.
62 *
63 * @param {Element} element The element for which to get the computed CSS text.
64 *
65 * @returns {string} The computed CSS text.
66 */
67 function getComputedCSSText(element)
68 {
69 let style = getComputedStyle(element);
70 let {cssText} = style;
71
72 if (cssText)
73 return cssText;
74
75 for (let property of style)
76 cssText += `${property}: ${style[property]}; `;
77
78 return cssText.trim();
55 } 79 }
56 80
57 /** 81 /**
58 * Injects JavaScript code into the document using a temporary 82 * Injects JavaScript code into the document using a temporary
59 * <code>script</code> element. 83 * <code>script</code> element.
60 * 84 *
61 * @param {string} code The code to inject. 85 * @param {string} code The code to inject.
62 * @param {Array.<function|string>} [dependencies] A list of dependencies 86 * @param {Array.<function|string>} [dependencies] A list of dependencies
63 * to inject along with the code. A dependency may be either a function or a 87 * to inject along with the code. A dependency may be either a function or a
64 * string containing some executable code. 88 * string containing some executable code.
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 384
361 let styleRegExp = style ? toRegExp(style) : null; 385 let styleRegExp = style ? toRegExp(style) : null;
362 let searchStyleRegExp = searchStyle ? toRegExp(searchStyle) : null; 386 let searchStyleRegExp = searchStyle ? toRegExp(searchStyle) : null;
363 387
364 new MutationObserver(() => 388 new MutationObserver(() =>
365 { 389 {
366 for (let element of document.querySelectorAll(searchSelector)) 390 for (let element of document.querySelectorAll(searchSelector))
367 { 391 {
368 if (searchRegExp.test(element.textContent) && 392 if (searchRegExp.test(element.textContent) &&
369 (!searchStyleRegExp || 393 (!searchStyleRegExp ||
370 searchStyleRegExp.test(getComputedStyle(element).cssText))) 394 searchStyleRegExp.test(getComputedCSSText(element))))
371 { 395 {
372 let closest = element.closest(selector); 396 let closest = element.closest(selector);
373 if (closest && (!styleRegExp || 397 if (closest && (!styleRegExp ||
374 styleRegExp.test(getComputedStyle(closest).cssText))) 398 styleRegExp.test(getComputedCSSText(closest))))
375 { 399 {
376 hideElement(closest); 400 hideElement(closest);
377 } 401 }
378 } 402 }
379 } 403 }
380 }) 404 })
381 .observe(document, {childList: true, characterData: true, subtree: true}); 405 .observe(document, {childList: true, characterData: true, subtree: true});
382 } 406 }
383 407
384 exports["hide-if-contains-and-matches-style"] = hideIfContainsAndMatchesStyle; 408 exports["hide-if-contains-and-matches-style"] = hideIfContainsAndMatchesStyle;
(...skipping 22 matching lines...) Expand all
407 // but it's usually OK to just add it at the end. 431 // but it's usually OK to just add it at the end.
408 mutation.target.appendChild(node); 432 mutation.target.appendChild(node);
409 } 433 }
410 } 434 }
411 } 435 }
412 }); 436 });
413 } 437 }
414 438
415 exports.readd = readd; 439 exports.readd = readd;
416 440
441 /**
442 * Wraps the <code>console.dir</code> API to call the <code>toString</code>
443 * method of the argument.
444 *
445 * @param {string} [times=1] The number of times to call the
446 * <code>toString</code> method of the argument to <code>console.dir</code>.
447 */
448 function dirString(times = "1")
449 {
450 let {dir} = console;
451
452 console.dir = function(object)
453 {
454 for (let i = 0; i < times; i++)
455 object + "";
456
457 if (typeof dir == "function")
458 dir.call(this, object);
459 };
460 }
461
462 exports["dir-string"] = makeInjector(dirString);
463
464 /**
465 * Prevents the execution of inline scripts.
466 *
467 * Only on Firefox.
468 *
469 * @param {string} [search] If specified, only scripts containing the given
470 * string are prevented from executing. If the string begins and ends with a
471 * slash (<code>/</code>), the text in between is treated as a regular
472 * expression.
473 * @param {string} [selector] If specified, only scripts whose HTML element
474 * matches the given CSS selector are prevented from executing.
475 */
476 function preventInlineScripts(search = null, selector = null)
477 {
478 let re = search ? toRegExp(search) : null;
479
480 document.addEventListener("beforescriptexecute", event =>
481 {
482 let {target} = event;
483
484 if ((!selector || target.matches(selector)) &&
485 (!re || re.test(target.textContent)))
486 {
487 event.preventDefault();
488 }
489 },
490 true);
491 }
492
493 exports["prevent-inline-scripts"] = preventInlineScripts;
494
495 /**
496 * Generates a random alphanumeric ID consisting of 6 base-36 digits
497 * from the range 100000..zzzzzz (both inclusive).
498 *
499 * @returns {string} The random ID.
500 */
417 function randomId() 501 function randomId()
418 { 502 {
419 // 2176782336 is 36^6 which mean 6 chars [a-z0-9] 503 // 2176782336 is 36^6 which mean 6 chars [a-z0-9]
420 return Math.floor(Math.random() * 2176782336).toString(36); 504 // 60466176 is 36^5
421 } 505 // 2176782336 - 60466176 = 2116316160. This ensure to always have 6
422 506 // chars even if Math.random() returns its minimum value 0.0
423 /** 507 //
424 * Will patch a property on the window object to abort when read. 508 return Math.floor(Math.random() * 2116316160 + 60466176).toString(36);
425 * It will intercept the onerror callback and block it if tagged. 509 }
426 * 510
427 * @todo handle properties of properties. 511 function wrapPropertyAccess(object, property, descriptor)
428 * 512 {
429 * @param {string} prop the name of the property. 513 let currentDescriptor = Object.getOwnPropertyDescriptor(object, property);
430 */ 514 if (currentDescriptor && !currentDescriptor.configurable)
431 function abortOnPropertyRead(prop) 515 return false;
432 { 516
433 if (!prop) 517 Object.defineProperty(object, property, descriptor);
518 return true;
519 }
520
521 /**
522 * Patches a property on the window object to abort execution when the
523 * property is read.
524 *
525 * No error is be printed to the console.
526 *
527 * The idea originates from
528 * {@link https://github.com/uBlockOrigin/uAssets/blob/80b195436f8f8d78ba713237b fc268ecfc9d9d2b/filters/resources.txt#L1703 uBlock Origin}.
529 *
530 * @param {string} property The name of the property.
531 */
532 function abortOnPropertyRead(property)
533 {
534 if (!property)
434 return; 535 return;
435 536
436 let magic = randomId(); 537 let rid = randomId();
437 538
438 let abort = function() 539 function abort()
439 { 540 {
440 throw new ReferenceError(magic); 541 throw new ReferenceError(rid);
441 }; 542 }
442 543
443 let {onerror} = window.onerror; 544 let {onerror} = window;
444 window.onerror = (msg, ...args) => 545 if (wrapPropertyAccess(window, property, {get: abort, set() {}}))
445 { 546 {
446 if (typeof msg === "string" && msg.indexOf(magic) != -1) 547 window.onerror = (message, ...rest) =>
447 return true; 548 {
448 if (onerror) 549 if (typeof message == "string" && message.includes(rid))
449 return onerror(msg, ...args); 550 return true;
450 }; 551 if (typeof onerror == "function")
451 552 return (() => {}).call.call(onerror, this, message, ...rest);
452 // patching function 553 };
453 (function(o, p) 554 }
454 { 555 }
455 // simple property 556
456 let d = Object.getOwnPropertyDescriptor(o, p); 557 exports["abort-on-property-read"] = makeInjector(abortOnPropertyRead,
457 if (!d || d.get !== abort) 558 wrapPropertyAccess,
458 Object.defineProperty(o, p, {get: abort, set() {}}); 559 randomId);
459 })(window, prop);
460 }
461
462 exports["abort-on-property-read"] = makeInjector(abortOnPropertyRead, randomId);
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld