Skip to content

Commit b1ab968

Browse files
Merge pull request #13780 from brave/dapps_active_tab
Dapps active tab
2 parents b71e60c + 8605448 commit b1ab968

11 files changed

+218
-0
lines changed

browser/brave_wallet/brave_wallet_provider_delegate_impl.cc

+7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "brave/components/permissions/contexts/brave_wallet_permission_context.h"
1818
#include "components/content_settings/core/common/content_settings.h"
1919
#include "content/public/browser/render_frame_host.h"
20+
#include "content/public/browser/visibility.h"
2021
#include "content/public/browser/web_contents.h"
2122

2223
namespace brave_wallet {
@@ -93,6 +94,12 @@ url::Origin BraveWalletProviderDelegateImpl::GetOrigin() const {
9394
return rfh ? rfh->GetLastCommittedOrigin() : url::Origin();
9495
}
9596

97+
bool BraveWalletProviderDelegateImpl::IsTabVisible() {
98+
return web_contents_
99+
? web_contents_->GetVisibility() == content::Visibility::VISIBLE
100+
: false;
101+
}
102+
96103
void BraveWalletProviderDelegateImpl::ShowPanel() {
97104
::brave_wallet::ShowPanel(web_contents_);
98105
}

browser/brave_wallet/brave_wallet_provider_delegate_impl.h

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class BraveWalletProviderDelegateImpl : public BraveWalletProviderDelegate,
3535
const BraveWalletProviderDelegateImpl&) = delete;
3636
~BraveWalletProviderDelegateImpl() override;
3737

