Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support resolution of unstoppable domains with IPFS records via Ethereum #8456

Merged
merged 6 commits into from
Apr 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/brave_generated_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,9 @@ By installing this extension, you are agreeing to the Google Widevine Terms of U
<message name="IDS_SETTINGS_RESOLVE_UNSTOPPABLE_DOMAINS_DESC" desc="The description for how to handle Unstoppable Domains">
Method to resolve Unstoppable Domains
</message>
<message name="IDS_SETTINGS_RESOLVE_UNSTOPPABLE_DOMAINS_SUB_DESC" desc="The sub-description for how to handle Unstoppable Domains">
<ph name="BEGIN_LINK">&lt;a target="_blank" rel="noopener noreferrer" href="$1"&gt;</ph>Learn More<ph name="END_LINK">&lt;/a&gt;</ph> about DNS over HTTPS and Ethereum privacy considerations.
</message>
<message name="IDS_SETTINGS_RESOLVE_ENS_DESC" desc="The description for how to handle ENS">
Method to resolve Ethereum Name Service (ENS)
</message>
Expand Down
2 changes: 2 additions & 0 deletions browser/decentralized_dns/test/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ 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",
]

deps = [
"//base",
"//base/test:test_support",
"//brave/browser/net",
"//brave/components/decentralized_dns",
"//brave/components/tor/buildflags",
"//chrome/test:test_support",
Expand Down
9 changes: 9 additions & 0 deletions browser/decentralized_dns/test/utils_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>(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")));
Expand Down
16 changes: 16 additions & 0 deletions browser/net/BUILD.gn
Original file line number Diff line number Diff line change
@@ -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")

Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
]
}
}
12 changes: 12 additions & 0 deletions browser/net/brave_request_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<brave::BraveRequestInfo> ctx) {
DCHECK(ctx);
return ctx->request_url.SchemeIs(extensions::kExtensionScheme) ||
Expand Down Expand Up @@ -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);
Expand Down
108 changes: 108 additions & 0 deletions browser/net/decentralized_dns_network_delegate_helper.cc
Original file line number Diff line number Diff line change
@@ -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 <vector>

#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<std::string>& arr, RecordKeys key) {
return arr[static_cast<size_t>(key)];
}

} // namespace

int OnBeforeURLRequest_DecentralizedDnsPreRedirectWork(
const brave::ResponseCallback& next_callback,
std::shared_ptr<brave::BraveRequestInfo> 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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not really clear: "many" of what? and the method doesn't explain anything

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also curious whether we consider the endpoint as trustworthy.. In theory, we'd better to follow Rule of 2: https://chromium.googlesource.com/chromium/src/+/master/docs/security/rule-of-2.md
probably something to consider during sec review

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's calling getMany function defined by Unstoppable Domains's ProxyReader smart contract.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We issue these calls to Unstoppable Domains smart contract via Infura to the Ethereum network.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some more comments in 1cdb4f081decc67ac46ac53ed9bee83fcf3ebb34, and created security review issue.

kProxyReaderContractAddress, ctx->request_url.host(),
std::vector<std::string>(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<brave::BraveRequestInfo> ctx,
bool success,
const std::string& result) {
if (!success) {
if (!next_callback.is_null())
next_callback.Run();
return;
}

std::vector<std::string> 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
31 changes: 31 additions & 0 deletions browser/net/decentralized_dns_network_delegate_helper.h
Original file line number Diff line number Diff line change
@@ -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 <memory>
#include <string>

#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<brave::BraveRequestInfo> ctx);

void OnBeforeURLRequest_DecentralizedDnsRedirectWork(
const brave::ResponseCallback& next_callback,
std::shared_ptr<brave::BraveRequestInfo> ctx,
bool success,
const std::string& result);

} // namespace decentralized_dns

#endif // BRAVE_BROWSER_NET_DECENTRALIZED_DNS_NETWORK_DELEGATE_HELPER_H_
Loading