Inject-scripts-for-AMP-tracking-ads-and-video-functionality.patch 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. From: csagan5 <32685696+csagan5@users.noreply.github.com>
  2. Date: Sat, 28 Oct 2017 10:09:41 +0200
  3. Subject: Inject scripts for AMP, tracking, ads and video functionality
  4. Remove AMP, tracking and ads from search/news results
  5. Break Page Visibility API and Fullscreen API for youtube.com and vimeo.com to
  6. allow playing videos in background (original Javascript code by timdream)
  7. Send a random key press to circumvent idle status detection
  8. ---
  9. third_party/blink/renderer/core/dom/BUILD.gn | 2 ++
  10. third_party/blink/renderer/core/dom/document.cc | 31 +++++++++++++++++++++-
  11. .../renderer/core/dom/extensions/anti_amp_cure.h | 6 +++++
  12. .../renderer/core/dom/extensions/video_bg_play.h | 6 +++++
  13. .../renderer/core/html/html_script_element.cc | 5 ++++
  14. .../blink/renderer/core/html/html_script_element.h | 1 +
  15. 6 files changed, 50 insertions(+), 1 deletion(-)
  16. create mode 100644 third_party/blink/renderer/core/dom/extensions/anti_amp_cure.h
  17. create mode 100644 third_party/blink/renderer/core/dom/extensions/video_bg_play.h
  18. diff --git a/third_party/blink/renderer/core/dom/BUILD.gn b/third_party/blink/renderer/core/dom/BUILD.gn
  19. --- a/third_party/blink/renderer/core/dom/BUILD.gn
  20. +++ b/third_party/blink/renderer/core/dom/BUILD.gn
  21. @@ -146,6 +146,8 @@ blink_core_sources("dom") {
  22. "global_event_handlers.h",
  23. "icon_url.cc",
  24. "icon_url.h",
  25. + "extensions/anti_amp_cure.h",
  26. + "extensions/video_bg_play.h",
  27. "id_target_observer.cc",
  28. "id_target_observer.h",
  29. "id_target_observer_registry.cc",
  30. diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
  31. --- a/third_party/blink/renderer/core/dom/document.cc
  32. +++ b/third_party/blink/renderer/core/dom/document.cc
  33. @@ -254,6 +254,7 @@
  34. #include "third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h"
  35. #include "third_party/blink/renderer/core/page/scrolling/scroll_state_callback.h"
  36. #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
  37. +#include "extensions/video_bg_play.h"
  38. #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
  39. #include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h"
  40. #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
  41. @@ -319,6 +320,8 @@
  42. #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
  43. #include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h"
  44. +#include "extensions/anti_amp_cure.h"
  45. +
  46. #ifndef NDEBUG
  47. using WeakDocumentSet = blink::HeapHashSet<blink::WeakMember<blink::Document>>;
  48. static WeakDocumentSet& liveDocumentSet();
  49. @@ -6688,8 +6691,34 @@ void Document::FinishedParsing() {
  50. // Parser should have picked up all preloads by now
  51. fetcher_->ClearPreloads(ResourceFetcher::kClearSpeculativeMarkupPreloads);
  52. - if (IsPrefetchOnly())
  53. + if (IsPrefetchOnly()) {
  54. WebPrerenderingSupport::Current()->PrefetchFinished();
  55. + return;
  56. + }
  57. +
  58. + // determine whether this is a search results page
  59. + const WTF::String& host = url_.Host();
  60. + if ((host == nullptr) || host.IsEmpty())
  61. + return;
  62. +
  63. + auto* bodyElement = body();
  64. + if (bodyElement) {
  65. + size_t pos1 = host.Find("www.google."), pos2 = host.Find("news.google."), pos3 = url_.GetPath().Find("/search");
  66. + if (((pos1 == 0) && (pos3 == 0)) || (pos2 == 0)) {
  67. + LOG(INFO) << "injecting anti-AMP-cure Javascript payload, URL: " << url_.GetString();
  68. + HTMLScriptElement* e = MakeGarbageCollected<HTMLScriptElement>(*this, CreateElementFlags());
  69. + e->setTextDirect(ANTI_AMP_CURE_JS);
  70. + bodyElement->AppendChild(e);
  71. + }
  72. +
  73. + // check for eligibility of the video bg fix
  74. + if ((WTF::kNotFound != host.Find("youtube.com")) || (WTF::kNotFound != host.Find("vimeo.com"))) {
  75. + LOG(INFO) << "injecting video-bg-play Javascript payload, URL: " << url_.GetString();
  76. + HTMLScriptElement* e = MakeGarbageCollected<HTMLScriptElement>(*this, CreateElementFlags());
  77. + e->setTextDirect(VIDEO_BG_PLAY_JS);
  78. + bodyElement->AppendChild(e);
  79. + }
  80. + } // has origin and body element
  81. }
  82. void Document::ElementDataCacheClearTimerFired(TimerBase*) {
  83. diff --git a/third_party/blink/renderer/core/dom/extensions/anti_amp_cure.h b/third_party/blink/renderer/core/dom/extensions/anti_amp_cure.h
  84. new file mode 100644
  85. --- /dev/null
  86. +++ b/third_party/blink/renderer/core/dom/extensions/anti_amp_cure.h
  87. @@ -0,0 +1,6 @@
  88. +#ifndef anti_amp_cure_h
  89. +#define anti_amp_cure_h
  90. +
  91. +#define ANTI_AMP_CURE_JS "/* Bromite click-tracking and AMP removal v0.3.7 */\n\nfunction recreateHyperlink(a) {\n // skip already-sanitized hyperlinks\n if (a.sane) return false;\n\n // create new A element - old one has event listeners attached\n var newA = document.createElement('a');\n newA.referrerPolicy = 'origin';\n // property set when hyperlink has been created by this script\n newA.sane = 1;\n\n // remove AMP class, get actual page URL\n var ampCur = a.getAttribute('data-amp-cur');\n if (ampCur) {\n newA.href = ampCur;\n a.classList.remove('amp_r');\n } else {\n var realLink = getRealLinkFromGoogleUrl(a);\n if (realLink) {\n newA.href = realLink;\n } else {\n // might not be an actual hyperlink, ignore it\n if (!a.href) {\n return false;\n }\n // leave original href unchanged\n newA.href = a.href;\n }\n }\n // copy CSS classes\n newA.className = a.className;\n\n // copy nodes inside the hyperlink\n while (a.firstChild) {\n newA.appendChild(a.lastChild);\n }\n // replace hyperlink\n a.parentNode.replaceChild(newA, a);\n return true;\n}\n\nfunction isResult(a) {\n if (a.getAttribute('data-amp-cur'))\n return true;\n var inlineMousedown = a.getAttribute('onmousedown');\n if (!inlineMousedown)\n\treturn false;\n // return rwt(....); // E.g Google search results.\n // return google.rwt(...); // E.g. sponsored search results\n // return google.arwt(this); // E.g. sponsored search results (dec 2016).\n return /\\ba?rwt\\(/.test(inlineMousedown) || /\\bctpacw\\b/.test(inlineMousedown);\n}\n\n/**\n * @returns {String} the real URL if the given link is a Google redirect URL.\n */\nfunction getRealLinkFromGoogleUrl(a) {\n if ((a.hostname === location.hostname || a.hostname.indexOf('www.google.') == 0) &&\n /^\\/(local_)?url$/.test(a.pathname)) {\n // Google Maps / Dito (/local_url?q=<url>)\n // Mobile (/url?q=<url>)\n var url = /[?&](?:q|url)=((?:https?|ftp)[%:][^&]+)/.exec(a.search);\n if (url) {\n return decodeURIComponent(url[1]);\n }\n // Help pages, e.g. safe browsing (/url?...&q=%2Fsupport%2Fanswer...)\n url = /[?&](?:q|url)=((?:%2[Ff]|\\/)[^&]+)/.exec(a.search);\n if (url) {\n return a.origin + decodeURIComponent(url[1]);\n }\n }\n}\n\nfunction sanitizeAds() {\n // scan all divs\n var div = document.getElementById('tads');\n if (div) {\n div.style.display = 'none';\n\treturn true;\n }\n return false;\n}\n\nfunction hookMoreResults() {\n var extrares = document.getElementById('extrares');\n if (!extrares) {\n console.log(\"could not hook more results\");\n return;\n }\n // mutation observers are great but they don't work\n extrares.addEventListener(\"DOMNodeInserted\", function(e) {\n var node = e.target;\n if (node.id && node.id.startsWith(\"arc-srp\"))\n console.log(\"hyperlinks sanitized on new result node: \", sanitizeAllHyperlinks(node));\n });\n}\n\nfunction setMlogoClick() {\n // skip home page\n if (document.getElementById('hplogo')) return;\n\n var mlogo = document.getElementById('qslc');\n if (mlogo && mlogo.children[0]) {\n mlogo = mlogo.children[0];\n } else {\n mlogo = document.getElementById('mlogo');\n }\n if (mlogo) {\n mlogo.removeAttribute(\"href\");\n mlogo.setAttribute(\"onclick\", \"sanitizeAll()\");\n console.log(\"logo link replaced\");\n } else {\n console.log(\"could not replace logo link\");\n }\n}\n\nfunction sanitizeAllHyperlinks(rootNode) {\n var sanitized = 0, total = 0;\n // exclude translation hyperlink nodes\n const exclude = rootNode.querySelectorAll('#tw-ob a');\n // selector for both results and news\n rootNode.querySelectorAll('div[data-hveid]:not([data-hveid=\"\"]) a, div[data-ved]:not([data-ved=\"\"]) a').forEach(function(a) {\n // exclude nodes which should not be processed\n var excluded = false;\n exclude.forEach(function(e) {\n if (excluded) return;\n if (e == a) {\n excluded = true;\n }\n });\n if (excluded) return;\n\n\ttotal++;\n\tvar res = recreateHyperlink(a);\n\tif (res) sanitized++;\n });\n console.log(\"sanitized \", sanitized, \"/\", total, \" hyperlinks\");\n\n return sanitized;\n}\n\nfunction sanitizeAll() {\n console.log(\"ads removed: \", sanitizeAds());\n console.log(\"hyperlinks sanitized: \", sanitizeAllHyperlinks(document));\n}\n\n// avoid running cleanup on non-search pages\nif ((document.location.host.indexOf(\"images.google.\") == -1) &&\n (document.location.host.indexOf(\"accounts.google.\") == -1)) {\n sanitizeAll();\n}\nsetMlogoClick();\n\nhookMoreResults();\n"
  92. +
  93. +#endif // anti_amp_cure_h
  94. diff --git a/third_party/blink/renderer/core/dom/extensions/video_bg_play.h b/third_party/blink/renderer/core/dom/extensions/video_bg_play.h
  95. new file mode 100644
  96. --- /dev/null
  97. +++ b/third_party/blink/renderer/core/dom/extensions/video_bg_play.h
  98. @@ -0,0 +1,6 @@
  99. +#ifndef video_bg_play_h
  100. +#define video_bg_play_h
  101. +
  102. +#define VIDEO_BG_PLAY_JS "'use strict';\n\n/* generate a synthetic keypress to circumvent the extremely useful pause-and-prompt beaviour */\nsetInterval(function() {\n document.dispatchEvent(new KeyboardEvent(\"keydown\", {key : \"a\", char : \"a\", shiftKey: false}));\n}, 3 * 60 * 1000);\n\n/* video background play fix - original version by timdream */\ndocument.videoBGFix = {};\n\n// Page Visibility API\nObject.defineProperties(document.videoBGFix,\n { 'hidden': {value: false}, 'visibilityState': {value: 'visible'} });\n\nwindow.addEventListener(\n 'visibilitychange', evt => evt.stopImmediatePropagation(), true);\nwindow.addEventListener(\n 'blur', evt => evt.stopImmediatePropagation(), true);\n\n// Fullscreen API\nwindow.addEventListener('fullscreenchange', evt => {\n Object.defineProperties(document.videoBGFix,\n { 'fullscreenEnabled': {value: true},\n 'fullscreen': {value: true},\n 'fullscreenElement': {value: document.fullscreenElement.videoBGFix}});\n window.addEventListener(\n 'fullscreenchange', evt => evt.stopImmediatePropagation(), true);\n}, { capture: true, once: true });\n"
  103. +
  104. +#endif // video_bg_play_h
  105. diff --git a/third_party/blink/renderer/core/html/html_script_element.cc b/third_party/blink/renderer/core/html/html_script_element.cc
  106. --- a/third_party/blink/renderer/core/html/html_script_element.cc
  107. +++ b/third_party/blink/renderer/core/html/html_script_element.cc
  108. @@ -149,6 +149,11 @@ void HTMLScriptElement::setTextContent(
  109. }
  110. }
  111. +void HTMLScriptElement::setTextDirect(
  112. + const char *s) {
  113. + Node::setTextContent(s);
  114. +}
  115. +
  116. void HTMLScriptElement::setAsync(bool async) {
  117. SetBooleanAttribute(kAsyncAttr, async);
  118. loader_->HandleAsyncAttribute();
  119. diff --git a/third_party/blink/renderer/core/html/html_script_element.h b/third_party/blink/renderer/core/html/html_script_element.h
  120. --- a/third_party/blink/renderer/core/html/html_script_element.h
  121. +++ b/third_party/blink/renderer/core/html/html_script_element.h
  122. @@ -51,6 +51,7 @@ class CORE_EXPORT HTMLScriptElement final : public HTMLElement,
  123. void setText(const StringOrTrustedScript&, ExceptionState&);
  124. void setInnerText(const StringOrTrustedScript&, ExceptionState&) override;
  125. void setTextContent(const StringOrTrustedScript&, ExceptionState&) override;
  126. + void setTextDirect(const char*);
  127. void setAsync(bool);
  128. bool async() const;
  129. --
  130. 2.11.0