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: Revert to having one single property per call. Created Sept. 25, 2018, 3:38 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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 for (let i = 0; i < times; i++) 454 for (let i = 0; i < times; i++)
431 object + ""; 455 object + "";
432 456
433 if (typeof dir == "function") 457 if (typeof dir == "function")
434 dir.call(this, object); 458 dir.call(this, object);
435 }; 459 };
436 } 460 }
437 461
438 exports["dir-string"] = makeInjector(dirString); 462 exports["dir-string"] = makeInjector(dirString);
439 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 */
440 function randomId() 501 function randomId()
441 { 502 {
442 // 2176782336 is 36^6 which mean 6 chars [a-z0-9] 503 // 2176782336 is 36^6 which mean 6 chars [a-z0-9]
443 // 60466176 is 36^5 504 // 60466176 is 36^5
444 // 2176782336 - 60466176 = 2116316160. This ensure always 6 chars 505 // 2176782336 - 60466176 = 2116316160. This ensure to always have 6
445 // for when Math.random() returns 0.0 506 // chars even if Math.random() returns its minimum value 0.0
507 //
446 return Math.floor(Math.random() * 2116316160 + 60466176).toString(36); 508 return Math.floor(Math.random() * 2116316160 + 60466176).toString(36);
447 } 509 }
448 510
449 /** 511 function wrapPropertyAccess(object, property, descriptor)
450 * Will patch a property on the window object to abort when read. 512 {
451 * It will intercept the onerror callback and block it if tagged. 513 let currentDescriptor = Object.getOwnPropertyDescriptor(object, property);
452 * 514 if (currentDescriptor && !currentDescriptor.configurable)
453 * @todo handle properties of properties. 515 return false;
454 * 516
455 * @param {string} prop the name of the property. 517 Object.defineProperty(object, property, descriptor);
456 */ 518 return true;
457 function abortOnPropertyRead(prop) 519 }
458 { 520
459 if (!prop) 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)
460 return; 535 return;
461 536
462 let magic = randomId(); 537 let rid = randomId();
463 538
464 let abort = function() 539 function abort()
465 { 540 {
466 throw new ReferenceError(magic); 541 throw new ReferenceError(rid);
467 }; 542 }
468 543
469 let {onerror} = window; 544 let {onerror} = window;
470 window.onerror = (message, ...rest) => 545 if (wrapPropertyAccess(window, property, {get: abort, set() {}}))
471 { 546 {
472 if (typeof message == "string" && message.includes(magic)) 547 window.onerror = (message, ...rest) =>
473 return true; 548 {
474 if (onerror && typeof onerro == "function") 549 if (typeof message == "string" && message.includes(rid))
475 return onerror(this, message, ...rest); 550 return true;
476 }; 551 if (typeof onerror == "function")
477 552 return (() => {}).call.call(onerror, this, message, ...rest);
478 (function(o, p) 553 };
479 { 554 }
480 // simple property 555 }
481 let d = Object.getOwnPropertyDescriptor(o, p); 556
482 if (!d || d.get != abort) 557 exports["abort-on-property-read"] = makeInjector(abortOnPropertyRead,
483 Object.defineProperty(o, p, {get: abort, set() {}}); 558 wrapPropertyAccess,
484 })(window, prop); 559 randomId);
485 }
486
487 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