rmi.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /**
  2. * Remove all the IFRAMEs that are off-site or do not have a “src” attribute.
  3. * These are typically used for ads and unwanted external content.
  4. * navigation etc.
  5. *
  6. * IFRAMEs without a “src” attribute are also used for sandboxing untrusted
  7. * content, e.g. on mailinator.com, but I have not yet found a way to
  8. * distinguish between src-less IFRAMEs for ads and src-less IFRAMEs for
  9. * “regular” content. Maybe try to guess based on the dimensions? Meh.
  10. *
  11. * @title rm IFRAMEs
  12. */
  13. (function rmi() {
  14. /* Create a new IFRAME to get a "clean" Window object, so we can use its
  15. * console. Sometimes sites (e.g. Twitter) override console.log and even
  16. * the entire console object. "delete console.log" or "delete console"
  17. * does not always work, and messing with the prototype seemed more
  18. * brittle than this. */
  19. let console = (function () {
  20. let iframe = document.getElementById('xxxJanConsole');
  21. if (!iframe) {
  22. iframe = document.createElementNS('http://www.w3.org/1999/xhtml', 'iframe');
  23. iframe.id = 'xxxJanConsole';
  24. iframe.style.display = 'none';
  25. (document.body || document.documentElement).appendChild(iframe);
  26. }
  27. return iframe && iframe.contentWindow && iframe.contentWindow.console || {
  28. log: function () {}
  29. };
  30. })();
  31. /* Keep track of the HTMLDocument instances we have processed. */
  32. let processed = new Set();
  33. /**
  34. * Is the given node empty-ish? I.e., does it lack child elements and
  35. * non-whitespace text?
  36. */
  37. function isEmpty(node) {
  38. return !node || (!node.childElementCount && (typeof node.textContent !== 'string' || node.textContent.trim() === ''));
  39. }
  40. /* The main function. */
  41. (function execute(document) {
  42. if (!document || typeof document.querySelectorAll !== 'function' || processed.has(document)) {
  43. return;
  44. }
  45. processed.add(document);
  46. /* Process all IFRAMEs. */
  47. Array.from(document.querySelectorAll('iframe:not(#xxxJanConsole)')).forEach(iframe => {
  48. let shouldDelete = false;
  49. try {
  50. shouldDelete = iframe.contentDocument === null || iframe.src === '';
  51. } catch (e) {
  52. shouldDelete = true;
  53. }
  54. if (shouldDelete) {
  55. console.log('rm IFRAMEs: found suspicious IFRAME to delete: ', iframe);
  56. let parentNode = iframe.parentNode;
  57. iframe.remove();
  58. while (parentNode && isEmpty(parentNode)) {
  59. console.log('rm IFRAMEs: found empty parent node to delete: ', parentNode);
  60. let oldParentNode = parentNode;
  61. parentNode = parentNode.parentNode;
  62. oldParentNode.remove();
  63. }
  64. } else {
  65. console.log('rm IFRAMEs: found non-suspicious IFRAME to recurse into: ', iframe);
  66. execute(iframe.contentDocument);
  67. }
  68. });
  69. })(document);
  70. })();