diff --git a/app/brave_generated_resources.grd b/app/brave_generated_resources.grd index 3272bd9f9093..14a9651dadfa 100644 --- a/app/brave_generated_resources.grd +++ b/app/brave_generated_resources.grd @@ -715,6 +715,9 @@ By installing this extension, you are agreeing to the Google Widevine Terms of U Method to resolve Unstoppable Domains + + <a target="_blank" rel="noopener noreferrer" href="$1">Learn More</a> about DNS over HTTPS and Ethereum privacy considerations. + Method to resolve Ethereum Name Service (ENS) diff --git a/browser/decentralized_dns/test/BUILD.gn b/browser/decentralized_dns/test/BUILD.gn index 1b09e76facb3..fc92e7c989d2 100644 --- a/browser/decentralized_dns/test/BUILD.gn +++ b/browser/decentralized_dns/test/BUILD.gn @@ -32,6 +32,7 @@ source_set("unit_tests") { sources = [ "//brave/browser/decentralized_dns/test/decentralized_dns_navigation_throttle_unittest.cc", "//brave/browser/decentralized_dns/test/utils_unittest.cc", + "//brave/browser/net/decentralized_dns_network_delegate_helper_unittest.cc", "//brave/net/dns/brave_resolve_context_unittest.cc", "//brave/net/dns/dns_transaction_unittest.cc", ] @@ -39,6 +40,7 @@ source_set("unit_tests") { deps = [ "//base", "//base/test:test_support", + "//brave/browser/net", "//brave/components/decentralized_dns", "//brave/components/tor/buildflags", "//chrome/test:test_support", diff --git a/browser/decentralized_dns/test/utils_unittest.cc b/browser/decentralized_dns/test/utils_unittest.cc index 6309647de9ca..74579a0ed42a 100644 --- a/browser/decentralized_dns/test/utils_unittest.cc +++ b/browser/decentralized_dns/test/utils_unittest.cc @@ -73,6 +73,15 @@ TEST_P(UtilsUnitTest, IsUnstoppableDomainsResolveMethodDoH) { IsUnstoppableDomainsResolveMethodDoH(local_state())); } +TEST_P(UtilsUnitTest, IsUnstoppableDomainsResolveMethodEthereum) { + EXPECT_FALSE(IsUnstoppableDomainsResolveMethodEthereum(local_state())); + + local_state()->SetInteger(kUnstoppableDomainsResolveMethod, + static_cast(ResolveMethodTypes::ETHEREUM)); + EXPECT_EQ(feature_enabled(), + IsUnstoppableDomainsResolveMethodEthereum(local_state())); +} + TEST_P(UtilsUnitTest, IsENSTLD) { EXPECT_TRUE(IsENSTLD(GURL("http://test.eth"))); EXPECT_FALSE(IsENSTLD(GURL("http://test.com"))); diff --git a/browser/net/BUILD.gn b/browser/net/BUILD.gn index d63bb5b24591..a85a883895af 100644 --- a/browser/net/BUILD.gn +++ b/browser/net/BUILD.gn @@ -1,6 +1,8 @@ import("//brave/browser/translate/buildflags/buildflags.gni") import("//brave/components/brave_referrals/buildflags/buildflags.gni") +import("//brave/components/brave_wallet/common/buildflags/buildflags.gni") import("//brave/components/brave_webtorrent/browser/buildflags/buildflags.gni") +import("//brave/components/decentralized_dns/buildflags/buildflags.gni") import("//brave/components/ipfs/buildflags/buildflags.gni") import("//build/config/features.gni") @@ -54,7 +56,9 @@ source_set("net") { "//brave/components/brave_referrals/buildflags", "//brave/components/brave_shields/browser", "//brave/components/brave_shields/common", + "//brave/components/brave_wallet/common/buildflags", "//brave/components/brave_webtorrent/browser/buildflags", + "//brave/components/decentralized_dns/buildflags", "//brave/components/ipfs/buildflags", "//brave/extensions:common", "//components/content_settings/core/browser", @@ -112,4 +116,16 @@ source_set("net") { "brave_translate_redirect_network_delegate_helper.h", ] } + + if (decentralized_dns_enabled && brave_wallet_enabled) { + sources += [ + "decentralized_dns_network_delegate_helper.cc", + "decentralized_dns_network_delegate_helper.h", + ] + + deps += [ + "//brave/components/brave_wallet/browser", + "//brave/components/decentralized_dns", + ] + } } diff --git a/browser/net/brave_request_handler.cc b/browser/net/brave_request_handler.cc index e9f2c1a69abd..2ebc8d0e03d3 100644 --- a/browser/net/brave_request_handler.cc +++ b/browser/net/brave_request_handler.cc @@ -23,7 +23,9 @@ #include "brave/components/brave_referrals/buildflags/buildflags.h" #include "brave/components/brave_rewards/browser/buildflags/buildflags.h" #include "brave/components/brave_shields/common/features.h" +#include "brave/components/brave_wallet/common/buildflags/buildflags.h" #include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h" +#include "brave/components/decentralized_dns/buildflags/buildflags.h" #include "brave/components/ipfs/buildflags/buildflags.h" #include "chrome/browser/browser_process.h" #include "components/prefs/pref_change_registrar.h" @@ -55,6 +57,10 @@ #include "brave/components/ipfs/features.h" #endif +#if BUILDFLAG(DECENTRALIZED_DNS_ENABLED) +#include "brave/browser/net/decentralized_dns_network_delegate_helper.h" +#endif + static bool IsInternalScheme(std::shared_ptr ctx) { DCHECK(ctx); return ctx->request_url.SchemeIs(extensions::kExtensionScheme) || @@ -84,6 +90,12 @@ void BraveRequestHandler::SetupCallbacks() { callback = base::Bind(brave::OnBeforeURLRequest_CommonStaticRedirectWork); before_url_request_callbacks_.push_back(callback); +#if BUILDFLAG(DECENTRALIZED_DNS_ENABLED) && BUILDFLAG(BRAVE_WALLET_ENABLED) + callback = base::Bind( + decentralized_dns::OnBeforeURLRequest_DecentralizedDnsPreRedirectWork); + before_url_request_callbacks_.push_back(callback); +#endif + #if BUILDFLAG(BRAVE_REWARDS_ENABLED) callback = base::Bind(brave_rewards::OnBeforeURLRequest); before_url_request_callbacks_.push_back(callback); diff --git a/browser/net/decentralized_dns_network_delegate_helper.cc b/browser/net/decentralized_dns_network_delegate_helper.cc new file mode 100644 index 000000000000..c87d50179e0a --- /dev/null +++ b/browser/net/decentralized_dns_network_delegate_helper.cc @@ -0,0 +1,108 @@ +/* Copyright (c) 2021 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/net/decentralized_dns_network_delegate_helper.h" + +#include + +#include "net/base/net_errors.h" + +#include "brave/browser/brave_wallet/brave_wallet_service_factory.h" +#include "brave/components/brave_wallet/browser/brave_wallet_service.h" +#include "brave/components/brave_wallet/browser/brave_wallet_utils.h" +#include "brave/components/brave_wallet/browser/eth_json_rpc_controller.h" +#include "brave/components/decentralized_dns/constants.h" +#include "brave/components/decentralized_dns/utils.h" +#include "chrome/browser/browser_process.h" +#include "content/public/browser/browser_context.h" + +namespace decentralized_dns { + +namespace { + +std::string GetValue(const std::vector& arr, RecordKeys key) { + return arr[static_cast(key)]; +} + +} // namespace + +int OnBeforeURLRequest_DecentralizedDnsPreRedirectWork( + const brave::ResponseCallback& next_callback, + std::shared_ptr ctx) { + if (!ctx->browser_context || !IsDecentralizedDnsEnabled() || + ctx->browser_context->IsOffTheRecord() || !g_browser_process) { + return net::OK; + } + + if (IsUnstoppableDomainsTLD(ctx->request_url) && + IsUnstoppableDomainsResolveMethodEthereum( + g_browser_process->local_state())) { + auto* service = BraveWalletServiceFactory::GetInstance()->GetForContext( + ctx->browser_context); + if (!service) { + return net::OK; + } + + service->controller()->UnstoppableDomainsProxyReaderGetMany( + kProxyReaderContractAddress, ctx->request_url.host(), + std::vector(std::begin(kRecordKeys), + std::end(kRecordKeys)), + base::BindOnce(&OnBeforeURLRequest_DecentralizedDnsRedirectWork, + next_callback, ctx)); + + return net::ERR_IO_PENDING; + } + + return net::OK; +} + +void OnBeforeURLRequest_DecentralizedDnsRedirectWork( + const brave::ResponseCallback& next_callback, + std::shared_ptr ctx, + bool success, + const std::string& result) { + if (!success) { + if (!next_callback.is_null()) + next_callback.Run(); + return; + } + + std::vector output; + size_t offset = 2 /* len of "0x" */ + 64 /* len of offset to array */; + if (offset > result.size() || + !brave_wallet::DecodeStringArray(result.substr(offset), &output)) { + if (!next_callback.is_null()) + next_callback.Run(); + return; + } + + // Redirect to ipfs URI if content hash is set, otherwise, fallback to the + // set redirect URL. If no records available to use, do nothing. See + // https://docs.unstoppabledomains.com/browser-resolution/browser-resolution-algorithm + // for more details. + // + // TODO(jocelyn): Do not fallback to the set redirect URL if dns.A or + // dns.AAAA is not empty once we support the classical DNS records case. + std::string ipfs_uri = GetValue(output, RecordKeys::DWEB_IPFS_HASH); + if (ipfs_uri.empty()) { // Try legacy value. + ipfs_uri = GetValue(output, RecordKeys::IPFS_HTML_VALUE); + } + + std::string fallback_url = GetValue(output, RecordKeys::BROWSER_REDIRECT_URL); + if (fallback_url.empty()) { // Try legacy value. + fallback_url = GetValue(output, RecordKeys::IPFS_REDIRECT_DOMAIN_VALUE); + } + + if (!ipfs_uri.empty()) { + ctx->new_url_spec = GURL("ipfs://" + ipfs_uri).spec(); + } else if (!fallback_url.empty()) { + ctx->new_url_spec = GURL(fallback_url).spec(); + } + + if (!next_callback.is_null()) + next_callback.Run(); +} + +} // namespace decentralized_dns diff --git a/browser/net/decentralized_dns_network_delegate_helper.h b/browser/net/decentralized_dns_network_delegate_helper.h new file mode 100644 index 000000000000..8cdf441c719e --- /dev/null +++ b/browser/net/decentralized_dns_network_delegate_helper.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2021 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_NET_DECENTRALIZED_DNS_NETWORK_DELEGATE_HELPER_H_ +#define BRAVE_BROWSER_NET_DECENTRALIZED_DNS_NETWORK_DELEGATE_HELPER_H_ + +#include +#include + +#include "brave/browser/net/url_context.h" +#include "net/base/completion_once_callback.h" + +namespace decentralized_dns { + +// Issue eth_call requests via Ethereum provider such as Infura to query +// decentralized DNS records, and redirect URL requests based on them. +int OnBeforeURLRequest_DecentralizedDnsPreRedirectWork( + const brave::ResponseCallback& next_callback, + std::shared_ptr ctx); + +void OnBeforeURLRequest_DecentralizedDnsRedirectWork( + const brave::ResponseCallback& next_callback, + std::shared_ptr ctx, + bool success, + const std::string& result); + +} // namespace decentralized_dns + +#endif // BRAVE_BROWSER_NET_DECENTRALIZED_DNS_NETWORK_DELEGATE_HELPER_H_ diff --git a/browser/net/decentralized_dns_network_delegate_helper_unittest.cc b/browser/net/decentralized_dns_network_delegate_helper_unittest.cc new file mode 100644 index 000000000000..5e7c57e83864 --- /dev/null +++ b/browser/net/decentralized_dns_network_delegate_helper_unittest.cc @@ -0,0 +1,252 @@ +/* Copyright (c) 2021 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/net/decentralized_dns_network_delegate_helper.h" + +#include + +#include "base/test/scoped_feature_list.h" +#include "brave/browser/net/url_context.h" +#include "brave/components/decentralized_dns/constants.h" +#include "brave/components/decentralized_dns/features.h" +#include "brave/components/decentralized_dns/pref_names.h" +#include "brave/components/decentralized_dns/utils.h" +#include "chrome/test/base/scoped_testing_local_state.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile.h" +#include "components/prefs/testing_pref_service.h" +#include "content/public/test/browser_task_environment.h" +#include "net/base/net_errors.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +using brave::ResponseCallback; + +namespace decentralized_dns { + +class DecentralizedDnsNetworkDelegateHelperTest : public testing::Test { + public: + DecentralizedDnsNetworkDelegateHelperTest() + : local_state_(std::make_unique( + TestingBrowserProcess::GetGlobal())) {} + + ~DecentralizedDnsNetworkDelegateHelperTest() override = default; + + void SetUp() override { + feature_list_.InitAndEnableFeature(features::kDecentralizedDns); + profile_ = std::make_unique(); + } + + void TearDown() override { + profile_.reset(); + local_state_.reset(); + } + + TestingProfile* profile() { return profile_.get(); } + PrefService* local_state() { return local_state_->Get(); } + + private: + content::BrowserTaskEnvironment task_environment_; + std::unique_ptr profile_; + std::unique_ptr local_state_; + base::test::ScopedFeatureList feature_list_; +}; + +TEST_F(DecentralizedDnsNetworkDelegateHelperTest, + DecentralizedDnsPreRedirectWork) { + GURL url("http://brave.crypto"); + auto brave_request_info = std::make_shared(url); + brave_request_info->browser_context = profile(); + + // No redirect if resolve method is not set to Ethereum. + EXPECT_FALSE(IsUnstoppableDomainsResolveMethodEthereum(local_state())); + int rc = OnBeforeURLRequest_DecentralizedDnsPreRedirectWork( + ResponseCallback(), brave_request_info); + EXPECT_EQ(rc, net::OK); + EXPECT_TRUE(brave_request_info->new_url_spec.empty()); + + local_state()->SetInteger(kUnstoppableDomainsResolveMethod, + static_cast(ResolveMethodTypes::ETHEREUM)); + EXPECT_TRUE(IsUnstoppableDomainsResolveMethodEthereum(local_state())); + + // No redirect for OTR context. + brave_request_info->browser_context = profile()->GetPrimaryOTRProfile(); + rc = OnBeforeURLRequest_DecentralizedDnsPreRedirectWork(ResponseCallback(), + brave_request_info); + EXPECT_EQ(rc, net::OK); + EXPECT_TRUE(brave_request_info->new_url_spec.empty()); + brave_request_info->browser_context = profile(); + + // TLD is not .crypto + brave_request_info->request_url = GURL("http://test.com"); + rc = OnBeforeURLRequest_DecentralizedDnsPreRedirectWork(ResponseCallback(), + brave_request_info); + EXPECT_EQ(rc, net::OK); + EXPECT_TRUE(brave_request_info->new_url_spec.empty()); + brave_request_info->request_url = url; + + rc = OnBeforeURLRequest_DecentralizedDnsPreRedirectWork(ResponseCallback(), + brave_request_info); + EXPECT_EQ(rc, net::ERR_IO_PENDING); +} + +TEST_F(DecentralizedDnsNetworkDelegateHelperTest, + DecentralizedDnsRedirectWork) { + GURL url("http://brave.crypto"); + auto brave_request_info = std::make_shared(url); + + // No redirect for failed requests. + OnBeforeURLRequest_DecentralizedDnsRedirectWork( + ResponseCallback(), brave_request_info, false, ""); + EXPECT_TRUE(brave_request_info->new_url_spec.empty()); + + OnBeforeURLRequest_DecentralizedDnsRedirectWork(ResponseCallback(), + brave_request_info, true, ""); + EXPECT_TRUE(brave_request_info->new_url_spec.empty()); + + // Has both IPFS URI & fallback URL. + std::string result = + // offset for array + "0x0000000000000000000000000000000000000000000000000000000000000020" + // count for array + "0000000000000000000000000000000000000000000000000000000000000006" + // offsets for array elements + "00000000000000000000000000000000000000000000000000000000000000c0" + "0000000000000000000000000000000000000000000000000000000000000120" + "0000000000000000000000000000000000000000000000000000000000000180" + "00000000000000000000000000000000000000000000000000000000000001a0" + "00000000000000000000000000000000000000000000000000000000000001c0" + "0000000000000000000000000000000000000000000000000000000000000200" + // count for "QmWrdNJWMbvRxxzLhojVKaBDswS4KNVM7LvjsN7QbDrvka" + "000000000000000000000000000000000000000000000000000000000000002e" + // encoding for "QmWrdNJWMbvRxxzLhojVKaBDswS4KNVM7LvjsN7QbDrvka" + "516d5772644e4a574d62765278787a4c686f6a564b614244737753344b4e564d" + "374c766a734e3751624472766b61000000000000000000000000000000000000" + // count for "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR" + "000000000000000000000000000000000000000000000000000000000000002e" + // encoding for "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR" + "516d6257717842454b433350387471734b633938786d574e7a727a4474524c4d" + "694d504c387742755447734d6e52000000000000000000000000000000000000" + // count for empty dns.A + "0000000000000000000000000000000000000000000000000000000000000000" + // count for empty dns.AAAA + "0000000000000000000000000000000000000000000000000000000000000000" + // count for "https://fallback1.test.com" + "000000000000000000000000000000000000000000000000000000000000001a" + // encoding for "https://fallback1.test.com" + "68747470733a2f2f66616c6c6261636b312e746573742e636f6d000000000000" + // count for "https://fallback2.test.com" + "000000000000000000000000000000000000000000000000000000000000001a" + // encoding for "https://fallback2.test.com" + "68747470733a2f2f66616c6c6261636b322e746573742e636f6d000000000000"; + + OnBeforeURLRequest_DecentralizedDnsRedirectWork( + ResponseCallback(), brave_request_info, true, result); + EXPECT_EQ("ipfs://QmWrdNJWMbvRxxzLhojVKaBDswS4KNVM7LvjsN7QbDrvka", + brave_request_info->new_url_spec); + + // Has legacy IPFS URI & fallback URL + result = + // offset for array + "0x0000000000000000000000000000000000000000000000000000000000000020" + // count for array + "0000000000000000000000000000000000000000000000000000000000000006" + // offsets for array elements + "00000000000000000000000000000000000000000000000000000000000000c0" + "00000000000000000000000000000000000000000000000000000000000000e0" + "0000000000000000000000000000000000000000000000000000000000000140" + "0000000000000000000000000000000000000000000000000000000000000160" + "0000000000000000000000000000000000000000000000000000000000000180" + "00000000000000000000000000000000000000000000000000000000000001c0" + // count for empty dweb.ipfs.hash + "0000000000000000000000000000000000000000000000000000000000000000" + // count for "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR" + "000000000000000000000000000000000000000000000000000000000000002e" + // encoding for "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR" + "516d6257717842454b433350387471734b633938786d574e7a727a4474524c4d" + "694d504c387742755447734d6e52000000000000000000000000000000000000" + // count for empty dns.A + "0000000000000000000000000000000000000000000000000000000000000000" + // count for empty dns.AAAA + "0000000000000000000000000000000000000000000000000000000000000000" + // count for "https://fallback1.test.com" + "000000000000000000000000000000000000000000000000000000000000001a" + // encoding for "https://fallback1.test.com" + "68747470733a2f2f66616c6c6261636b312e746573742e636f6d000000000000" + // count for "https://fallback2.test.com" + "000000000000000000000000000000000000000000000000000000000000001a" + // encoding for "https://fallback2.test.com" + "68747470733a2f2f66616c6c6261636b322e746573742e636f6d000000000000"; + OnBeforeURLRequest_DecentralizedDnsRedirectWork( + ResponseCallback(), brave_request_info, true, result); + EXPECT_EQ("ipfs://QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR", + brave_request_info->new_url_spec); + + // Has both fallback URL + result = + // offset for array + "0x0000000000000000000000000000000000000000000000000000000000000020" + // count for array + "0000000000000000000000000000000000000000000000000000000000000006" + // offsets for array elements + "00000000000000000000000000000000000000000000000000000000000000c0" + "00000000000000000000000000000000000000000000000000000000000000e0" + "0000000000000000000000000000000000000000000000000000000000000100" + "0000000000000000000000000000000000000000000000000000000000000120" + "0000000000000000000000000000000000000000000000000000000000000140" + "0000000000000000000000000000000000000000000000000000000000000180" + // count for empty dweb.ipfs.hash + "0000000000000000000000000000000000000000000000000000000000000000" + // count for empty ipfs.html.value + "0000000000000000000000000000000000000000000000000000000000000000" + // count for empty dns.A + "0000000000000000000000000000000000000000000000000000000000000000" + // count for empty dns.AAAA + "0000000000000000000000000000000000000000000000000000000000000000" + // count for "https://fallback1.test.com" + "000000000000000000000000000000000000000000000000000000000000001a" + // encoding for "https://fallback1.test.com" + "68747470733a2f2f66616c6c6261636b312e746573742e636f6d000000000000" + // count for "https://fallback2.test.com" + "000000000000000000000000000000000000000000000000000000000000001a" + // encoding for "https://fallback2.test.com" + "68747470733a2f2f66616c6c6261636b322e746573742e636f6d000000000000"; + OnBeforeURLRequest_DecentralizedDnsRedirectWork( + ResponseCallback(), brave_request_info, true, result); + EXPECT_EQ("https://fallback1.test.com/", brave_request_info->new_url_spec); + + // Has legacy URL + result = + // offset for array + "0x0000000000000000000000000000000000000000000000000000000000000020" + // count for array + "0000000000000000000000000000000000000000000000000000000000000006" + // offsets for array elements + "00000000000000000000000000000000000000000000000000000000000000c0" + "00000000000000000000000000000000000000000000000000000000000000e0" + "0000000000000000000000000000000000000000000000000000000000000100" + "0000000000000000000000000000000000000000000000000000000000000120" + "0000000000000000000000000000000000000000000000000000000000000140" + "0000000000000000000000000000000000000000000000000000000000000160" + // count for empty dweb.ipfs.hash + "0000000000000000000000000000000000000000000000000000000000000000" + // count for empty ipfs.html.value + "0000000000000000000000000000000000000000000000000000000000000000" + // count for empty dns.A + "0000000000000000000000000000000000000000000000000000000000000000" + // count for empty dns.AAAA + "0000000000000000000000000000000000000000000000000000000000000000" + // count for empty browser.redirect_url + "0000000000000000000000000000000000000000000000000000000000000000" + // count for "https://fallback2.test.com" + "000000000000000000000000000000000000000000000000000000000000001a" + // encoding for "https://fallback2.test.com" + "68747470733a2f2f66616c6c6261636b322e746573742e636f6d000000000000"; + OnBeforeURLRequest_DecentralizedDnsRedirectWork( + ResponseCallback(), brave_request_info, true, result); + EXPECT_EQ("https://fallback2.test.com/", brave_request_info->new_url_spec); +} + +} // namespace decentralized_dns diff --git a/browser/resources/settings/brave_default_extensions_page/brave_default_extensions_browser_proxy.js b/browser/resources/settings/brave_default_extensions_page/brave_default_extensions_browser_proxy.js index 8935c285f8a5..431bb583fe67 100644 --- a/browser/resources/settings/brave_default_extensions_page/brave_default_extensions_browser_proxy.js +++ b/browser/resources/settings/brave_default_extensions_page/brave_default_extensions_browser_proxy.js @@ -22,7 +22,7 @@ cr.define('settings', function () { getRestartNeeded () {} wasSignInEnabledAtStartup () {} isDecentralizedDnsEnabled() {} - getDecentralizedDnsResolveMethodList() {} + getDecentralizedDnsResolveMethodList(provider) {} } /** @@ -74,8 +74,8 @@ cr.define('settings', function () { return cr.sendWithPromise('isDecentralizedDnsEnabled') } - getDecentralizedDnsResolveMethodList () { - return cr.sendWithPromise('getDecentralizedDnsResolveMethodList') + getDecentralizedDnsResolveMethodList (provider) { + return cr.sendWithPromise('getDecentralizedDnsResolveMethodList', provider) } } diff --git a/browser/resources/settings/brave_default_extensions_page/brave_default_extensions_page.html b/browser/resources/settings/brave_default_extensions_page/brave_default_extensions_page.html index ad40e33be6bf..2a77a64a6cbe 100644 --- a/browser/resources/settings/brave_default_extensions_page/brave_default_extensions_page.html +++ b/browser/resources/settings/brave_default_extensions_page/brave_default_extensions_page.html @@ -87,16 +87,19 @@ - $i18n{resolveUnstoppableDomainsDesc} + + $i18n{resolveUnstoppableDomainsDesc} + $i18nRaw{resolveUnstoppableDomainsSubDesc} + + menu-options="[[unstoppableDomainsResolveMethod_]]"> $i18n{resolveENSDesc} + menu-options="[[ensResolveMethod_]]"> { this.decentralizedDnsEnabled_ = enabled }) - this.browserProxy_.getDecentralizedDnsResolveMethodList().then(list => { - this.decentralizedDnsResolveMethod_ = list + this.browserProxy_.getDecentralizedDnsResolveMethodList( + this.Provider.UNSTOPPABLE_DOMAINS).then(list => { + this.unstoppableDomainsResolveMethod_ = list + }) + this.browserProxy_.getDecentralizedDnsResolveMethodList( + this.Provider.ENS).then(list => { + this.ensResolveMethod_ = list }) }, diff --git a/browser/ui/webui/settings/brave_default_extensions_handler.cc b/browser/ui/webui/settings/brave_default_extensions_handler.cc index 91f1e5af6ed1..0b07a157148e 100644 --- a/browser/ui/webui/settings/brave_default_extensions_handler.cc +++ b/browser/ui/webui/settings/brave_default_extensions_handler.cc @@ -52,6 +52,7 @@ #endif #if BUILDFLAG(DECENTRALIZED_DNS_ENABLED) +#include "brave/components/decentralized_dns/constants.h" #include "brave/components/decentralized_dns/utils.h" #endif @@ -481,13 +482,16 @@ void BraveDefaultExtensionsHandler::IsDecentralizedDnsEnabled( void BraveDefaultExtensionsHandler::GetDecentralizedDnsResolveMethodList( const base::ListValue* args) { - CHECK_EQ(args->GetSize(), 1U); + CHECK_EQ(args->GetSize(), 2U); AllowJavascript(); - ResolveJavascriptCallback(args->GetList()[0], #if BUILDFLAG(DECENTRALIZED_DNS_ENABLED) - decentralized_dns::GetResolveMethodList()); + decentralized_dns::Provider provider = + static_cast(args->GetList()[1].GetInt()); + ResolveJavascriptCallback(args->GetList()[0], + decentralized_dns::GetResolveMethodList(provider)); #else + ResolveJavascriptCallback(args->GetList()[0], base::Value(base::Value::Type::LIST)); #endif } diff --git a/chromium_src/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chromium_src/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index f2dc01bf6fa8..7da111709659 100644 --- a/chromium_src/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chromium_src/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc @@ -60,6 +60,9 @@ const char kGoogleLoginLearnMoreURL[] = "https://github.com/brave/brave-browser/wiki/" "Allow-Google-login---Third-Parties-and-Extensions"; const char kDNSLinkLearnMoreURL[] = "https://docs.ipfs.io/concepts/dnslink/"; +const char kUnstoppableDomainsLearnMoreURL[] = + "https://github.com/brave/brave-browser/wiki/" + "Resolve-Methods-for-Unstoppable-Domains"; void BraveAddCommonStrings(content::WebUIDataSource* html_source, Profile* profile) { @@ -292,6 +295,12 @@ void BraveAddCommonStrings(content::WebUIDataSource* html_source, l10n_util::GetStringFUTF16(IDS_SETTINGS_IPFS_METHOD_DESC, base::ASCIIToUTF16(ipfs::kIPFSLearnMoreURL)); html_source->AddString("ipfsMethodDesc", ipfs_method_desc); + + html_source->AddString( + "resolveUnstoppableDomainsSubDesc", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_RESOLVE_UNSTOPPABLE_DOMAINS_SUB_DESC, + base::ASCIIToUTF16(kUnstoppableDomainsLearnMoreURL))); } void BraveAddResources(content::WebUIDataSource* html_source, diff --git a/components/brave_wallet/browser/eth_call_data_builder.h b/components/brave_wallet/browser/eth_call_data_builder.h index 6d5b6bd86183..32e97ef791de 100644 --- a/components/brave_wallet/browser/eth_call_data_builder.h +++ b/components/brave_wallet/browser/eth_call_data_builder.h @@ -21,6 +21,7 @@ bool BalanceOf(const std::string& address, std::string* data); namespace unstoppable_domains { +// Get mutiple record values mapped with keys of the target domain. bool GetMany(const std::vector& keys, const std::string& domain, std::string* data); diff --git a/components/brave_wallet/browser/eth_json_rpc_controller.h b/components/brave_wallet/browser/eth_json_rpc_controller.h index 315eb39cbef5..6860e7bc5819 100644 --- a/components/brave_wallet/browser/eth_json_rpc_controller.h +++ b/components/brave_wallet/browser/eth_json_rpc_controller.h @@ -48,6 +48,7 @@ class EthJsonRpcController { const std::string& address, GetERC20TokenBalanceCallback callback); + // Call getMany function of ProxyReader contract from Unstoppable Domains. using UnstoppableDomainsProxyReaderGetManyCallback = base::OnceCallback; bool UnstoppableDomainsProxyReaderGetMany( diff --git a/components/decentralized_dns/constants.h b/components/decentralized_dns/constants.h index 1ff0ead2156e..ef6140f735e7 100644 --- a/components/decentralized_dns/constants.h +++ b/components/decentralized_dns/constants.h @@ -8,12 +8,42 @@ namespace decentralized_dns { +enum class Provider { + UNSTOPPABLE_DOMAINS, + ENS, +}; + enum class ResolveMethodTypes { ASK, DISABLED, DNS_OVER_HTTPS, + ETHEREUM, +}; + +enum class RecordKeys { + DWEB_IPFS_HASH, + IPFS_HTML_VALUE, + DNS_A, + DNS_AAAA, + BROWSER_REDIRECT_URL, + IPFS_REDIRECT_DOMAIN_VALUE, + MAX_RECORD_KEY = IPFS_REDIRECT_DOMAIN_VALUE, }; +// Need to match RecordKeys above. See +// https://docs.unstoppabledomains.com/browser-resolution/browser-resolution-algorithm#browser-resolution-records +// for more details. +const constexpr char* const kRecordKeys[] = { + "dweb.ipfs.hash", "ipfs.html.value", "dns.A", + "dns.AAAA", "browser.redirect_url", "ipfs.redirect_domain.value"}; + +static_assert(static_cast(RecordKeys::MAX_RECORD_KEY) + 1u == + sizeof(kRecordKeys) / sizeof(kRecordKeys[0]), + "Size should match between RecordKeys and kRecordKeys."); + +constexpr char kProxyReaderContractAddress[] = + "0xa6E7cEf2EDDEA66352Fd68E5915b60BDbb7309f5"; + } // namespace decentralized_dns #endif // BRAVE_COMPONENTS_DECENTRALIZED_DNS_CONSTANTS_H_ diff --git a/components/decentralized_dns/utils.cc b/components/decentralized_dns/utils.cc index ff2c01609b98..7abf3baabfd0 100644 --- a/components/decentralized_dns/utils.cc +++ b/components/decentralized_dns/utils.cc @@ -57,6 +57,15 @@ bool IsUnstoppableDomainsResolveMethodDoH(PrefService* local_state) { static_cast(ResolveMethodTypes::DNS_OVER_HTTPS); } +bool IsUnstoppableDomainsResolveMethodEthereum(PrefService* local_state) { + if (!local_state || !IsDecentralizedDnsEnabled()) { + return false; // Treat it as disabled. + } + + return local_state->GetInteger(kUnstoppableDomainsResolveMethod) == + static_cast(ResolveMethodTypes::ETHEREUM); +} + bool IsENSTLD(const GURL& url) { return base::EndsWith(url.host_piece(), kEthDomain); } @@ -79,7 +88,7 @@ bool IsENSResolveMethodDoH(PrefService* local_state) { static_cast(ResolveMethodTypes::DNS_OVER_HTTPS); } -base::Value GetResolveMethodList() { +base::Value GetResolveMethodList(Provider provider) { base::Value list(base::Value::Type::LIST); list.Append(MakeSelectValue( ResolveMethodTypes::ASK, @@ -92,6 +101,14 @@ base::Value GetResolveMethodList() { ResolveMethodTypes::DNS_OVER_HTTPS, l10n_util::GetStringUTF16( IDS_DECENTRALIZED_DNS_RESOLVE_OPTION_DNS_OVER_HTTPS))); + + if (provider == Provider::UNSTOPPABLE_DOMAINS) { + list.Append( + MakeSelectValue(ResolveMethodTypes::ETHEREUM, + l10n_util::GetStringUTF16( + IDS_DECENTRALIZED_DNS_RESOLVE_OPTION_ETHEREUM))); + } + return list; } diff --git a/components/decentralized_dns/utils.h b/components/decentralized_dns/utils.h index 48be480a5e99..67278109afca 100644 --- a/components/decentralized_dns/utils.h +++ b/components/decentralized_dns/utils.h @@ -15,17 +15,20 @@ class Value; namespace decentralized_dns { +enum class Provider; + bool IsDecentralizedDnsEnabled(); bool IsUnstoppableDomainsTLD(const GURL& url); bool IsUnstoppableDomainsResolveMethodAsk(PrefService* local_state); bool IsUnstoppableDomainsResolveMethodDoH(PrefService* local_state); +bool IsUnstoppableDomainsResolveMethodEthereum(PrefService* local_state); bool IsENSTLD(const GURL& url); bool IsENSResolveMethodAsk(PrefService* local_state); bool IsENSResolveMethodDoH(PrefService* local_state); -base::Value GetResolveMethodList(); +base::Value GetResolveMethodList(Provider provider); } // namespace decentralized_dns diff --git a/components/resources/decentralized_dns_strings.grdp b/components/resources/decentralized_dns_strings.grdp index e6bfaa0cca8b..f3928daa2294 100644 --- a/components/resources/decentralized_dns_strings.grdp +++ b/components/resources/decentralized_dns_strings.grdp @@ -34,5 +34,8 @@ DNS over HTTPS + + Ethereum +