[tbb-commits] [tor-browser/tor-browser-85.0b1-10.5-1] Bug 16620: Clear window.name when no referrer sent

gk at torproject.org gk at torproject.org
Tue Jan 12 08:37:42 UTC 2021


commit 65bc66d6e360578e4c40404f614a411ddbe72860
Author: Kathy Brade <brade at pearlcrescent.com>
Date:   Fri Oct 30 14:28:13 2015 -0400

    Bug 16620: Clear window.name when no referrer sent
    
    Convert JS implementation (within Torbutton) to a C++ browser patch.
---
 docshell/base/nsDocShell.cpp                   |  60 +++++++
 docshell/test/mochitest/mochitest.ini          |   3 +
 docshell/test/mochitest/test_tor_bug16620.html | 212 +++++++++++++++++++++++++
 docshell/test/mochitest/tor_bug16620.html      |  51 ++++++
 docshell/test/mochitest/tor_bug16620_form.html |  51 ++++++
 5 files changed, 377 insertions(+)

diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index 512ea9dbd97b..80073e338e2d 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -7744,11 +7744,71 @@ nsresult nsDocShell::CreateContentViewer(const nsACString& aContentType,
     aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
   }
   FirePageHideNotification(!mSavingOldViewer);
+
   if (mIsBeingDestroyed) {
     // Force to stop the newly created orphaned viewer.
     viewer->Stop();
     return NS_ERROR_DOCSHELL_DYING;
   }
+
+  // Tor bug 16620: Clear window.name of top-level documents if
+  // there is no referrer. We make an exception for new windows,
+  // e.g., window.open(url, "MyName").
+  bool isNewWindowTarget = false;
+  nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aRequest, &rv));
+  if (props) {
+    props->GetPropertyAsBool(u"docshell.newWindowTarget"_ns,
+                             &isNewWindowTarget);
+  }
+
+  if (!isNewWindowTarget) {
+    nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aOpenedChannel));
+    nsCOMPtr<nsIURI> httpReferrer;
+    if (httpChannel) {
+      nsCOMPtr<nsIReferrerInfo> referrerInfo;
+      rv = httpChannel->GetReferrerInfo(getter_AddRefs(referrerInfo));
+      NS_ENSURE_SUCCESS(rv, rv);
+      if (referrerInfo) {
+        // We want GetComputedReferrer() instead of GetOriginalReferrer(), since
+        // the former takes into consideration referrer policy, protocol
+        // whitelisting...
+        httpReferrer = referrerInfo->GetComputedReferrer();
+      }
+    }
+
+    bool isTopFrame = mBrowsingContext->IsTop();
+
+#ifdef DEBUG_WINDOW_NAME
+    printf("DOCSHELL %p CreateContentViewer - possibly clearing window.name:\n",
+           this);
+    printf("  current window.name: \"%s\"\n",
+           NS_ConvertUTF16toUTF8(mName).get());
+
+    nsAutoCString curSpec, loadingSpec;
+    if (this->mCurrentURI) mCurrentURI->GetSpec(curSpec);
+    if (mLoadingURI) mLoadingURI->GetSpec(loadingSpec);
+    printf("  current URI: %s\n", curSpec.get());
+    printf("  loading URI: %s\n", loadingSpec.get());
+    printf("  is top document: %s\n", isTopFrame ? "Yes" : "No");
+
+    if (!httpReferrer) {
+      printf("  referrer: None\n");
+    } else {
+      nsAutoCString refSpec;
+      httpReferrer->GetSpec(refSpec);
+      printf("  referrer: %s\n", refSpec.get());
+    }
+#endif
+
+    bool clearName = isTopFrame && !httpReferrer;
+    if (clearName) SetName(u""_ns);
+
+#ifdef DEBUG_WINDOW_NAME
+    printf("  action taken: %s window.name\n",
+           clearName ? "Cleared" : "Preserved");
+#endif
+  }
+
   mLoadingURI = nullptr;
 
   // Set mFiredUnloadEvent = false so that the unload handler for the
diff --git a/docshell/test/mochitest/mochitest.ini b/docshell/test/mochitest/mochitest.ini
index d7cf516baa64..62d72db74d52 100644
--- a/docshell/test/mochitest/mochitest.ini
+++ b/docshell/test/mochitest/mochitest.ini
@@ -53,6 +53,8 @@ support-files =
   start_historyframe.html
   url1_historyframe.html
   url2_historyframe.html
