Skip to content
Permalink
Browse files Browse the repository at this point in the history
Merge pull request #14484 from brave/pr14313_brave_24211_1.43.x
Do not commit subframe navigations for ipfs (uplift to 1.43.x)
  • Loading branch information
LaurenWags committed Aug 8, 2022
2 parents 53d4128 + 213f1ea commit 82d8e39
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 14 deletions.
4 changes: 4 additions & 0 deletions browser/brave_content_browser_client.cc
Expand Up @@ -139,6 +139,7 @@ using extensions::ChromeContentBrowserClientExtensionsPart;
#if BUILDFLAG(ENABLE_IPFS)
#include "brave/browser/ipfs/content_browser_client_helper.h"
#include "brave/browser/ipfs/ipfs_service_factory.h"
#include "brave/browser/ipfs/ipfs_subframe_navigation_throttle.h"
#include "brave/components/ipfs/ipfs_constants.h"
#include "brave/components/ipfs/ipfs_navigation_throttle.h"
#endif
Expand Down Expand Up @@ -965,6 +966,9 @@ BraveContentBrowserClient::CreateThrottlesForNavigation(
#endif

#if BUILDFLAG(ENABLE_IPFS)
throttles.insert(
throttles.begin(),
ipfs::IpfsSubframeNavigationThrottle::CreateThrottleFor(handle));
std::unique_ptr<content::NavigationThrottle> ipfs_navigation_throttle =
ipfs::IpfsNavigationThrottle::MaybeCreateThrottleFor(
handle, ipfs::IpfsServiceFactory::GetForContext(context),
Expand Down
43 changes: 43 additions & 0 deletions browser/ipfs/ipfs_subframe_navigation_throttle.cc
@@ -0,0 +1,43 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "brave/browser/ipfs/ipfs_subframe_navigation_throttle.h"

#include "brave/components/ipfs/ipfs_constants.h"

namespace ipfs {

// static
std::unique_ptr<IpfsSubframeNavigationThrottle>
IpfsSubframeNavigationThrottle::CreateThrottleFor(
content::NavigationHandle* navigation_handle) {
return std::make_unique<IpfsSubframeNavigationThrottle>(navigation_handle);
}

IpfsSubframeNavigationThrottle::IpfsSubframeNavigationThrottle(
content::NavigationHandle* navigation_handle)
: content::NavigationThrottle(navigation_handle) {}

IpfsSubframeNavigationThrottle::~IpfsSubframeNavigationThrottle() {}

// content::NavigationThrottle implementation:
content::NavigationThrottle::ThrottleCheckResult
IpfsSubframeNavigationThrottle::WillFailRequest() {
// Ignores subframe ipfs:// navigation. It is ok to commit toplevel
// navigation.
if (!navigation_handle()->IsInMainFrame() &&
(navigation_handle()->GetURL().SchemeIs(ipfs::kIPFSScheme) ||
navigation_handle()->GetURL().SchemeIs(ipfs::kIPNSScheme))) {
return {content::NavigationThrottle::CANCEL_AND_IGNORE,
navigation_handle()->GetNetErrorCode()};
}
return content::NavigationThrottle::PROCEED;
}

const char* IpfsSubframeNavigationThrottle::GetNameForLogging() {
return "IpfsSubframeNavigationThrottle";
}

} // namespace ipfs
42 changes: 42 additions & 0 deletions browser/ipfs/ipfs_subframe_navigation_throttle.h
@@ -0,0 +1,42 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef BRAVE_BROWSER_IPFS_IPFS_SUBFRAME_NAVIGATION_THROTTLE_H_
#define BRAVE_BROWSER_IPFS_IPFS_SUBFRAME_NAVIGATION_THROTTLE_H_

#include <memory>

#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/navigation_throttle.h"

namespace ipfs {

// Prevents commiting of subframe IPFS navigations.
// IPFS urls must be changed to proper gateway urls.
// See ipfs_redirect_network_delegate_helper.h for example.
class IpfsSubframeNavigationThrottle : public content::NavigationThrottle {
public:
static std::unique_ptr<IpfsSubframeNavigationThrottle> CreateThrottleFor(
content::NavigationHandle* navigation_handle);

explicit IpfsSubframeNavigationThrottle(
content::NavigationHandle* navigation_handle);
~IpfsSubframeNavigationThrottle() override;

IpfsSubframeNavigationThrottle(const IpfsSubframeNavigationThrottle&) =
delete;
IpfsSubframeNavigationThrottle& operator=(
const IpfsSubframeNavigationThrottle&) = delete;

// content::NavigationThrottle implementation:
// This is called before navigation commits with error.
// Here we can cancel subframe navigation for ipfs:// urls.
content::NavigationThrottle::ThrottleCheckResult WillFailRequest() override;
const char* GetNameForLogging() override;
};

} // namespace ipfs

#endif // BRAVE_BROWSER_IPFS_IPFS_SUBFRAME_NAVIGATION_THROTTLE_H_
2 changes: 2 additions & 0 deletions browser/ipfs/sources.gni
Expand Up @@ -25,6 +25,8 @@ if (enable_ipfs) {
"//brave/browser/ipfs/ipfs_host_resolver.h",
"//brave/browser/ipfs/ipfs_service_factory.cc",
"//brave/browser/ipfs/ipfs_service_factory.h",
"//brave/browser/ipfs/ipfs_subframe_navigation_throttle.cc",
"//brave/browser/ipfs/ipfs_subframe_navigation_throttle.h",
"//brave/browser/ipfs/ipfs_tab_helper.cc",
"//brave/browser/ipfs/ipfs_tab_helper.h",
]
Expand Down
112 changes: 100 additions & 12 deletions browser/ipfs/test/ipfs_service_browsertest.cc
Expand Up @@ -431,6 +431,15 @@ class IpfsServiceBrowserTest : public InProcessBrowserTest {
http_response->set_content(
"<iframe "
"src='ipfs://Qmc2JTQo4iXf24g98otZmGFQq176eQ2Cdbb88qA5ToMEvC/2'>"
"</iframe>"
"<iframe "
"src='ipfs://10.10.1.1'>"
"</iframe>"
"<iframe "
"src='ipns://10.10.1.1'>"
"</iframe>"
"<iframe "
"src='ipfs://'>"
"</iframe>");
http_response->set_code(net::HTTP_OK);
} else if (request_path ==
Expand Down Expand Up @@ -840,8 +849,49 @@ IN_PROC_BROWSER_TEST_F(IpfsServiceBrowserTest, CanFetchIPFSResourcesFromIPFS) {
EXPECT_EQ(base::Value(true), got_fetch.value);
}

// Make sure an <iframe src="ipfs://..."> cannot load within http:// scheme in
// incognito
IN_PROC_BROWSER_TEST_F(IpfsServiceBrowserTest,
CannotLoadIframeFromHTTP_Incognito) {
browser()->profile()->GetPrefs()->SetInteger(
kIPFSResolveMethod,
static_cast<int>(ipfs::IPFSResolveMethodTypes::IPFS_LOCAL));

ResetTestServer(
base::BindRepeating(&IpfsServiceBrowserTest::HandleEmbeddedSrvrRequest,
base::Unretained(this)));
SetIPFSDefaultGatewayForTest(GetURL("b.com", "/"));
Browser* private_browser = CreateIncognitoBrowser(nullptr);

ASSERT_TRUE(ui_test_utils::NavigateToURL(private_browser,
GetURL("b.com", "/iframe.html")));
content::WebContents* contents =
private_browser->tab_strip_model()->GetActiveWebContents();

int child_index = 0;
while (auto* child_frame =
ChildFrameAt(contents->GetMainFrame(), child_index++)) {
auto location =
EvalJs(child_frame,
"const timer = setInterval(function () {"
" if (document.readyState == 'complete') {"
" clearInterval(timer);"
" window.domAutomationController.send(window.location.href);"
" }"
"}, 100);",
content::EXECUTE_SCRIPT_USE_MANUAL_REPLY);

ASSERT_TRUE(location.error.empty());
EXPECT_EQ(base::Value("chrome-error://chromewebdata/"), location.value);
}
}

// Make sure an <iframe src="ipfs://..."> cannot load within http:// scheme
IN_PROC_BROWSER_TEST_F(IpfsServiceBrowserTest, CannotLoadIframeFromHTTP) {
browser()->profile()->GetPrefs()->SetInteger(
kIPFSResolveMethod,
static_cast<int>(ipfs::IPFSResolveMethodTypes::IPFS_ASK));

ResetTestServer(
base::BindRepeating(&IpfsServiceBrowserTest::HandleEmbeddedSrvrRequest,
base::Unretained(this)));
Expand All @@ -851,19 +901,57 @@ IN_PROC_BROWSER_TEST_F(IpfsServiceBrowserTest, CannotLoadIframeFromHTTP) {
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();

auto* child_frame = ChildFrameAt(contents->GetMainFrame(), 0);
auto location =
EvalJs(child_frame,
"const timer = setInterval(function () {"
" if (document.readyState == 'complete') {"
" clearInterval(timer);"
" window.domAutomationController.send(window.location.href);"
" }"
"}, 100);",
content::EXECUTE_SCRIPT_USE_MANUAL_REPLY);
int child_index = 0;
while (auto* child_frame =
ChildFrameAt(contents->GetMainFrame(), child_index++)) {
auto location =
EvalJs(child_frame,
"const timer = setInterval(function () {"
" if (document.readyState == 'complete') {"
" clearInterval(timer);"
" window.domAutomationController.send(window.location.href);"
" }"
"}, 100);",
content::EXECUTE_SCRIPT_USE_MANUAL_REPLY);

ASSERT_TRUE(location.error.empty());
EXPECT_EQ(base::Value("chrome-error://chromewebdata/"), location.value);
}
}

// Make sure an <iframe src="ipfs://..."> cannot load within http:// scheme when
// ipfs is disabled
IN_PROC_BROWSER_TEST_F(IpfsServiceBrowserTest,
CannotLoadIframeFromHTTP_IPFSDisabled) {
browser()->profile()->GetPrefs()->SetInteger(
kIPFSResolveMethod,
static_cast<int>(ipfs::IPFSResolveMethodTypes::IPFS_DISABLED));

ASSERT_TRUE(location.error.empty());
EXPECT_EQ(base::Value("chrome-error://chromewebdata/"), location.value);
ResetTestServer(
base::BindRepeating(&IpfsServiceBrowserTest::HandleEmbeddedSrvrRequest,
base::Unretained(this)));
SetIPFSDefaultGatewayForTest(GetURL("b.com", "/"));
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), GetURL("b.com", "/iframe.html")));
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();

int child_index = 0;
while (auto* child_frame =
ChildFrameAt(contents->GetMainFrame(), child_index++)) {
auto location =
EvalJs(child_frame,
"const timer = setInterval(function () {"
" if (document.readyState == 'complete') {"
" clearInterval(timer);"
" window.domAutomationController.send(window.location.href);"
" }"
"}, 100);",
content::EXECUTE_SCRIPT_USE_MANUAL_REPLY);

ASSERT_TRUE(location.error.empty());
EXPECT_EQ(base::Value("chrome-error://chromewebdata/"), location.value);
}
}

// Make sure an <iframe src="ipfs://..."> can load within another ipfs:// scheme
Expand Down
5 changes: 4 additions & 1 deletion browser/net/ipfs_redirect_network_delegate_helper.cc
Expand Up @@ -40,7 +40,10 @@ int OnBeforeURLRequest_IPFSRedirectWork(
if (has_ipfs_scheme && !brave::IsRegularProfile(ctx->browser_context)) {
// Don't allow IPFS requests without translation of IPFS urls.
ctx->blocked_by = brave::kOtherBlocked;
return net::ERR_INCOGNITO_IPFS_NOT_ALLOWED;
// Only net::OK navigation will be actually blocked without commit.
return ctx->resource_type == blink::mojom::ResourceType::kMainFrame
? net::ERR_INCOGNITO_IPFS_NOT_ALLOWED
: net::OK;
}

GURL new_url;
Expand Down
18 changes: 17 additions & 1 deletion browser/net/ipfs_redirect_network_delegate_helper_unittest.cc
Expand Up @@ -108,7 +108,7 @@ TEST_F(IPFSRedirectNetworkDelegateHelperTest,

GURL url("ipfs://QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG");
auto brave_request_info = std::make_shared<brave::BraveRequestInfo>(url);
brave_request_info->resource_type = blink::mojom::ResourceType::kSubFrame;
brave_request_info->resource_type = blink::mojom::ResourceType::kMainFrame;
brave_request_info->browser_context = profile()->GetOffTheRecordProfile(
Profile::OTRProfileID::CreateUnique("incognito"), true);
int rc = ipfs::OnBeforeURLRequest_IPFSRedirectWork(brave::ResponseCallback(),
Expand All @@ -117,6 +117,22 @@ TEST_F(IPFSRedirectNetworkDelegateHelperTest,
EXPECT_EQ(brave_request_info->blocked_by, brave::kOtherBlocked);
}

TEST_F(IPFSRedirectNetworkDelegateHelperTest,
SubFrameRequestDisabledWhenIPFSDisabled_Incognito_Subframe) {
profile()->GetPrefs()->SetInteger(
kIPFSResolveMethod, static_cast<int>(IPFSResolveMethodTypes::IPFS_LOCAL));

GURL url("ipfs://QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG");
auto brave_request_info = std::make_shared<brave::BraveRequestInfo>(url);
brave_request_info->resource_type = blink::mojom::ResourceType::kSubFrame;
brave_request_info->browser_context = profile()->GetOffTheRecordProfile(
Profile::OTRProfileID::CreateUnique("incognito"), true);
int rc = ipfs::OnBeforeURLRequest_IPFSRedirectWork(brave::ResponseCallback(),
brave_request_info);
EXPECT_EQ(rc, net::OK);
EXPECT_EQ(brave_request_info->blocked_by, brave::kOtherBlocked);
}

TEST_F(IPFSRedirectNetworkDelegateHelperTest,
LoadDisabledWhenIPFS_WhenWrongIPFSUrl) {
profile()->GetPrefs()->SetInteger(
Expand Down

0 comments on commit 82d8e39

Please sign in to comment.