38+
bool IsTabVisible() override;
3839
void ShowPanel() override;
3940
void WalletInteractionDetected() override;
4041
void ShowWalletOnboarding() override;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
4+
* You can obtain one at http://mozilla.org/MPL/2.0/. */
5+
6+
#include "base/command_line.h"
7+
#include "base/memory/raw_ptr.h"
8+
#include "base/path_service.h"
9+
#include "base/test/bind.h"
10+
#include "brave/browser/brave_wallet/keyring_service_factory.h"
11+
#include "brave/components/brave_wallet/browser/keyring_service.h"
12+
#include "brave/components/constants/brave_paths.h"
13+
#include "chrome/browser/profiles/profile.h"
14+
#include "chrome/browser/ui/browser.h"
15+
#include "chrome/test/base/in_process_browser_test.h"
16+
#include "chrome/test/base/ui_test_utils.h"
17+
#include "components/network_session_configurator/common/network_switches.h"
18+
#include "content/public/browser/web_contents.h"
19+
#include "content/public/test/browser_test.h"
20+
#include "content/public/test/browser_test_utils.h"
21+
#include "content/public/test/test_utils.h"
22+
#include "net/dns/mock_host_resolver.h"
23+
#include "net/test/embedded_test_server/embedded_test_server.h"
24+
#include "url/gurl.h"
25+
26+
namespace {
27+
28+
std::string CheckForEventScript(const std::string& event_var) {
29+
return base::StringPrintf(R"(function waitForEvent() {
30+
if (%s) {
31+
window.domAutomationController.send(true);
32+
}
33+
}
34+
setInterval(waitForEvent, 100);)",
35+
event_var.c_str());
36+
}
37+
38+
} // namespace
39+
40+
namespace brave_wallet {
41+
42+
class EthereumProviderBrowserTest : public InProcessBrowserTest {
43+
public:
44+
EthereumProviderBrowserTest()
45+
: https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
46+
47+
~EthereumProviderBrowserTest() override = default;
48+
49+
void SetUpCommandLine(base::CommandLine* command_line) override {
50+
InProcessBrowserTest::SetUpCommandLine(command_line);
51+
command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
52+
}
53+
54+
void SetUpOnMainThread() override {
55+
host_resolver()->AddRule("*", "127.0.0.1");
56+
57+
brave::RegisterPathProvider();
58+
base::FilePath test_data_dir;
59+
base::PathService::Get(brave::DIR_TEST_DATA, &test_data_dir);
60+
test_data_dir = test_data_dir.AppendASCII("brave-wallet");
61+
https_server_.ServeFilesFromDirectory(test_data_dir);
62+
https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
63+
ASSERT_TRUE(https_server()->Start());
64+
65+
keyring_service_ =
66+
KeyringServiceFactory::GetServiceForContext(browser()->profile());
67+
}
68+
69+
content::WebContents* web_contents() {
70+
return browser()->tab_strip_model()->GetActiveWebContents();
71+
}
72+
73+
net::EmbeddedTestServer* https_server() { return &https_server_; }
74+
75+
void RestoreWallet() {
76+
const char mnemonic[] =
77+
"drip caution abandon festival order clown oven regular absorb "
78+
"evidence crew where";
79+
base::RunLoop run_loop;
80+
keyring_service_->RestoreWallet(
81+
mnemonic, "brave123", false,
82+
base::BindLambdaForTesting([&](bool success) {
83+
ASSERT_TRUE(success);
84+
run_loop.Quit();
85+
}));
86+
run_loop.Run();
87+
}
88+
89+
private:
90+
net::test_server::EmbeddedTestServer https_server_;
91+
raw_ptr<KeyringService> keyring_service_ = nullptr;
92+
};
93+
94+
IN_PROC_BROWSER_TEST_F(EthereumProviderBrowserTest, InactiveTabRequest) {
95+
RestoreWallet();
96+
GURL url = https_server()->GetURL("a.com", "/ethereum_provider.html");
97+
98+
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
99+
content::WebContents* first_tab_web_contents = web_contents();
100+
101+
// Add a new tab and switch to it
102+
ASSERT_TRUE(AddTabAtIndex(1, url, ui::PAGE_TRANSITION_TYPED));
103+
ASSERT_EQ(browser()->tab_strip_model()->active_index(), 1);
104+
105+
// Add an asset using the first page web contents
106+
ASSERT_TRUE(
107+
ExecJs(first_tab_web_contents,
108+
"wallet_watchAsset('ERC20', "
109+
"'0x6B175474E89094C44Da98b954EedeAC495271d0F', 'USDC', 6)"));
110+
base::RunLoop().RunUntilIdle();
111+
112+
auto result_first =
113+
EvalJs(first_tab_web_contents, CheckForEventScript("inactiveTabError"),
114+
content::EXECUTE_SCRIPT_USE_MANUAL_REPLY);
115+
EXPECT_EQ(base::Value(true), result_first.value);
116+
}
117+
118+
IN_PROC_BROWSER_TEST_F(EthereumProviderBrowserTest, ActiveTabRequest) {
119+
RestoreWallet();
120+
GURL url = https_server()->GetURL("a.com", "/ethereum_provider.html");
121+
122+
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
123+
124+
// Add a new tab and switch to it
125+
ASSERT_TRUE(AddTabAtIndex(1, url, ui::PAGE_TRANSITION_TYPED));
126+
ASSERT_EQ(browser()->tab_strip_model()->active_index(), 1);
127+
128+
// Switch back to first tab
129+
browser()->tab_strip_model()->ActivateTabAt(0);
130+
ASSERT_EQ(browser()->tab_strip_model()->active_index(), 0);
131+
132+
// Add an asset using the first page web contents
133+
ASSERT_TRUE(
134+
ExecJs(web_contents(),
135+
"wallet_watchAsset('ERC20', "
136+
"'0x6B175474E89094C44Da98b954EedeAC495271d0F', 'USDC', 6)"));
137+
base::RunLoop().RunUntilIdle();
138+
139+
auto result_first =
140+
EvalJs(web_contents(), CheckForEventScript("!inactiveTabError"),
141+
content::EXECUTE_SCRIPT_USE_MANUAL_REPLY);
142+
EXPECT_EQ(base::Value(true), result_first.value);
143+
}
144+
145+
} // namespace brave_wallet

