From 6538fe56825659fe4f0b959c99016062fcb9b10b Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 13 Jul 2020 17:02:28 -0400 Subject: [PATCH] Add IPFS protocol support with gateway --- .../brave_autocomplete_scheme_classifier.cc | 13 ++ browser/brave_content_browser_client.cc | 19 +++ common/url_constants.cc | 2 + common/url_constants.h | 2 + components/ipfs/browser/BUILD.gn | 1 + .../browser/content_browser_client_helper.h | 122 ++++++++++++++++++ 6 files changed, 159 insertions(+) create mode 100644 components/ipfs/browser/content_browser_client_helper.h diff --git a/browser/autocomplete/brave_autocomplete_scheme_classifier.cc b/browser/autocomplete/brave_autocomplete_scheme_classifier.cc index c7f30f6e9290..5ac93b088f88 100644 --- a/browser/autocomplete/brave_autocomplete_scheme_classifier.cc +++ b/browser/autocomplete/brave_autocomplete_scheme_classifier.cc @@ -9,6 +9,7 @@ #include "base/strings/string_util.h" #include "brave/common/url_constants.h" +#include "brave/components/ipfs/browser/buildflags/buildflags.h" #include "chrome/browser/profiles/profile.h" #if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT) @@ -37,6 +38,10 @@ BraveAutocompleteSchemeClassifier::GetInputTypeForScheme( base::LowerCaseEqualsASCII(scheme, kBraveUIScheme)) { return metrics::OmniboxInputType::URL; } + if (base::IsStringASCII(scheme) && + base::LowerCaseEqualsASCII(scheme, kBraveUIScheme)) { + return metrics::OmniboxInputType::URL; + } #if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT) if (base::IsStringASCII(scheme) && @@ -46,5 +51,13 @@ BraveAutocompleteSchemeClassifier::GetInputTypeForScheme( } #endif +#if BUILDFLAG(IPFS_ENABLED) + if (base::IsStringASCII(scheme) && + base::LowerCaseEqualsASCII(scheme, kIPFSScheme)) { + return metrics::OmniboxInputType::URL; + } +#endif + + return ChromeAutocompleteSchemeClassifier::GetInputTypeForScheme(scheme); } diff --git a/browser/brave_content_browser_client.cc b/browser/brave_content_browser_client.cc index 44b06f762e6d..9f3a837f4286 100644 --- a/browser/brave_content_browser_client.cc +++ b/browser/brave_content_browser_client.cc @@ -31,6 +31,7 @@ #include "brave/components/brave_shields/common/brave_shield_constants.h" #include "brave/components/brave_wallet/browser/buildflags/buildflags.h" #include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h" +#include "brave/components/ipfs/browser/buildflags/buildflags.h" #include "brave/components/services/brave_content_browser_overlay_manifest.h" #include "brave/components/speedreader/buildflags.h" #include "brave/grit/brave_generated_resources.h" @@ -83,6 +84,10 @@ using extensions::ChromeContentBrowserClientExtensionsPart; #include "brave/browser/extensions/brave_webtorrent_navigation_throttle.h" #endif +#if BUILDFLAG(IPFS_ENABLED) +#include "brave/components/ipfs/browser/content_browser_client_helper.h" +#endif + #if BUILDFLAG(BRAVE_REWARDS_ENABLED) #include "brave/components/brave_rewards/browser/rewards_protocol_handler.h" #endif @@ -159,6 +164,12 @@ void BraveContentBrowserClient::BrowserURLHandlerCreated( content::BrowserURLHandler::null_handler()); handler->AddHandlerPair(&webtorrent::HandleTorrentURLRewrite, &webtorrent::HandleTorrentURLReverseRewrite); +#endif +#if BUILDFLAG(IPFS_ENABLED) + handler->AddHandlerPair(&ipfs::HandleIPFSURLRewrite, + content::BrowserURLHandler::null_handler()); + handler->AddHandlerPair(&ipfs::HandleIPFSURLRewrite, + &ipfs::HandleIPFSURLReverseRewrite); #endif handler->AddHandlerPair(&HandleURLRewrite, &HandleURLReverseOverrideRewrite); ChromeContentBrowserClient::BrowserURLHandlerCreated(handler); @@ -190,6 +201,14 @@ bool BraveContentBrowserClient::HandleExternalProtocol( return true; } #endif +#if BUILDFLAG(IPFS_ENABLED) + if (ipfs::IsIPFSProtocol(url)) { + ipfs::HandleIPFSProtocol(url, std::move(web_contents_getter), + page_transition, has_user_gesture, + initiating_origin); + return true; + } +#endif #if BUILDFLAG(BRAVE_REWARDS_ENABLED) if (brave_rewards::IsRewardsProtocol(url)) { diff --git a/common/url_constants.cc b/common/url_constants.cc index 636cd1587ba5..ef911e641121 100644 --- a/common/url_constants.cc +++ b/common/url_constants.cc @@ -9,6 +9,8 @@ const char kChromeExtensionScheme[] = "chrome-extension"; const char kBraveUIScheme[] = "brave"; const char kMagnetScheme[] = "magnet"; +const char kIPFSScheme[] = "ipfs"; +const char kDefaultIPFSGateway[] = "https://dweb.link/ipfs/"; const char kBinanceScheme[] = "com.brave.binance"; const char kGeminiScheme[] = "com.brave.gemini"; const char kWidevineMoreInfoURL[] = "https://www.eff.org/issues/drm"; diff --git a/common/url_constants.h b/common/url_constants.h index fd2d5417e245..d8b681bb0843 100644 --- a/common/url_constants.h +++ b/common/url_constants.h @@ -10,6 +10,8 @@ extern const char kChromeExtensionScheme[]; extern const char kBraveUIScheme[]; extern const char kMagnetScheme[]; +extern const char kIPFSScheme[]; +extern const char kDefaultIPFSGateway[]; extern const char kBinanceScheme[]; extern const char kGeminiScheme[]; extern const char kWidevineMoreInfoURL[]; diff --git a/components/ipfs/browser/BUILD.gn b/components/ipfs/browser/BUILD.gn index 39344da53459..d935cd9fd051 100644 --- a/components/ipfs/browser/BUILD.gn +++ b/components/ipfs/browser/BUILD.gn @@ -2,6 +2,7 @@ source_set("browser") { sources = [ "brave_ipfs_client_updater.cc", "brave_ipfs_client_updater.h", + "content_browser_client_helper.h", "ipfs_service.cc", "ipfs_service.h", ] diff --git a/components/ipfs/browser/content_browser_client_helper.h b/components/ipfs/browser/content_browser_client_helper.h new file mode 100644 index 000000000000..a162a3824054 --- /dev/null +++ b/components/ipfs/browser/content_browser_client_helper.h @@ -0,0 +1,122 @@ +/* Copyright (c) 2019 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_COMPONENTS_IPFS_BROWSER_CONTENT_BROWSER_CLIENT_HELPER_H_ +#define BRAVE_COMPONENTS_IPFS_BROWSER_CONTENT_BROWSER_CLIENT_HELPER_H_ + +#include +#include + +#include "base/strings/strcat.h" +#include "base/strings/string_util.h" +#include "base/task/post_task.h" +#include "brave/common/url_constants.h" +#include "brave/common/extensions/extension_constants.h" +#include "chrome/browser/external_protocol/external_protocol_handler.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/constants.h" +#include "extensions/common/extension_set.h" +#include "net/base/escape.h" + +namespace ipfs { + +static bool TranslateIPFSURL(const GURL& url, GURL* new_url) { + if (!url.SchemeIs(kIPFSScheme)) { + return false; + } + + std::string path = url.path(); + // In the case of a URL like ipfs://[cid]/wiki/Vincent_van_Gogh.html + // host is empty and path is //wiki/Vincent_van_Gogh.html + if (url.host().empty() && path.length() > 2 && + path.substr(0, 2) == "//") { + std::string cid(path.substr(2)); + // If we have a path after the CID, get at the real resource path + size_t pos = cid.find("/"); + std::string path; + if (pos != std::string::npos && pos != 0) { + // path would be /wiki/Vincent_van_Gogh.html + path = cid.substr(pos, cid.length() - pos); + // cid would be [cid] + cid = cid.substr(0, pos); + } + if (std::all_of(cid.begin(), cid.end(), + [loc = std::locale{}](char c) { + return std::isalnum(c, loc); + })) { + // new_url would be: + // https://dweb.link/ipfs/[cid]//wiki/Vincent_van_Gogh.html + *new_url = GURL(std::string(kDefaultIPFSGateway) + cid + path); + return true; + } + } + return false; +} + +static bool HandleIPFSURLReverseRewrite(GURL* url, + content::BrowserContext* browser_context) { + return false; +} + +static void LoadOrLaunchIPFSURL( + const GURL& url, + content::WebContents::OnceGetter web_contents_getter, + ui::PageTransition page_transition, + bool has_user_gesture, + const base::Optional& initiating_origin) { + content::WebContents* web_contents = std::move(web_contents_getter).Run(); + if (!web_contents) + return; + + web_contents->GetController().LoadURL(url, content::Referrer(), + page_transition, std::string()); + // TODO: We probably want something more like this: + /* + if (IsWebtorrentEnabled(web_contents->GetBrowserContext())) { + web_contents->GetController().LoadURL(url, content::Referrer(), + page_transition, std::string()); + } else { + ExternalProtocolHandler::LaunchUrl( + url, web_contents->GetRenderViewHost()->GetProcess()->GetID(), + web_contents->GetRenderViewHost()->GetRoutingID(), page_transition, + has_user_gesture, initiating_origin); + } + */ +} + +static bool HandleIPFSURLRewrite(GURL* url, + content::BrowserContext* browser_context) { + if (url->SchemeIs(kIPFSScheme)) { + return TranslateIPFSURL(*url, url); + } + + return false; +} + +static void HandleIPFSProtocol( + const GURL& url, + content::WebContents::OnceGetter web_contents_getter, + ui::PageTransition page_transition, + bool has_user_gesture, + const base::Optional& initiating_origin) { + DCHECK(url.SchemeIs(kIPFSScheme)); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&LoadOrLaunchIPFSURL, url, + std::move(web_contents_getter), page_transition, + has_user_gesture, initiating_origin)); +} + +static bool IsIPFSProtocol(const GURL& url) { + GURL new_url; + return TranslateIPFSURL(url, &new_url); +} + +} // namespace ipfs + +#endif // BRAVE_COMPONENTS_IPFS_BROWSER_CONTENT_BROWSER_CLIENT_HELPER_H_