+  tor_bug16620.html
+  tor_bug16620_form.html
 
 [test_anchor_scroll_after_document_open.html]
 [test_bfcache_plus_hash.html]
@@ -124,6 +126,7 @@ support-files =
   file_history_length_during_pageload.html
   file_history_length_during_pageload_2.html
 [test_pushState_after_document_open.html]
+[test_tor_bug16620.html]
 [test_navigate_after_pagehide.html]
 [test_redirect_history.html]
 support-files =
diff --git a/docshell/test/mochitest/test_tor_bug16620.html b/docshell/test/mochitest/test_tor_bug16620.html
new file mode 100644
index 000000000000..f60a06711c17
--- /dev/null
+++ b/docshell/test/mochitest/test_tor_bug16620.html
@@ -0,0 +1,212 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+  Tor Bug 16620: Clear window.name when no referrer sent.
+                 https://trac.torproject.org/projects/tor/ticket/16620
+-->
+<meta charset="utf-8">
+<head>
+  <title>Test for Tor Bug 16620 - Clear window.name when no referrer sent</title>
+  <script type="application/javascript"
+          src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://trac.torproject.org/projects/tor/ticket/16620">Tor Bug 16620</a>
+<script type="application/javascript;version=1.7">
+
+// ## Test constants
+const kTestPath = "/tests/docshell/test/mochitest/";
+const kLinkFile = "tor_bug16620.html";
+const kFormFile = "tor_bug16620_form.html";
+const kBaseURL1 = "http://example.com";
+const kBaseURL1_https = "https://example.com";
+const kBaseURL2 = "http://example.net";
+const kSendReferrerPref = "network.http.sendRefererHeader";
+const kSendReferrerNever = 0;
+const kSendReferrerForUserAction = 1;
+const kSendReferrerAlways = 2;
+
+let gTests = [
+  // Test #1: Same domain; never send referrer.
+  { startURL: kBaseURL1, destURL: kBaseURL1,
+    referrerPref: kSendReferrerNever,
+    expectIsolation: true },
+
+  // Test #2: Same domain; send referrer upon user action.
+  { startURL: kBaseURL1, destURL: kBaseURL1,
+    referrerPref: kSendReferrerForUserAction,
+    expectIsolation: false },
+
+  // Test #3: Same domain; always send referrer.
+  { startURL: kBaseURL1, destURL: kBaseURL1,
+    referrerPref: kSendReferrerAlways,
+    expectIsolation: false },
+
+  // Test #4: Different top-level domains; never send referrer.
+  { startURL: kBaseURL1, destURL: kBaseURL2,
+    referrerPref: kSendReferrerNever,
+    expectIsolation: true },
+
+  // Test #5: Different top-level domains; send referrer upon user action.
+  { startURL: kBaseURL1, destURL: kBaseURL2,
+    referrerPref: kSendReferrerForUserAction,
+    expectIsolation: false },
+
+  // Test #6: Different top-level domains; always send referrer.
+  { startURL: kBaseURL1, destURL: kBaseURL2,
+    referrerPref: kSendReferrerAlways,
+    expectIsolation: false },
+
+  // Test #7: https -> http transition.
+  { startURL: kBaseURL1_https, destURL: kBaseURL1,
+    referrerPref: kSendReferrerForUserAction,
+    expectIsolation: true },
+
+  // Test #8: Same domain, rel="noreferrer" on link.
+  { startURL: kBaseURL1, destURL: kBaseURL1, noReferrerOnLink: true,
+    referrerPref: kSendReferrerAlways,
+    expectIsolation: true },
+
+  // Test #9: Same domain, "no-referrer" meta tag in document.
+  { startURL: kBaseURL1, destURL: kBaseURL1, noReferrerInMetaTag: true,
+    referrerPref: kSendReferrerAlways,
+    expectIsolation: true },
+
+  // Test #10: Like test #9, but reset window.name during unload.
+  // (similar to http://www.thomasfrank.se/sessvarsTestPage1.html)
+  { startURL: kBaseURL1, destURL: kBaseURL1, noReferrerInMetaTag: true,
+    resetInUnload: true,
+    referrerPref: kSendReferrerAlways,
+    expectIsolation: true },
+
+  // Test #11: Data URL as destination (no referrer).
+  { startURL: kBaseURL1,
+    referrerPref: kSendReferrerAlways,
+    expectIsolation: true },
+
+  // Test #12: Ensure that window.name is preserved when a dynamically loaded
+  // iframe is used to perform a form post (regression test for Tor bug 18168).
+  { startURL: kBaseURL1,
+    isFormTest: true,
+    referrerPref: kSendReferrerAlways,
+    expectIsolation: false },
+];
+
+let gCurTest = 0;
+let gCurWinName, gChildWin, gDataURL;
+
+// ## Utility functions
+function generateRandomName()
+{
+  // Generate a random 6 character string using 0-9 and a-z.
+  return ((1 + Math.random()).toString(36) + '000000').substr(2, 6);
+}
+
+function startNextTest() {
+  ++gCurTest;
+  if (gCurTest > gTests.length) {
+    SimpleTest.finish();
+  } else {
+    let curTest = gTests[gCurTest - 1];
+    if ("referrerPref" in curTest)
+      SpecialPowers.setIntPref(kSendReferrerPref, curTest.referrerPref);
+    else
+      SpecialPowers.setIntPref(kSendReferrerPref, kSendReferrerForUserAction);
+    gCurWinName = generateRandomName();
+    let url = curTest.startURL + kTestPath;
+    if (curTest.isFormTest === true) {
+      url += kFormFile + "?" + gCurWinName;
+      gChildWin = window.open(url, undefined);
+    } else {
+      url += kLinkFile + "?firstDocLoaded";
+      gChildWin = window.open(url, gCurWinName);
+    }
+  }
+}
+
+// ## Add a message event listener.
+window.addEventListener("message", function(aEvent) {
+    if (aEvent.source !== gChildWin)
+      return;
+
+//    console.log("parent received message:" + JSON.stringify(aEvent.data));
+
+    let proceedToNextTest = false;
+    let curTest = gTests[gCurTest - 1];
+    let state = aEvent.data.state;
+    let winName = aEvent.data.winName;
+    if ("firstDocLoaded" == state) {
+      // Process response from step one of the link-based  tests.
+      let step1Passed = (winName === gCurWinName);
+      if (!step1Passed) {
+        ok(step1Passed, "Test #" + gCurTest +
+                 " - first document's name matches window.open parameter");
+        proceedToNextTest = true;
+      }
+
+      // Send an "openURL" message to the loaded document.
+      let url2 = (curTest.destURL)
+                  ? curTest.destURL + kTestPath + kLinkFile + "?secondDocLoaded"
+                  : gDataURL;
+      let noReferrerOnLink = (curTest.noReferrerOnLink === true);
+      let noReferrerInMetaTag = (curTest.noReferrerInMetaTag === true);
+      let resetInUnload = (curTest.resetInUnload === true);
+      aEvent.source.postMessage({ action: "openURL", url: url2,
+                                  noReferrerOnLink: noReferrerOnLink,
+                                  noReferrerInMetaTag: noReferrerInMetaTag,
+                                  resetInUnload: resetInUnload },
+                                aEvent.origin);
+    } else if ("secondDocLoaded" == state) {
+      // Process response from step two of the link-based tests.
+      if (curTest.expectIsolation) {
+        ok(winName === "",
+           "Test #" + gCurTest + " - second document: name was cleared");
+      } else {
+        ok(winName === gCurWinName,
+           "Test #" + gCurTest + " - second document: name was preserved");
+      }
+      proceedToNextTest = true;
+    } else if ("formPostDone" == state) {
+      // Process response from the form post tests.
+      if (curTest.expectIsolation) {
+        ok(winName === "",
+           "Test #" + gCurTest + " - iframe form post: name was cleared");
+      } else {
+        ok(winName === gCurWinName,
+           "Test #" + gCurTest + " - iframe form post: name was preserved");
+      }
+      proceedToNextTest = true;
+
+    }
+
+    if (proceedToNextTest) {
+      gChildWin.close();
+      startNextTest();
+    }
+  }, false);
+
+  SimpleTest.waitForExplicitFinish();
+
+  if (SpecialPowers.getBoolPref("security.nocertdb")) {
+    // Mochitests don't simulate https correctly with "security.nocertdb"
+    // enabled.  See https://bugs.torproject.org/18087
+    ok(false, "Please disable the pref `security.nocertdb` before running this test.");
+    SimpleTest.finish();
+  } else {
+
+    // Read file contents, construct a data URL (used by some tests), and
+    // then start the first test.
+    let url = kTestPath + kLinkFile;
+    let xhr = new XMLHttpRequest();
+    xhr.open("GET", url);
+    xhr.onload = function() {
+      gDataURL = "data:text/html;charset=utf-8,"
+                 + encodeURIComponent(this.responseText);
+      startNextTest();
+    }
+    xhr.send();
+  }
+</script>
+</body>
+</html>
diff --git a/docshell/test/mochitest/tor_bug16620.html b/docshell/test/mochitest/tor_bug16620.html
new file mode 100644
index 000000000000..a8e90502f1d1
--- /dev/null
+++ b/docshell/test/mochitest/tor_bug16620.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+  Tor Bug 16620: Clear window.name when no referrer sent.
+                 https://trac.torproject.org/projects/tor/ticket/16620
+-->
+<head>
+  <meta charset="UTF-8">
+  <title>Supporting Doc for Tor Bug 16620 Tests</title>
+</head>
+<body>
+<a id="link" href="">secondDoc</a>
+
+<script type="application/javascript;version=1.7">
+// Extract test state from our query string, defaulting to
+// "secondDocLoaded" to support use of this HTML content within
+// a data URI (where query strings are not supported).
+let state = (location.search.length > 0) ? location.search.substr(1)
+                                         : "secondDocLoaded";
+
+// Notify the test driver.
+opener.postMessage({ state: state, winName: window.name }, "*");
+
+// Add a message event listener to process "openURL" actions.
+window.addEventListener("message", function(aEvent) {
+  if (aEvent.data.action == "openURL") {
+    if (aEvent.data.noReferrerInMetaTag) {
+      let metaElem = document.createElement("meta");
+      metaElem.name = "referrer";
+      metaElem.content = "no-referrer";
+      document.head.appendChild(metaElem);
+    }
+
+    let linkElem = document.getElementById("link");
+    linkElem.href = aEvent.data.url;
+    if (aEvent.data.noReferrerOnLink)
+      linkElem.rel = "noreferrer";
+
+    if (aEvent.data.resetInUnload) {
+      let tmpName = window.name;
+      window.addEventListener("unload", function() {
+        window.name = tmpName;
+      }, false);
+    }
+
+    linkElem.click();
+  }
+}, false);
+</script>
+</body>
+</html>
diff --git a/docshell/test/mochitest/tor_bug16620_form.html b/docshell/test/mochitest/tor_bug16620_form.html
new file mode 100644
index 000000000000..3b6e6c72cfc9
--- /dev/null
+++ b/docshell/test/mochitest/tor_bug16620_form.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+  Tor Bug 16620: Clear window.name when no referrer sent.
+                 https://trac.torproject.org/projects/tor/ticket/16620
+
+  Regression test for bug 18168: iframe-based AJAX call opening in new tab
+-->
+<head>
+  <meta charset="UTF-8">
+  <title>Supporting Form-based Doc for Tor Bug 16620 Tests</title>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+document.addEventListener("DOMContentLoaded", function () {
+  addPostTarget();
+}, false);
+
+
+function addPostTarget()
+{
+  let frameName = location.search.substr(1);
+  let form = document.getElementById("postform");
+  let iframe = document.createElement("iframe");
+  iframe.style.border = "1px solid red";
+  iframe.src = "about:blank";
+  form.target = iframe.name = iframe.id = frameName;
+  document.body.appendChild(iframe);
+
+  let didSubmit = false;
+  iframe.onload = function() {
+    if (!didSubmit) {
+      didSubmit = true;
+      let submitButton = document.getElementById("submitButton");
+      submitButton.click();
+    } else {
+      // Form submission complete. Report iframe's name to test driver.
+      opener.postMessage({ state: "formPostDone", winName: iframe.name }, "*");
+    }
+  };
+}
+
+</script>
+<form name="postform" id="postform"
+      action="data:text/plain;charset=utf-8,Hello%20world"
+      method="POST" enctype="multipart/form-data">
+  <input type="hidden" name="field1" value="value1"><br>
+  <input id="submitButton" type="submit" value="Post It">
+</body>
+</html>





More information about the tbb-commits mailing list