components/brave_wallet/browser/brave_wallet_provider_delegate.h

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class BraveWalletProviderDelegate {
3131
delete;
3232
virtual ~BraveWalletProviderDelegate() = default;
3333

34+
virtual bool IsTabVisible() = 0;
3435
virtual void ShowPanel() = 0;
3536
virtual void WalletInteractionDetected() = 0;
3637
virtual void ShowWalletOnboarding() = 0;

components/brave_wallet/browser/ethereum_provider_impl.cc

+24
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,23 @@ void EthereumProviderImpl::CommonRequestOrSendAsync(base::Value input_value,
10001000
return;
10011001
}
10021002

1003+
// That check prevents from pop ups from backgrounded pages.
1004+
// We need to add any method that requires a dialog to interact with.
1005+
if ((method == kEthRequestAccounts || method == kAddEthereumChainMethod ||
1006+
method == kSwitchEthereumChainMethod || method == kEthSendTransaction ||
1007+
method == kEthSign || method == kPersonalSign ||
1008+
method == kPersonalEcRecover || method == kEthSignTypedDataV3 ||
1009+
method == kEthSignTypedDataV4 || method == kEthGetEncryptionPublicKey ||
1010+
method == kEthDecrypt || method == kWalletWatchAsset ||
1011+
method == kRequestPermissionsMethod) &&
1012+
!delegate_->IsTabVisible()) {
1013+
SendErrorOnRequest(
1014+
mojom::ProviderError::kResourceUnavailable,
1015+
l10n_util::GetStringUTF8(IDS_WALLET_TAB_IS_NOT_ACTIVE_ERROR),
1016+
std::move(callback), base::Value());
1017+
return;
1018+
}
1019+
10031020
if (method == kEthAccounts) {
10041021
GetAllowedAccounts(
10051022
false,
@@ -1244,6 +1261,13 @@ void EthereumProviderImpl::ContinueRequestEthereumPermissions(
12441261
}
12451262

12461263
void EthereumProviderImpl::Enable(EnableCallback callback) {
1264+
if (!delegate_->IsTabVisible()) {
1265+
SendErrorOnRequest(
1266+
mojom::ProviderError::kResourceUnavailable,
1267+
l10n_util::GetStringUTF8(IDS_WALLET_TAB_IS_NOT_ACTIVE_ERROR),
1268+
std::move(callback), base::Value());
1269+
return;
1270+
}
12471271
RequestEthereumPermissions(std::move(callback), base::Value(), "",
12481272
delegate_->GetOrigin());
12491273
delegate_->WalletInteractionDetected();

components/resources/wallet_strings.grdp

+1
Original file line numberDiff line numberDiff line change
@@ -468,4 +468,5 @@
468468
<message name="IDS_WALLET_TRANSACTION_STATUS_UPDATE_MESSAGE_TITLE_CONFIRMED" desc="Notification message title when transaction confirmed">Transaction confirmed</message>
469469
<message name="IDS_WALLET_TRANSACTION_STATUS_UPDATE_MESSAGE_TITLE_ERROR" desc="Notification message title when transaction error">Transaction error</message>
470470
<message name="IDS_WALLET_TRANSACTION_STATUS_UPDATE_MESSAGE_TITLE_DROPPED" desc="Notification message title when transaction dropped">Transaction dropped</message>
471+
<message name="IDS_WALLET_TAB_IS_NOT_ACTIVE_ERROR" desc="Error message if it comes from an inactive tab">The tab is not active</message>
471472
</grit-part>

ios/browser/api/brave_wallet/brave_wallet_provider_delegate_ios+private.h

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class BraveWalletProviderDelegateBridge
2525
private:
2626
__weak id<BraveWalletProviderDelegate> bridge_;
2727

28+
bool IsTabVisible() override;
2829
void ShowPanel() override;
2930
void WalletInteractionDetected() override;
3031
url::Origin GetOrigin() const override;

ios/browser/api/brave_wallet/brave_wallet_provider_delegate_ios.h

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ typedef void (^GetAllowedAccountsCallback)(bool success,
2424

2525
OBJC_EXPORT
2626
@protocol BraveWalletProviderDelegate
27+
- (bool)isTabVisible;
2728
- (void)showPanel;
2829
- (URLOriginIOS*)getOrigin;
2930
- (void)walletInteractionDetected;

ios/browser/api/brave_wallet/brave_wallet_provider_delegate_ios.mm

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
namespace brave_wallet {
1616

17+
bool BraveWalletProviderDelegateBridge::IsTabVisible() {
18+
return [bridge_ isTabVisible];
19+
}
20+
1721
void BraveWalletProviderDelegateBridge::ShowPanel() {
1822
[bridge_ showPanel];
1923
}

test/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ if (!is_android) {
648648
"//brave/browser/brave_wallet/brave_wallet_service_browsertest.cc",
649649
"//brave/browser/brave_wallet/brave_wallet_sign_message_browsertest.cc",
650650
"//brave/browser/brave_wallet/brave_wallet_tab_helper_browsertest.cc",
651+
"//brave/browser/brave_wallet/ethereum_provider_browsertest.cc",
651652
"//brave/browser/brave_wallet/send_transaction_browsertest.cc",
652653
"//brave/browser/brave_wallet/solana_provider_browsertest.cc",
653654
"//brave/browser/brave_wallet/solana_provider_renderer_browsertest.cc",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<html>
2+
3+
<script>
4+
var inactiveTabError
5+
function wallet_watchAsset(type, address, symbol, decimals) {
6+
const params = {
7+
options: {
8+
address,
9+
symbol,
10+
decimals
11+
},
12+
type
13+
}
14+
15+
window.ethereum.request({
16+
method: 'wallet_watchAsset',
17+
params
18+
}).then(result => {
19+
inactiveTabError = false
20+
}).catch(error => {
21+
inactiveTabError = false
22+
if (error.code == -32002) {
23+
inactiveTabError = true
24+
}
25+
})
26+
}
27+
</script>
28+
29+
<body>
30+
</body>
31+
</html>
32+

0 commit comments

Comments
 (0)