From: csagan5 <32685696+csagan5@users.noreply.github.com>
Date: Sat, 28 Oct 2017 10:09:41 +0200
Subject: Inject scripts for AMP, tracking, ads and video functionality

Remove AMP, tracking and ads from search/news results
Break Page Visibility API and Fullscreen API for youtube.com and vimeo.com to
allow playing videos in background (original Javascript code by timdream)
Send a random key press to circumvent idle status detection
---
 third_party/blink/renderer/core/dom/BUILD.gn       |  2 ++
 third_party/blink/renderer/core/dom/document.cc    | 32 +++++++++++++++++++++-
 .../renderer/core/dom/extensions/anti_amp_cure.h   |  6 ++++
 .../renderer/core/dom/extensions/video_bg_play.h   |  6 ++++
 .../renderer/core/html/html_script_element.cc      |  5 ++++
 .../blink/renderer/core/html/html_script_element.h |  1 +
 6 files changed, 51 insertions(+), 1 deletion(-)
 create mode 100644 third_party/blink/renderer/core/dom/extensions/anti_amp_cure.h
 create mode 100644 third_party/blink/renderer/core/dom/extensions/video_bg_play.h

diff --git a/third_party/blink/renderer/core/dom/BUILD.gn b/third_party/blink/renderer/core/dom/BUILD.gn
--- a/third_party/blink/renderer/core/dom/BUILD.gn
+++ b/third_party/blink/renderer/core/dom/BUILD.gn
@@ -144,6 +144,8 @@ blink_core_sources("dom") {
     "global_event_handlers.h",
     "icon_url.cc",
     "icon_url.h",
+    "extensions/anti_amp_cure.h",
+    "extensions/video_bg_play.h",
     "id_target_observer.cc",
     "id_target_observer.h",
     "id_target_observer_registry.cc",
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -241,6 +241,7 @@
 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
 #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
+#include "extensions/video_bg_play.h"
 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
 #include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -300,6 +301,8 @@
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
+#include "extensions/anti_amp_cure.h"
+
 #ifndef NDEBUG
 using WeakDocumentSet = blink::HeapHashSet<blink::WeakMember<blink::Document>>;
 static WeakDocumentSet& liveDocumentSet();
@@ -6224,8 +6227,35 @@ void Document::FinishedParsing() {
   // Parser should have picked up all preloads by now
   fetcher_->ClearPreloads(ResourceFetcher::kClearSpeculativeMarkupPreloads);
 
-  if (IsPrefetchOnly())
+  if (IsPrefetchOnly()) {
     WebPrerenderingSupport::Current()->PrefetchFinished();
+    return;
+  }
+
+  // determine whether this is a search results page
+  const WTF::String& host = url_.Host();
+  if ((host == nullptr) || host.IsEmpty())
+    return;
+
+  LOG(INFO) << "checking URL host for possible injections: " << host;
+  auto* bodyElement = body();
+  if (bodyElement) {
+    size_t pos1 = host.Find("www.google."), pos2 = host.Find("news.google.");
+    if ((pos1 == 0) || (pos2 == 0)) {
+      LOG(INFO) << "injecting anti-AMP-cure Javascript payload, URL: " << url_.GetString();
+      HTMLScriptElement* e = HTMLScriptElement::Create(*this, CreateElementFlags());
+      e->setTextDirect(ANTI_AMP_CURE_JS);
+      bodyElement->AppendChild(e);
+    }
+
+    // check for eligibility of the video bg fix
+    if ((WTF::kNotFound != host.Find("youtube.com")) || (WTF::kNotFound != host.Find("vimeo.com"))) {
+      LOG(INFO) << "injecting video-bg-play Javascript payload, URL: " << url_.GetString();
+      HTMLScriptElement* e = HTMLScriptElement::Create(*this, CreateElementFlags());
+      e->setTextDirect(VIDEO_BG_PLAY_JS);
+      bodyElement->AppendChild(e);
+    }
+  } // has origin and body element
 }
 
 void Document::ElementDataCacheClearTimerFired(TimerBase*) {
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
new file mode 100644
--- /dev/null
+++ b/third_party/blink/renderer/core/dom/extensions/anti_amp_cure.h
@@ -0,0 +1,6 @@
+#ifndef anti_amp_cure_h
+#define anti_amp_cure_h
+
+#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"
+
+#endif  // anti_amp_cure_h
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
new file mode 100644
--- /dev/null
+++ b/third_party/blink/renderer/core/dom/extensions/video_bg_play.h
@@ -0,0 +1,6 @@
+#ifndef video_bg_play_h
+#define video_bg_play_h
+
+#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"
+
+#endif  // video_bg_play_h
diff --git a/third_party/blink/renderer/core/html/html_script_element.cc b/third_party/blink/renderer/core/html/html_script_element.cc
--- a/third_party/blink/renderer/core/html/html_script_element.cc
+++ b/third_party/blink/renderer/core/html/html_script_element.cc
@@ -154,6 +154,11 @@ void HTMLScriptElement::setTextContent(
   }
 }
 
+void HTMLScriptElement::setTextDirect(
+    const char *s) {
+  Node::setTextContent(s);
+}
+
 void HTMLScriptElement::setAsync(bool async) {
   SetBooleanAttribute(kAsyncAttr, async);
   loader_->HandleAsyncAttribute();
diff --git a/third_party/blink/renderer/core/html/html_script_element.h b/third_party/blink/renderer/core/html/html_script_element.h
--- a/third_party/blink/renderer/core/html/html_script_element.h
+++ b/third_party/blink/renderer/core/html/html_script_element.h
@@ -53,6 +53,7 @@ class CORE_EXPORT HTMLScriptElement final : public HTMLElement,
   void setText(const StringOrTrustedScript&, ExceptionState&);
   void setInnerText(const StringOrTrustedScript&, ExceptionState&) override;
   void setTextContent(const StringOrTrustedScript&, ExceptionState&) override;
+  void setTextDirect(const char*);
 
   KURL Src() const;
 
-- 
2.11.0

