diff --git a/browser/ipfs/test/BUILD.gn b/browser/ipfs/test/BUILD.gn index 87d0de5cedf..404f4456cb8 100644 --- a/browser/ipfs/test/BUILD.gn +++ b/browser/ipfs/test/BUILD.gn @@ -29,6 +29,7 @@ source_set("unittests") { "//brave/components/tor/buildflags", "//chrome/common:channel_info", "//chrome/test:test_support", + "//components/security_interstitials/content:security_interstitial_page", "//content/test:test_support", "//net", "//net:test_support", diff --git a/browser/ipfs/test/ipfs_navigation_throttle_unittest.cc b/browser/ipfs/test/ipfs_navigation_throttle_unittest.cc index 7137859fef2..c20fe13ebf8 100644 --- a/browser/ipfs/test/ipfs_navigation_throttle_unittest.cc +++ b/browser/ipfs/test/ipfs_navigation_throttle_unittest.cc @@ -24,6 +24,7 @@ #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" +#include "components/security_interstitials/content/security_interstitial_tab_helper.h" #include "content/public/browser/navigation_handle.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/mock_navigation_handle.h" @@ -42,6 +43,12 @@ namespace { constexpr char kTestProfileName[] = "TestProfile"; +const GURL& GetIPFSSchemeURL() { + static const GURL ipfs_url( + "ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/"); + return ipfs_url; +} + const GURL& GetIPFSURL() { static const GURL ipfs_url( "http://localhost:48080/ipfs/" @@ -356,6 +363,45 @@ TEST_F(IpfsNavigationThrottleUnitTest, ProceedForAskNodeMode) { << GetIPFSURL(); } +TEST_F(IpfsNavigationThrottleUnitTest, ShowInterstitial) { + profile()->GetPrefs()->SetInteger( + kIPFSResolveMethod, static_cast(IPFSResolveMethodTypes::IPFS_ASK)); + + content::MockNavigationHandle test_handle(web_contents()); + test_handle.set_url(GetIPFSSchemeURL()); + + auto throttle = IpfsNavigationThrottle::MaybeCreateThrottleFor( + &test_handle, ipfs_service(profile()), profile()->GetPrefs(), locale()); + ASSERT_TRUE(throttle != nullptr); + EXPECT_EQ(NavigationThrottle::CANCEL, throttle->WillStartRequest().action()); + + ASSERT_TRUE( + security_interstitials::SecurityInterstitialTabHelper::FromWebContents( + web_contents()) + ->IsInterstitialPendingForNavigation(test_handle.GetNavigationId())); +} + +TEST_F(IpfsNavigationThrottleUnitTest, ShowInterstitialAfterNavigationFails) { + profile()->GetPrefs()->SetInteger( + kIPFSResolveMethod, static_cast(IPFSResolveMethodTypes::IPFS_ASK)); + + content::MockNavigationHandle test_handle(web_contents()); + test_handle.set_url(GetNonIPFSURL()); + + auto throttle = IpfsNavigationThrottle::MaybeCreateThrottleFor( + &test_handle, ipfs_service(profile()), profile()->GetPrefs(), locale()); + ASSERT_TRUE(throttle != nullptr); + EXPECT_EQ(NavigationThrottle::PROCEED, throttle->WillStartRequest().action()) + << GetIPFSURL(); + + test_handle.set_net_error_code(net::ERR_IPFS_RESOLVE_METHOD_NOT_SELECTED); + EXPECT_EQ(NavigationThrottle::CANCEL, throttle->WillFailRequest().action()); + ASSERT_TRUE( + security_interstitials::SecurityInterstitialTabHelper::FromWebContents( + web_contents()) + ->IsInterstitialPendingForNavigation(test_handle.GetNavigationId())); +} + TEST_F(IpfsNavigationThrottleUnitTest, ProceedForNonLocalGatewayURL) { profile()->GetPrefs()->SetInteger( kIPFSResolveMethod, static_cast(IPFSResolveMethodTypes::IPFS_LOCAL)); diff --git a/browser/net/ipfs_redirect_network_delegate_helper.cc b/browser/net/ipfs_redirect_network_delegate_helper.cc index 0fa6f77eaaa..46795328738 100644 --- a/browser/net/ipfs_redirect_network_delegate_helper.cc +++ b/browser/net/ipfs_redirect_network_delegate_helper.cc @@ -32,20 +32,34 @@ int OnBeforeURLRequest_IPFSRedirectWork( auto* prefs = user_prefs::UserPrefs::Get(ctx->browser_context); const bool ipfs_disabled = IsIpfsResolveMethodDisabled(prefs); - if (has_ipfs_scheme && ipfs_disabled) { - ctx->blocked_by = brave::kOtherBlocked; - return net::OK; - } - if (has_ipfs_scheme && !brave::IsRegularProfile(ctx->browser_context)) { // Don't allow IPFS requests without translation of IPFS urls. ctx->blocked_by = brave::kOtherBlocked; // Only net::OK navigation will be actually blocked without commit. + // Show proper error for mainframe navigation. return ctx->resource_type == blink::mojom::ResourceType::kMainFrame ? net::ERR_INCOGNITO_IPFS_NOT_ALLOWED : net::OK; } + if (has_ipfs_scheme && ipfs_disabled) { + ctx->blocked_by = brave::kOtherBlocked; + // Only net::OK navigation will be actually blocked without commit. + // Show proper error for mainframe navigation. + return ctx->resource_type == blink::mojom::ResourceType::kMainFrame + ? net::ERR_IPFS_DISABLED + : net::OK; + } + + if (has_ipfs_scheme && IsIpfsResolveMethodAsk(prefs)) { + ctx->blocked_by = brave::kOtherBlocked; + // Only net::OK navigation will be actually blocked without commit. + // Show proper error for mainframe navigation. + return ctx->resource_type == blink::mojom::ResourceType::kMainFrame + ? net::ERR_IPFS_RESOLVE_METHOD_NOT_SELECTED + : net::OK; + } + GURL new_url; if (ipfs::TranslateIPFSURI(ctx->request_url, &new_url, ctx->ipfs_gateway_url, false)) { diff --git a/browser/net/ipfs_redirect_network_delegate_helper_browsertest.cc b/browser/net/ipfs_redirect_network_delegate_helper_browsertest.cc index bf84928cedf..457647cf218 100644 --- a/browser/net/ipfs_redirect_network_delegate_helper_browsertest.cc +++ b/browser/net/ipfs_redirect_network_delegate_helper_browsertest.cc @@ -72,7 +72,7 @@ IN_PROC_BROWSER_TEST_F(IpfsRedirectNetworkDelegateHelperBrowserTest, } IN_PROC_BROWSER_TEST_F(IpfsRedirectNetworkDelegateHelperBrowserTest, - IPFSResolveRedirectsToErrorPage) { + IPFSResolveRedirectsToErrorPage_Incognito) { GetPrefs()->SetInteger( kIPFSResolveMethod, static_cast(IPFSResolveMethodTypes::IPFS_GATEWAY)); @@ -92,4 +92,24 @@ IN_PROC_BROWSER_TEST_F(IpfsRedirectNetworkDelegateHelperBrowserTest, EXPECT_EQ(net::ERR_INCOGNITO_IPFS_NOT_ALLOWED, observer.net_error_code()); } +IN_PROC_BROWSER_TEST_F(IpfsRedirectNetworkDelegateHelperBrowserTest, + IPFSResolveRedirectsToErrorPage_IpfsDisabled) { + GetPrefs()->SetInteger( + kIPFSResolveMethod, + static_cast(IPFSResolveMethodTypes::IPFS_DISABLED)); + + EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), ipfs_url())); + EXPECT_EQ(web_contents()->GetURL(), ipfs_url()); + + auto* wc = browser()->tab_strip_model()->GetActiveWebContents(); + + content::NavigationHandleObserver observer(wc, ipfs_url()); + + // Try to navigate to the url. The navigation should be canceled and the + // NavigationHandle should have the right error code. + EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), ipfs_url())); + EXPECT_TRUE(wc->GetMainFrame()->IsErrorDocument()); + EXPECT_EQ(net::ERR_IPFS_DISABLED, observer.net_error_code()); +} + } // namespace ipfs diff --git a/browser/net/ipfs_redirect_network_delegate_helper_unittest.cc b/browser/net/ipfs_redirect_network_delegate_helper_unittest.cc index df8954c4747..f390e829ddc 100644 --- a/browser/net/ipfs_redirect_network_delegate_helper_unittest.cc +++ b/browser/net/ipfs_redirect_network_delegate_helper_unittest.cc @@ -60,6 +60,10 @@ class IPFSRedirectNetworkDelegateHelperTest : public testing::Test { }; TEST_F(IPFSRedirectNetworkDelegateHelperTest, TranslateIPFSURIHTTPScheme) { + profile()->GetPrefs()->SetInteger( + kIPFSResolveMethod, + static_cast(IPFSResolveMethodTypes::IPFS_GATEWAY)); + GURL url("http://a.com/ipfs/QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG"); auto brave_request_info = std::make_shared(url); brave_request_info->browser_context = profile(); @@ -70,6 +74,9 @@ TEST_F(IPFSRedirectNetworkDelegateHelperTest, TranslateIPFSURIHTTPScheme) { } TEST_F(IPFSRedirectNetworkDelegateHelperTest, TranslateIPFSURIIPFSSchemeLocal) { + profile()->GetPrefs()->SetInteger( + kIPFSResolveMethod, static_cast(IPFSResolveMethodTypes::IPFS_LOCAL)); + GURL url("ipfs://QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG"); auto brave_request_info = std::make_shared(url); brave_request_info->browser_context = profile(); @@ -85,6 +92,22 @@ TEST_F(IPFSRedirectNetworkDelegateHelperTest, TranslateIPFSURIIPFSSchemeLocal) { "QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG"); } +TEST_F(IPFSRedirectNetworkDelegateHelperTest, + ProperMainFrameErrorCodeWhenIPFSDisabled) { + profile()->GetPrefs()->SetInteger( + kIPFSResolveMethod, + static_cast(IPFSResolveMethodTypes::IPFS_DISABLED)); + + GURL url("ipfs://QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG"); + auto brave_request_info = std::make_shared(url); + brave_request_info->resource_type = blink::mojom::ResourceType::kMainFrame; + brave_request_info->browser_context = profile(); + int rc = ipfs::OnBeforeURLRequest_IPFSRedirectWork(brave::ResponseCallback(), + brave_request_info); + EXPECT_EQ(rc, net::ERR_IPFS_DISABLED); + EXPECT_EQ(brave_request_info->blocked_by, brave::kOtherBlocked); +} + TEST_F(IPFSRedirectNetworkDelegateHelperTest, SubFrameRequestDisabledWhenIPFSDisabled) { profile()->GetPrefs()->SetInteger( @@ -204,6 +227,10 @@ TEST_F(IPFSRedirectNetworkDelegateHelperTest, } TEST_F(IPFSRedirectNetworkDelegateHelperTest, TranslateIPFSURIIPFSScheme) { + profile()->GetPrefs()->SetInteger( + kIPFSResolveMethod, + static_cast(IPFSResolveMethodTypes::IPFS_GATEWAY)); + GURL url("ipfs://QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG"); auto brave_request_info = std::make_shared(url); brave_request_info->browser_context = profile(); @@ -219,6 +246,9 @@ TEST_F(IPFSRedirectNetworkDelegateHelperTest, TranslateIPFSURIIPFSScheme) { } TEST_F(IPFSRedirectNetworkDelegateHelperTest, TranslateIPFSURIIPNSSchemeLocal) { + profile()->GetPrefs()->SetInteger( + kIPFSResolveMethod, static_cast(IPFSResolveMethodTypes::IPFS_LOCAL)); + GURL url("ipns://QmSrPmbaUKA3ZodhzPWZnpFgcPMFWF4QsxXbkWfEptTBJd"); auto brave_request_info = std::make_shared(url); brave_request_info->browser_context = profile(); @@ -235,6 +265,10 @@ TEST_F(IPFSRedirectNetworkDelegateHelperTest, TranslateIPFSURIIPNSSchemeLocal) { } TEST_F(IPFSRedirectNetworkDelegateHelperTest, TranslateIPFSURIIPNSScheme) { + profile()->GetPrefs()->SetInteger( + kIPFSResolveMethod, + static_cast(IPFSResolveMethodTypes::IPFS_GATEWAY)); + GURL url("ipns://QmSrPmbaUKA3ZodhzPWZnpFgcPMFWF4QsxXbkWfEptTBJd"); auto brave_request_info = std::make_shared(url); brave_request_info->browser_context = profile(); diff --git a/chromium_src/components/error_page/common/localized_error.cc b/chromium_src/components/error_page/common/localized_error.cc index 84621b444d2..a4adc1d2edc 100644 --- a/chromium_src/components/error_page/common/localized_error.cc +++ b/chromium_src/components/error_page/common/localized_error.cc @@ -17,6 +17,15 @@ SHOW_NO_BUTTONS, \ }); \ return &error; \ + } else if (error_code == net::ERR_IPFS_DISABLED) { \ + static LocalizedErrorMap error({ \ + net::ERR_IPFS_DISABLED, \ + IDS_ERRORPAGES_IPFS_DISABLED_HEADING, \ + IDS_ERRORPAGES_IPFS_DISABLED_SUMMARY, \ + SUGGEST_NONE, \ + SHOW_BUTTON_RELOAD, \ + }); \ + return &error; \ } namespace error_page { diff --git a/chromium_src/net/base/net_error_list.h b/chromium_src/net/base/net_error_list.h index e2b9697398b..adc995dd361 100644 --- a/chromium_src/net/base/net_error_list.h +++ b/chromium_src/net/base/net_error_list.h @@ -11,3 +11,5 @@ // Error occurs when user tries to access ipfs sites in // incognito context NET_ERROR(INCOGNITO_IPFS_NOT_ALLOWED, -10001) +NET_ERROR(IPFS_DISABLED, -10002) +NET_ERROR(IPFS_RESOLVE_METHOD_NOT_SELECTED, -10003) diff --git a/components/ipfs/ipfs_navigation_throttle.cc b/components/ipfs/ipfs_navigation_throttle.cc index 5800755fe89..29b5feac87a 100644 --- a/components/ipfs/ipfs_navigation_throttle.cc +++ b/components/ipfs/ipfs_navigation_throttle.cc @@ -99,10 +99,7 @@ content::NavigationThrottle::ThrottleCheckResult IpfsNavigationThrottle::WillStartRequest() { GURL url = navigation_handle()->GetURL(); - bool should_ask = - pref_service_->FindPreference(kIPFSResolveMethod) && - pref_service_->GetInteger(kIPFSResolveMethod) == - static_cast(ipfs::IPFSResolveMethodTypes::IPFS_ASK); + bool should_ask = IsIpfsResolveMethodAsk(pref_service_); if (IsIPFSScheme(url) && should_ask) { return ShowIPFSOnboardingInterstitial(); @@ -135,6 +132,16 @@ IpfsNavigationThrottle::WillStartRequest() { return content::NavigationThrottle::PROCEED; } +content::NavigationThrottle::ThrottleCheckResult +IpfsNavigationThrottle::WillFailRequest() { + auto* handle = navigation_handle(); + if (handle && + handle->GetNetErrorCode() == net::ERR_IPFS_RESOLVE_METHOD_NOT_SELECTED) { + return ShowIPFSOnboardingInterstitial(); + } + return content::NavigationThrottle::PROCEED; +} + void IpfsNavigationThrottle::GetConnectedPeers() { ipfs_service_->GetConnectedPeers( base::BindOnce(&IpfsNavigationThrottle::OnGetConnectedPeers, diff --git a/components/ipfs/ipfs_navigation_throttle.h b/components/ipfs/ipfs_navigation_throttle.h index 38ea0f1ecec..31d5e54fb70 100644 --- a/components/ipfs/ipfs_navigation_throttle.h +++ b/components/ipfs/ipfs_navigation_throttle.h @@ -45,6 +45,7 @@ class IpfsNavigationThrottle : public content::NavigationThrottle { // content::NavigationThrottle implementation: ThrottleCheckResult WillStartRequest() override; + ThrottleCheckResult WillFailRequest() override; const char* GetNameForLogging() override; private: @@ -64,6 +65,7 @@ class IpfsNavigationThrottle : public content::NavigationThrottle { void GetConnectedPeers(); void OnGetConnectedPeers(bool success, const std::vector& peers); void OnIpfsLaunched(bool result); + bool ShouldAsk(); bool resume_pending_ = false; IpfsService* ipfs_service_ = nullptr; diff --git a/components/ipfs/ipfs_utils.cc b/components/ipfs/ipfs_utils.cc index 4845d8516f7..d80f44979d9 100644 --- a/components/ipfs/ipfs_utils.cc +++ b/components/ipfs/ipfs_utils.cc @@ -102,6 +102,19 @@ bool IsIpfsResolveMethodDisabled(PrefService* prefs) { static_cast(ipfs::IPFSResolveMethodTypes::IPFS_DISABLED); } +bool IsIpfsResolveMethodAsk(PrefService* prefs) { + DCHECK(prefs); + + // Ignore the actual pref value if IPFS feature is disabled. + if (IsIpfsResolveMethodDisabled(prefs)) { + return false; + } + + return prefs->FindPreference(kIPFSResolveMethod) && + prefs->GetInteger(kIPFSResolveMethod) == + static_cast(ipfs::IPFSResolveMethodTypes::IPFS_ASK); +} + bool IsIpfsMenuEnabled(PrefService* prefs) { return !ipfs::IsIpfsDisabledByFeatureOrPolicy(prefs) && ipfs::IsLocalGatewayConfigured(prefs); diff --git a/components/ipfs/ipfs_utils.h b/components/ipfs/ipfs_utils.h index 96fbc0f3819..3efcdbfed38 100644 --- a/components/ipfs/ipfs_utils.h +++ b/components/ipfs/ipfs_utils.h @@ -61,6 +61,7 @@ bool ParsePeerConnectionString(const std::string& value, GURL ContentHashToCIDv1URL(const std::string& contenthash); bool IsAPIGateway(const GURL& url, version_info::Channel channel); bool IsIpfsResolveMethodDisabled(PrefService* prefs); +bool IsIpfsResolveMethodAsk(PrefService* prefs); std::string GetRegistryDomainFromIPNS(const GURL& url); bool IsValidCIDOrDomain(const std::string& value); diff --git a/components/resources/brave_components_strings.grd b/components/resources/brave_components_strings.grd index cee3e6909ad..7ff8fba2b97 100644 --- a/components/resources/brave_components_strings.grd +++ b/components/resources/brave_components_strings.grd @@ -169,6 +169,12 @@ IPFS pages are not allowed in private windows. + + IPFS page cannot be loaded. + + + IPFS is disabled. Select IPFS resolve method in settings to open this site. + Trackers & ads blocked HTTPS Upgrades