Skip to content

Commit

Permalink
Add browsertest for cross-origin .onion requests.
Browse files Browse the repository at this point in the history
  • Loading branch information
fmarier committed Nov 19, 2021
1 parent 1cdcf6b commit 030bf22
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 4 deletions.
189 changes: 186 additions & 3 deletions browser/net/brave_site_hacks_network_delegate_helper_browsertest.cc
Expand Up @@ -9,6 +9,7 @@
#include "base/strings/stringprintf.h"
#include "brave/common/brave_paths.h"
#include "brave/components/brave_shields/browser/brave_shields_util.h"
#include "brave/components/tor/onion_location_navigation_throttle.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
Expand Down Expand Up @@ -38,6 +39,10 @@ class BraveSiteHacksNetworkDelegateBrowserTest : public InProcessBrowserTest {
https_server_.AddDefaultHandlers(GetChromeTestDataDir());
content::SetupCrossSiteRedirector(&https_server_);

https_server_.RegisterRequestMonitor(base::BindRepeating(
&BraveSiteHacksNetworkDelegateBrowserTest::HandleRequest,
base::Unretained(this)));

ASSERT_TRUE(https_server_.Start());

simple_landing_url_ = https_server_.GetURL("a.com", "/simple.html");
Expand All @@ -49,6 +54,39 @@ class BraveSiteHacksNetworkDelegateBrowserTest : public InProcessBrowserTest {
cross_site_url_ = https_server_.GetURL("b.com", "/navigate-to-site.html");
same_site_url_ =
https_server_.GetURL("sub.a.com", "/navigate-to-site.html");

onion_url_ = https_server_.GetURL("foobar.onion", "/navigate-to-site.html");
onion_post_url_ =
https_server_.GetURL("foobar.onion", "/post-to-site.html");
reflect_referrer_cross_origin_url_ =
https_server_.GetURL("a.com", "/reflect-referrer.html");
reflect_referrer_cross_origin_redirect_url_ = https_server_.GetURL(
"foobar.onion",
"/server-redirect-307?" + reflect_referrer_cross_origin_url_.spec());
reflect_referrer_same_origin_url_ =
https_server_.GetURL("foobar.onion", "/reflect-referrer.html");
reflect_referrer_same_origin_redirect_url_ = https_server_.GetURL(
"foobar.onion",
"/server-redirect-307?" + reflect_referrer_same_origin_url_.spec());
images_url_ = https_server_.GetURL("foobar.onion", "/referrer_images.html");
}

void HandleRequest(const net::test_server::HttpRequest& request) {
base::AutoLock auto_lock(last_headers_lock_);

auto referrer_it = request.headers.find("Referer");
if (referrer_it == request.headers.end()) {
last_referrer_[request.GetURL()] = "";
} else {
last_referrer_[request.GetURL()] = referrer_it->second;
}

auto origin_it = request.headers.find("Origin");
if (origin_it == request.headers.end()) {
last_origin_[request.GetURL()] = "";
} else {
last_origin_[request.GetURL()] = origin_it->second;
}
}

HostContentSettingsMap* content_settings() {
Expand All @@ -61,8 +99,6 @@ class BraveSiteHacksNetworkDelegateBrowserTest : public InProcessBrowserTest {
command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
}

const net::EmbeddedTestServer& https_server() { return https_server_; }

GURL url(const GURL& destination_url, const GURL& navigation_url) {
std::string encoded_destination;
base::Base64UrlEncode(destination_url.spec(),
Expand Down Expand Up @@ -97,6 +133,45 @@ class BraveSiteHacksNetworkDelegateBrowserTest : public InProcessBrowserTest {
}
const GURL& same_site_url() { return same_site_url_; }

const GURL& onion_url() { return onion_url_; }
const GURL& onion_post_url() { return onion_post_url_; }
const GURL& reflect_referrer_cross_origin_url() {
return reflect_referrer_cross_origin_url_;
}
const GURL& reflect_referrer_cross_origin_redirect_url() {
return reflect_referrer_cross_origin_redirect_url_;
}
const GURL& reflect_referrer_same_origin_url() {
return reflect_referrer_same_origin_url_;
}
const GURL& reflect_referrer_same_origin_redirect_url() {
return reflect_referrer_same_origin_redirect_url_;
}

const GURL& images_url() { return images_url_; }
GURL image_url(const std::string& number) {
GURL::Replacements replacements;
replacements.SetPathStr("/logo-referrer.png");
replacements.SetQueryStr(number);
return images_url().ReplaceComponents(replacements);
}

const std::string& last_referrer(const GURL& url) {
base::AutoLock auto_lock(last_headers_lock_);
GURL::Replacements replacements;
replacements.SetHostStr("127.0.0.1");
const GURL internal_url = url.ReplaceComponents(replacements);
return last_referrer_[internal_url];
}

const std::string& last_origin(const GURL& url) {
base::AutoLock auto_lock(last_headers_lock_);
GURL::Replacements replacements;
replacements.SetHostStr("127.0.0.1");
const GURL internal_url = url.ReplaceComponents(replacements);
return last_origin_[internal_url];
}

content::WebContents* contents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
Expand All @@ -119,8 +194,19 @@ class BraveSiteHacksNetworkDelegateBrowserTest : public InProcessBrowserTest {
GURL redirect_to_same_site_landing_url_;
GURL same_site_url_;
GURL simple_landing_url_;
base::FilePath test_data_dir_;

GURL onion_url_;
GURL onion_post_url_;
GURL reflect_referrer_cross_origin_url_;
GURL reflect_referrer_cross_origin_redirect_url_;
GURL reflect_referrer_same_origin_url_;
GURL reflect_referrer_same_origin_redirect_url_;
GURL images_url_;
std::map<GURL, std::string> last_referrer_;
std::map<GURL, std::string> last_origin_;
mutable base::Lock last_headers_lock_;

base::FilePath test_data_dir_;
net::test_server::EmbeddedTestServer https_server_;
};

Expand Down Expand Up @@ -256,3 +342,100 @@ IN_PROC_BROWSER_TEST_F(BraveSiteHacksNetworkDelegateBrowserTest,
EXPECT_EQ(contents()->GetLastCommittedURL(), output);
}
}

IN_PROC_BROWSER_TEST_F(BraveSiteHacksNetworkDelegateBrowserTest,
OnionReferrers) {
// Don't block the mock .onion requests.
tor::OnionLocationNavigationThrottle::BlockOnionRequestsOutsideTorForTesting(
false);

// Same-origin navigations
{
const GURL dest_url = reflect_referrer_same_origin_url();
const GURL same_origin_test_url = url(dest_url, onion_url());
NavigateToURLAndWaitForRedirects(same_origin_test_url, dest_url);
EXPECT_EQ(last_referrer(dest_url), same_origin_test_url.spec());
EXPECT_EQ(last_origin(dest_url), "");

// Redirect
const GURL intermediate_url = reflect_referrer_same_origin_redirect_url();
const GURL same_origin_redirect_test_url =
url(intermediate_url, onion_url());
NavigateToURLAndWaitForRedirects(same_origin_redirect_test_url, dest_url);
EXPECT_EQ(last_referrer(dest_url), same_origin_redirect_test_url.spec());
EXPECT_EQ(last_origin(dest_url), "");
}
{
// POST
const GURL dest_url = reflect_referrer_same_origin_url();
const GURL same_origin_test_url = url(dest_url, onion_post_url());
NavigateToURLAndWaitForRedirects(same_origin_test_url, dest_url);
EXPECT_EQ(last_referrer(dest_url), same_origin_test_url.spec());
std::string full_origin = same_origin_test_url.GetOrigin().spec();
full_origin.pop_back(); // CORS headers don't use canonical forms.
EXPECT_EQ(last_origin(dest_url), full_origin);

// Redirect
const GURL intermediate_url = reflect_referrer_same_origin_redirect_url();
const GURL same_origin_redirect_test_url =
url(intermediate_url, onion_post_url());
NavigateToURLAndWaitForRedirects(same_origin_redirect_test_url, dest_url);
EXPECT_EQ(last_referrer(dest_url), same_origin_redirect_test_url.spec());
EXPECT_EQ(last_origin(dest_url), full_origin);
}

// Cross-origin navigations
{
const GURL dest_url = reflect_referrer_cross_origin_url();
NavigateToURLAndWaitForRedirects(url(dest_url, onion_url()), dest_url);
EXPECT_EQ(last_referrer(dest_url), "");
EXPECT_EQ(last_origin(dest_url), "");

// Redirect
const GURL intermediate_url = reflect_referrer_cross_origin_redirect_url();
NavigateToURLAndWaitForRedirects(url(intermediate_url, onion_url()),
dest_url);
EXPECT_EQ(last_referrer(dest_url), "");
EXPECT_EQ(last_origin(dest_url), "");
}
{
// POST
const GURL dest_url = reflect_referrer_cross_origin_url();
NavigateToURLAndWaitForRedirects(url(dest_url, onion_post_url()), dest_url);
EXPECT_EQ(last_referrer(dest_url), "");
EXPECT_EQ(last_origin(dest_url), "null");

// Redirect
const GURL intermediate_url = reflect_referrer_cross_origin_redirect_url();
NavigateToURLAndWaitForRedirects(url(intermediate_url, onion_post_url()),
dest_url);
EXPECT_EQ(last_referrer(dest_url), "");
EXPECT_EQ(last_origin(dest_url), "null");
}

NavigateToURLAndWaitForRedirects(images_url(), images_url());

// Same-origin sub-requests
std::string full_origin = images_url().GetOrigin().spec();
full_origin.pop_back(); // CORS headers don't use canonical forms.
EXPECT_EQ(last_referrer(image_url("1")), images_url().spec());
EXPECT_EQ(last_origin(image_url("1")), ""); // nocors
EXPECT_EQ(last_referrer(image_url("2")), images_url().spec());
EXPECT_EQ(last_origin(image_url("2")), full_origin);
// Redirects
EXPECT_EQ(last_referrer(image_url("3")), images_url().spec());
EXPECT_EQ(last_origin(image_url("3")), ""); // nocors
EXPECT_EQ(last_referrer(image_url("4")), images_url().spec());
EXPECT_EQ(last_origin(image_url("4")), full_origin);

// Cross-origin sub-requests
EXPECT_EQ(last_referrer(image_url("5")), "");
EXPECT_EQ(last_origin(image_url("5")), ""); // nocors
EXPECT_EQ(last_referrer(image_url("6")), "");
EXPECT_EQ(last_origin(image_url("6")), "null");
// Redirects
EXPECT_EQ(last_referrer(image_url("7")), "");
EXPECT_EQ(last_origin(image_url("7")), ""); // nocors
EXPECT_EQ(last_referrer(image_url("8")), "");
EXPECT_EQ(last_origin(image_url("8")), "null");
}
7 changes: 6 additions & 1 deletion components/tor/onion_location_navigation_throttle.cc
Expand Up @@ -35,6 +35,9 @@ bool GetOnionLocation(const net::HttpResponseHeaders* headers,

} // namespace

bool OnionLocationNavigationThrottle::
block_onion_requests_outside_tor_for_testing_ = true;

// static
std::unique_ptr<OnionLocationNavigationThrottle>
OnionLocationNavigationThrottle::MaybeCreateThrottleFor(
Expand Down Expand Up @@ -106,7 +109,9 @@ OnionLocationNavigationThrottle::WillStartRequest() {
OnionLocationTabHelper::SetOnionLocation(
navigation_handle()->GetWebContents(), url);
}
return content::NavigationThrottle::BLOCK_REQUEST;
return block_onion_requests_outside_tor_for_testing_
? content::NavigationThrottle::BLOCK_REQUEST
: content::NavigationThrottle::PROCEED;
} else {
OnionLocationTabHelper::SetOnionLocation(
navigation_handle()->GetWebContents(), GURL());
Expand Down
5 changes: 5 additions & 0 deletions components/tor/onion_location_navigation_throttle.h
Expand Up @@ -44,7 +44,12 @@ class OnionLocationNavigationThrottle : public content::NavigationThrottle {
ThrottleCheckResult WillStartRequest() override;
const char* GetNameForLogging() override;

static void BlockOnionRequestsOutsideTorForTesting(bool block) {
block_onion_requests_outside_tor_for_testing_ = block;
}

private:
static bool block_onion_requests_outside_tor_for_testing_;
bool is_tor_profile_ = false;

PrefService* pref_service_ = nullptr;
Expand Down
1 change: 1 addition & 0 deletions test/BUILD.gn
Expand Up @@ -745,6 +745,7 @@ if (!is_android) {
"//brave/components/debounce/browser",
"//brave/components/debounce/common",
"//brave/components/resources:strings_grit",
"//brave/components/tor",
"//brave/renderer/test:browser_tests",
"//brave/vendor/bat-native-ads",
"//brave/vendor/bat-native-ledger",
Expand Down
Binary file added test/data/logo-referrer.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions test/data/logo-referrer.png.mock-http-headers
@@ -0,0 +1,4 @@
HTTP/1.1 200 OK
Cache-Control: no-store
Content-Type: image/png
Access-Control-Allow-Origin: *
19 changes: 19 additions & 0 deletions test/data/post-to-site.html
@@ -0,0 +1,19 @@
<html>
<head>
</head>
<body>
<p><form id="form" method="post" action="">
<input type="submit">
</form></p>
<p>Waiting for JS form submission...</p>
<script>
function redirectToDestination() {
const urlParams = new URLSearchParams(window.location.search);
const url = urlParams.get('url');
let form = document.getElementById("form");
form.action = atob(url);
form.submit();
}
setTimeout(redirectToDestination, 100);
</script>
</html>
39 changes: 39 additions & 0 deletions test/data/referrer_images.html
@@ -0,0 +1,39 @@
<html>
<head>
</head>
<body>
<img id="image1" src="" title="image1">
<img id="image2" src="" title="image2c" crossorigin="anonymous">
<img id="image3" src="" title="image3r">
<img id="image4" src="" title="image4rc" crossorigin="anonymous">
<br>
<img id="image5" src="" title="image5x">
<img id="image6" src="" title="image6xc" crossorigin="anonymous">
<img id="image7" src="" title="image7xr">
<img id="image8" src="" title="image8xrc" crossorigin="anonymous">>
<script>
const url = new URL(document.location);

// Same-origin images
let image1 = document.getElementById("image1");
image1.src = "https://" + url.host + "/logo-referrer.png?1";
let image2 = document.getElementById("image2");
image2.src = "https://" + url.host + "/logo-referrer.png?2";
let image3 = document.getElementById("image3");
image3.src = "https://" + url.host + "/cross-site/" + url.hostname + "/logo-referrer.png?3";
let image4 = document.getElementById("image4");
image4.src = "https://" + url.host + "/cross-site/" + url.hostname + "/logo-referrer.png?4";

// Cross-origin images
let image5 = document.getElementById("image5");
image5.src = "https://a.com:" + url.port + "/logo-referrer.png?5";
let image6 = document.getElementById("image6");
image6.src = "https://a.com:" + url.port + "/logo-referrer.png?6";
let image7 = document.getElementById("image7");
image7.src = "https://" + url.host + "/cross-site/a.com/logo-referrer.png?7";
let image8 = document.getElementById("image8");
image8.src = "https://" + url.host + "/cross-site/a.com/logo-referrer.png?8";

</script>
</body>
</html>
9 changes: 9 additions & 0 deletions test/data/reflect-referrer.html
@@ -0,0 +1,9 @@
<html>
<body>
<p>Referrer (JS): <code id="referrer"></code></p>
<script>
var referrer = document.getElementById("referrer");
referrer.innerText = document.referrer;
</script>
</body>
</html>
3 changes: 3 additions & 0 deletions test/data/reflect-referrer.html.mock-http-headers
@@ -0,0 +1,3 @@
HTTP/1.1 200 OK
Cache-Control: no-store
Content-Type: text/html

0 comments on commit 030bf22

Please sign in to comment.