diff --git a/android/java/org/chromium/chrome/browser/crypto_wallet/fragments/dapps/ConnectAccountFragment.java b/android/java/org/chromium/chrome/browser/crypto_wallet/fragments/dapps/ConnectAccountFragment.java index f48dd12f418d..c8172f49af87 100644 --- a/android/java/org/chromium/chrome/browser/crypto_wallet/fragments/dapps/ConnectAccountFragment.java +++ b/android/java/org/chromium/chrome/browser/crypto_wallet/fragments/dapps/ConnectAccountFragment.java @@ -20,10 +20,15 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import org.chromium.base.Callback; import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.NativeMethods; import org.chromium.brave_wallet.mojom.AccountInfo; import org.chromium.brave_wallet.mojom.CoinType; +import org.chromium.brave_wallet.mojom.PermissionLifetimeOption; import org.chromium.chrome.R; +import org.chromium.chrome.browser.BraveRewardsHelper; import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.app.BraveActivity; import org.chromium.chrome.browser.app.domain.WalletModel; @@ -32,21 +37,26 @@ import org.chromium.chrome.browser.crypto_wallet.util.AccountsPermissionsHelper; import org.chromium.chrome.browser.crypto_wallet.util.Utils; import org.chromium.chrome.browser.crypto_wallet.util.WalletUtils; +import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.ui.favicon.FaviconHelper; import org.chromium.chrome.browser.ui.favicon.FaviconHelper.DefaultFaviconHelper; import org.chromium.chrome.browser.ui.favicon.FaviconHelper.FaviconImageCallback; +import org.chromium.content_public.browser.WebContents; import org.chromium.url.GURL; import java.util.HashSet; import java.util.Iterator; +/** + * Fragment used to connect Dapps to the crypto account + */ public class ConnectAccountFragment extends BaseDAppsFragment implements BravePermissionAccountsListAdapter.BravePermissionDelegate { private static final String TAG = "ConnectAccount"; private TextView mWebSite; private TextView mAccountsConnected; - private TextView mbtNewAccount; + private TextView mButtonNewAccount; private ImageView mFavicon; private AccountInfo[] mAccountInfos; private HashSet mAccountsWithPermissions; @@ -99,8 +109,8 @@ public View onCreateView( View view = inflater.inflate(R.layout.fragment_connect_account, container, false); mWebSite = view.findViewById(R.id.fragment_connect_account_website); mAccountsConnected = view.findViewById(R.id.fragment_connect_account_accounts_connected); - mbtNewAccount = view.findViewById(R.id.fragment_connect_account_new_account_id); - mbtNewAccount.setOnClickListener(new View.OnClickListener() { + mButtonNewAccount = view.findViewById(R.id.fragment_connect_account_new_account_id); + mButtonNewAccount.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { BottomSheetDialogFragment sheetDialogFragment = @@ -175,17 +185,55 @@ public AccountInfo getSelectedAccount() { return mSelectedAccount; } + /** + * Data passed from ConnectAccountFragment to BraveDappPermissionPromptDialog for pending + * connect account requests + */ + public static class ConnectAccountPendingData { + ConnectAccountPendingData(String accountAddress, int permissionLifetimeOption) { + this.accountAddress = accountAddress; + this.permissionLifetimeOption = permissionLifetimeOption; + } + public String accountAddress; + public int permissionLifetimeOption; + } + private static ConnectAccountPendingData sConnectAccountPendingData; + + private static void setConnectAccountPendingData( + String accountAddress, int permissionLifetimeOption) { + sConnectAccountPendingData = + new ConnectAccountPendingData(accountAddress, permissionLifetimeOption); + } + + public static ConnectAccountPendingData getAndResetConnectAccountPendingData() { + if (sConnectAccountPendingData == null) { + return null; + } + ConnectAccountPendingData connectAccountPendingDataCopy = sConnectAccountPendingData; + sConnectAccountPendingData = null; + return connectAccountPendingDataCopy; + } + @Override public void connectAccount(AccountInfo account) { - getBraveWalletService().addPermission(account.accountId, success -> { - if (!success) { - return; - } - if (CoinType.SOL != account.accountId.coin) { - getKeyringService().setSelectedAccount(account.accountId, setSuccess -> {}); + Tab tab = BraveRewardsHelper.currentActiveChromeTabbedActivityTab(); + if (tab != null) { + if (tab.getWebContents() != null) { + // Static data for BraveDappPermissionPromptDialog.show + setConnectAccountPendingData(account.address, PermissionLifetimeOption.FOREVER); + ConnectAccountFragmentJni.get().connectAccount( + account.address, account.accountId.coin, tab.getWebContents(), success -> { + if (!success) { + return; + } + if (CoinType.SOL != account.accountId.coin) { + getKeyringService().setSelectedAccount( + account.accountId, setSuccess -> {}); + } + updateAccounts(); + }); } - updateAccounts(); - }); + } } @Override @@ -228,4 +276,15 @@ private GURL getCurrentHostHttpAddress() { } return GURL.emptyGURL(); } + + @CalledByNative + private static void onConnectAccountDone(Callback callback, Boolean result) { + callback.onResult(result); + } + + @NativeMethods + interface Natives { + void connectAccount(String accountAddress, int accountIdCoin, WebContents webContents, + Callback callback); + } } diff --git a/android/java/org/chromium/chrome/browser/crypto_wallet/permission/BraveDappPermissionPromptDialog.java b/android/java/org/chromium/chrome/browser/crypto_wallet/permission/BraveDappPermissionPromptDialog.java index ce9b679fe2b3..c706b052f12c 100644 --- a/android/java/org/chromium/chrome/browser/crypto_wallet/permission/BraveDappPermissionPromptDialog.java +++ b/android/java/org/chromium/chrome/browser/crypto_wallet/permission/BraveDappPermissionPromptDialog.java @@ -26,12 +26,14 @@ import org.chromium.brave_wallet.mojom.BraveWalletService; import org.chromium.brave_wallet.mojom.CoinType; import org.chromium.brave_wallet.mojom.KeyringService; +import org.chromium.brave_wallet.mojom.PermissionLifetimeOption; import org.chromium.chrome.R; import org.chromium.chrome.browser.app.BraveActivity; import org.chromium.chrome.browser.app.domain.WalletModel; import org.chromium.chrome.browser.app.helpers.ImageLoader; import org.chromium.chrome.browser.crypto_wallet.BraveWalletServiceFactory; import org.chromium.chrome.browser.crypto_wallet.KeyringServiceFactory; +import org.chromium.chrome.browser.crypto_wallet.fragments.dapps.ConnectAccountFragment; import org.chromium.chrome.browser.crypto_wallet.util.Utils; import org.chromium.chrome.browser.crypto_wallet.util.WalletConstants; import org.chromium.components.browser_ui.modaldialog.ModalDialogView; @@ -50,6 +52,9 @@ import java.lang.ref.WeakReference; import java.util.List; +/** + * Dialog to grant website permissions to use Dapps + */ public class BraveDappPermissionPromptDialog implements ModalDialogProperties.Controller, ConnectionErrorHandler { private static final String TAG = "BraveDappPermission"; @@ -113,7 +118,7 @@ void show() { setFavIcon(); mRecyclerView = customView.findViewById(R.id.accounts_list); - InitBraveWalletService(); + initBraveWalletService(); TextView domain = customView.findViewById(R.id.domain); mBraveWalletService.getActiveOrigin( originInfo -> { domain.setText(Utils.geteTldSpanned(originInfo)); }); @@ -131,7 +136,7 @@ void show() { .with(ModalDialogProperties.FILTER_TOUCH_FOR_SECURITY, true) .build(); mModalDialogManager.showDialog(mPropertyModel, ModalDialogType.APP); - InitKeyringService(); + initKeyringService(); try { BraveActivity activity = BraveActivity.getBraveActivity(); activity.dismissWalletPanelOrDialog(); @@ -150,6 +155,11 @@ void show() { initAccounts(); } + @PermissionLifetimeOption.EnumType + int getPermissionLifetimeOption() { + return PermissionLifetimeOption.FOREVER; + } + @NonNull private ViewGroup getPermissionModalViewContainer(View customView) { ViewParent viewParent = customView.getParent(); @@ -162,7 +172,7 @@ private ViewGroup getPermissionModalViewContainer(View customView) { return (ViewGroup) viewParent; } - private void InitBraveWalletService() { + private void initBraveWalletService() { if (mBraveWalletService != null) { return; } @@ -198,6 +208,18 @@ public void onAccountCheckChanged(AccountInfo account, boolean isChecked) { } } mAccountsListAdapter.notifyDataSetChanged(); + + // We are on the flow from ConnectAccountFragment.connectAccount + ConnectAccountFragment.ConnectAccountPendingData capd = + ConnectAccountFragment.getAndResetConnectAccountPendingData(); + if (capd != null) { + final String[] selectedAccounts = {capd.accountAddress}; + BraveDappPermissionPromptDialogJni.get().onPrimaryButtonClicked( + mNativeDialogController, selectedAccounts, + capd.permissionLifetimeOption); + mModalDialogManager.dismissDialog( + mPropertyModel, DialogDismissalCause.POSITIVE_BUTTON_CLICKED); + } }); } @@ -227,7 +249,7 @@ public String[] getSelectedAccounts() { public void onClick(PropertyModel model, @ButtonType int buttonType) { if (buttonType == ButtonType.POSITIVE) { BraveDappPermissionPromptDialogJni.get().onPrimaryButtonClicked( - mNativeDialogController, getSelectedAccounts()); + mNativeDialogController, getSelectedAccounts(), getPermissionLifetimeOption()); mModalDialogManager.dismissDialog( mPropertyModel, DialogDismissalCause.POSITIVE_BUTTON_CLICKED); } else if (buttonType == ButtonType.NEGATIVE) { @@ -240,7 +262,7 @@ public void onClick(PropertyModel model, @ButtonType int buttonType) { @Override public void onDismiss(PropertyModel model, int dismissalCause) { - DisconnectMojoServices(); + disconnectMojoServices(); BraveDappPermissionPromptDialogJni.get().onDialogDismissed(mNativeDialogController); mNativeDialogController = 0; } @@ -250,7 +272,7 @@ private void dismissDialog() { mModalDialogManager.dismissDialog(mPropertyModel, DialogDismissalCause.DISMISSED_BY_NATIVE); } - public void DisconnectMojoServices() { + public void disconnectMojoServices() { mMojoServicesClosed = true; if (mKeyringService != null) { mKeyringService.close(); @@ -269,10 +291,10 @@ public void onConnectionError(MojoException e) { } mKeyringService.close(); mKeyringService = null; - InitKeyringService(); + initKeyringService(); } - protected void InitKeyringService() { + protected void initKeyringService() { if (mKeyringService != null) { return; } @@ -282,8 +304,8 @@ protected void InitKeyringService() { @NativeMethods interface Natives { - void onPrimaryButtonClicked( - long nativeBraveDappPermissionPromptDialogController, String[] accounts); + void onPrimaryButtonClicked(long nativeBraveDappPermissionPromptDialogController, + String[] accounts, int permissionLifetimeOption); void onNegativeButtonClicked(long nativeBraveDappPermissionPromptDialogController); void onDialogDismissed(long nativeBraveDappPermissionPromptDialogController); } diff --git a/browser/brave_wallet/android/sources.gni b/browser/brave_wallet/android/sources.gni index dcf0e68638e4..829f7410a755 100644 --- a/browser/brave_wallet/android/sources.gni +++ b/browser/brave_wallet/android/sources.gni @@ -17,6 +17,7 @@ brave_browser_brave_wallet_android_sources = [ "//brave/browser/permissions/brave_dapp_permission_prompt_dialog_controller_android.h", "//brave/browser/permissions/brave_wallet_permission_prompt_android.cc", "//brave/browser/permissions/brave_wallet_permission_prompt_android.h", + "//brave/browser/permissions/connect_account_android.cc", ] brave_browser_brave_wallet_android_deps = [ diff --git a/browser/brave_wallet/brave_wallet_provider_delegate_impl.cc b/browser/brave_wallet/brave_wallet_provider_delegate_impl.cc index 31e2bda7a10f..6b3caf300063 100644 --- a/browser/brave_wallet/brave_wallet_provider_delegate_impl.cc +++ b/browser/brave_wallet/brave_wallet_provider_delegate_impl.cc @@ -57,18 +57,6 @@ void OnRequestPermissions( } } -absl::optional CoinTypeToPermissionRequestType( - mojom::CoinType coin_type) { - switch (coin_type) { - case mojom::CoinType::ETH: - return permissions::RequestType::kBraveEthereum; - case mojom::CoinType::SOL: - return permissions::RequestType::kBraveSolana; - default: - return absl::nullopt; - } -} - } // namespace BraveWalletProviderDelegateImpl::BraveWalletProviderDelegateImpl( diff --git a/browser/brave_wallet/brave_wallet_service_delegate_impl.cc b/browser/brave_wallet/brave_wallet_service_delegate_impl.cc index 2edefeb51b2c..1c200262f110 100644 --- a/browser/brave_wallet/brave_wallet_service_delegate_impl.cc +++ b/browser/brave_wallet/brave_wallet_service_delegate_impl.cc @@ -149,18 +149,6 @@ void BraveWalletServiceDelegateImpl::ContinueGetImportInfoFromExternalWallet( } } -bool BraveWalletServiceDelegateImpl::AddPermission(mojom::CoinType coin, - const url::Origin& origin, - const std::string& account) { - auto type = CoinTypeToPermissionType(coin); - if (!type) { - return false; - } - - return permissions::BraveWalletPermissionContext::AddPermission( - *type, context_, origin, account); -} - bool BraveWalletServiceDelegateImpl::HasPermission(mojom::CoinType coin, const url::Origin& origin, const std::string& account) { diff --git a/browser/brave_wallet/brave_wallet_service_delegate_impl.h b/browser/brave_wallet/brave_wallet_service_delegate_impl.h index 36caa3a67907..ba004e210cc3 100644 --- a/browser/brave_wallet/brave_wallet_service_delegate_impl.h +++ b/browser/brave_wallet/brave_wallet_service_delegate_impl.h @@ -50,9 +50,6 @@ class BraveWalletServiceDelegateImpl : public BraveWalletServiceDelegate, const std::string& password, GetImportInfoCallback callback) override; - bool AddPermission(mojom::CoinType coin, - const url::Origin& origin, - const std::string& account) override; bool HasPermission(mojom::CoinType coin, const url::Origin& origin, const std::string& account) override; diff --git a/browser/brave_wallet/ethereum_provider_impl_unittest.cc b/browser/brave_wallet/ethereum_provider_impl_unittest.cc index 4592c65fb7e7..142bf0628507 100644 --- a/browser/brave_wallet/ethereum_provider_impl_unittest.cc +++ b/browser/brave_wallet/ethereum_provider_impl_unittest.cc @@ -44,6 +44,7 @@ #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "brave/components/brave_wallet/common/hex_utils.h" #include "brave/components/permissions/brave_permission_manager.h" +#include "brave/components/permissions/contexts/brave_wallet_permission_context.h" #include "brave/components/version_info/version_info.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/permissions/permission_manager_factory.h" @@ -455,13 +456,9 @@ class EthereumProviderImplUnitTest : public testing::Test { } void AddEthereumPermission(const mojom::AccountIdPtr& account_id) { - base::RunLoop run_loop; - brave_wallet_service_->AddPermission( - account_id.Clone(), base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); - run_loop.Quit(); - })); - run_loop.Run(); + EXPECT_TRUE(permissions::BraveWalletPermissionContext::AddPermission( + blink::PermissionType::BRAVE_ETHEREUM, browser_context(), GetOrigin(), + account_id->address)); } void ResetEthereumPermission(const mojom::AccountIdPtr& account_id) { diff --git a/browser/brave_wallet/send_or_sign_transaction_browsertest.cc b/browser/brave_wallet/send_or_sign_transaction_browsertest.cc index 3b9020f8c357..30631681de8b 100644 --- a/browser/brave_wallet/send_or_sign_transaction_browsertest.cc +++ b/browser/brave_wallet/send_or_sign_transaction_browsertest.cc @@ -11,12 +11,10 @@ #include "base/strings/stringprintf.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" -#include "brave/browser/brave_wallet/brave_wallet_service_factory.h" #include "brave/browser/brave_wallet/brave_wallet_tab_helper.h" #include "brave/browser/brave_wallet/json_rpc_service_factory.h" #include "brave/browser/brave_wallet/keyring_service_factory.h" #include "brave/browser/brave_wallet/tx_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/json_rpc_service.h" #include "brave/components/brave_wallet/browser/keyring_service.h" @@ -191,9 +189,6 @@ class SendOrSignTransactionBrowserTest : public InProcessBrowserTest { https_server_for_files()->ServeFilesFromDirectory(test_data_dir); ASSERT_TRUE(https_server_for_files()->Start()); - brave_wallet_service_ = - brave_wallet::BraveWalletServiceFactory::GetServiceForContext( - browser()->profile()); keyring_service_ = KeyringServiceFactory::GetServiceForContext(browser()->profile()); tx_service_ = TxServiceFactory::GetServiceForContext(browser()->profile()); @@ -332,13 +327,10 @@ class SendOrSignTransactionBrowserTest : public InProcessBrowserTest { } void AddEthereumPermission(const mojom::AccountIdPtr& account_id) { - base::RunLoop run_loop; - brave_wallet_service_->AddPermission( - account_id.Clone(), base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); - run_loop.Quit(); - })); - run_loop.Run(); + EXPECT_TRUE(permissions::BraveWalletPermissionContext::AddPermission( + blink::PermissionType::BRAVE_ETHEREUM, browser()->profile(), + web_contents()->GetPrimaryMainFrame()->GetLastCommittedOrigin(), + account_id->address)); } const mojom::AccountInfoPtr& default_account() const { @@ -596,7 +588,6 @@ class SendOrSignTransactionBrowserTest : public InProcessBrowserTest { } protected: - raw_ptr brave_wallet_service_ = nullptr; mojom::AccountInfoPtr default_account_; private: diff --git a/browser/brave_wallet/solana_provider_impl_unittest.cc b/browser/brave_wallet/solana_provider_impl_unittest.cc index b1b4f4cb6538..5fa2f53bfda3 100644 --- a/browser/brave_wallet/solana_provider_impl_unittest.cc +++ b/browser/brave_wallet/solana_provider_impl_unittest.cc @@ -33,6 +33,7 @@ #include "brave/components/brave_wallet/common/features.h" #include "brave/components/brave_wallet/common/solana_utils.h" #include "brave/components/permissions/brave_permission_manager.h" +#include "brave/components/permissions/contexts/brave_wallet_permission_context.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/permissions/permission_manager_factory.h" #include "chrome/test/base/scoped_testing_local_state.h" @@ -270,13 +271,9 @@ class SolanaProviderImplUnitTest : public testing::Test { } void AddSolanaPermission(const mojom::AccountIdPtr& account_id) { - base::RunLoop run_loop; - brave_wallet_service_->AddPermission( - account_id.Clone(), base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); - run_loop.Quit(); - })); - run_loop.Run(); + EXPECT_TRUE(permissions::BraveWalletPermissionContext::AddPermission( + blink::PermissionType::BRAVE_SOLANA, browser_context(), GetOrigin(), + account_id->address)); } std::string Connect(absl::optional arg, diff --git a/browser/permissions/brave_dapp_permission_prompt_dialog_controller_android.cc b/browser/permissions/brave_dapp_permission_prompt_dialog_controller_android.cc index 867557b715f7..9b0c33bbcdb7 100644 --- a/browser/permissions/brave_dapp_permission_prompt_dialog_controller_android.cc +++ b/browser/permissions/brave_dapp_permission_prompt_dialog_controller_android.cc @@ -52,11 +52,12 @@ void BraveDappPermissionPromptDialogController::ShowDialog() { void BraveDappPermissionPromptDialogController::OnPrimaryButtonClicked( JNIEnv* env, - const base::android::JavaParamRef& accounts) { + const base::android::JavaParamRef& accounts, + int permission_lifetime_option) { std::vector allowedAccounts; base::android::AppendJavaStringArrayToStringVector(env, accounts, &allowedAccounts); - delegate_->ConnectToSite(allowedAccounts); + delegate_->ConnectToSite(allowedAccounts, permission_lifetime_option); } void BraveDappPermissionPromptDialogController::OnNegativeButtonClicked( diff --git a/browser/permissions/brave_dapp_permission_prompt_dialog_controller_android.h b/browser/permissions/brave_dapp_permission_prompt_dialog_controller_android.h index 3851f9e16535..082330b70a3c 100644 --- a/browser/permissions/brave_dapp_permission_prompt_dialog_controller_android.h +++ b/browser/permissions/brave_dapp_permission_prompt_dialog_controller_android.h @@ -23,7 +23,8 @@ class BraveDappPermissionPromptDialogController { class Delegate { public: virtual void OnDialogDismissed() = 0; - virtual void ConnectToSite(const std::vector& accounts) = 0; + virtual void ConnectToSite(const std::vector& accounts, + int permission_lifetime_option) = 0; virtual void CancelConnectToSite() = 0; }; @@ -39,7 +40,8 @@ class BraveDappPermissionPromptDialogController { void OnPrimaryButtonClicked( JNIEnv* env, - const base::android::JavaParamRef& accounts); + const base::android::JavaParamRef& accounts, + int permission_lifetime_option); void OnNegativeButtonClicked(JNIEnv* env); void OnDialogDismissed(JNIEnv* env); diff --git a/browser/permissions/brave_wallet_permission_prompt_android.cc b/browser/permissions/brave_wallet_permission_prompt_android.cc index 1ffb5cc78e04..e73af74c9981 100644 --- a/browser/permissions/brave_wallet_permission_prompt_android.cc +++ b/browser/permissions/brave_wallet_permission_prompt_android.cc @@ -27,7 +27,8 @@ BraveWalletPermissionPrompt::BraveWalletPermissionPrompt( BraveWalletPermissionPrompt::~BraveWalletPermissionPrompt() {} void BraveWalletPermissionPrompt::ConnectToSite( - const std::vector& accounts) { + const std::vector& accounts, + int permission_lifetime_option) { has_interacted_with_dialog_ = true; dialog_controller_.reset(); // TODO(SergeyZhukovsky): Use the real option that the user chooses, using diff --git a/browser/permissions/brave_wallet_permission_prompt_android.h b/browser/permissions/brave_wallet_permission_prompt_android.h index e6ebb343d81e..276d8060f8c2 100644 --- a/browser/permissions/brave_wallet_permission_prompt_android.h +++ b/browser/permissions/brave_wallet_permission_prompt_android.h @@ -47,7 +47,8 @@ class BraveWalletPermissionPrompt protected: // BraveDappPermissionPromptDialogController::Delegate: void OnDialogDismissed() override; - void ConnectToSite(const std::vector& accounts) override; + void ConnectToSite(const std::vector& accounts, + int permission_lifetime_option) override; void CancelConnectToSite() override; private: diff --git a/browser/permissions/connect_account_android.cc b/browser/permissions/connect_account_android.cc new file mode 100644 index 000000000000..0a1ffc5be738 --- /dev/null +++ b/browser/permissions/connect_account_android.cc @@ -0,0 +1,96 @@ +/* Copyright (c) 2023 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 https://mozilla.org/MPL/2.0/. */ + +#include "base/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "brave/build/android/jni_headers/ConnectAccountFragment_jni.h" +#include "brave/components/brave_wallet/browser/permission_utils.h" +#include "brave/components/brave_wallet/common/brave_wallet.mojom-shared.h" +#include "brave/components/permissions/contexts/brave_wallet_permission_context.h" +#include "content/public/browser/web_contents.h" + +#include "base/functional/callback.h" +#include "content/public/browser/render_frame_host.h" + +namespace { + +base::android::ScopedJavaLocalRef GetJavaBoolean(JNIEnv* env, + bool native_bool) { + jclass booleanClass = env->FindClass("java/lang/Boolean"); + jmethodID methodID = env->GetMethodID(booleanClass, "", "(Z)V"); + jobject booleanObject = env->NewObject(booleanClass, methodID, native_bool); + + return base::android::ScopedJavaLocalRef(env, booleanObject); +} + +void PlainCallConnectAccountCallback( + JNIEnv* env, + base::android::ScopedJavaGlobalRef java_callback, + bool value_result) { + Java_ConnectAccountFragment_onConnectAccountDone( + env, java_callback, GetJavaBoolean(env, value_result)); +} + +} // namespace + +static void JNI_ConnectAccountFragment_ConnectAccount( + JNIEnv* env, + const base::android::JavaParamRef& java_account_address, + jint account_id_coin, + const base::android::JavaParamRef& java_web_contents, + const base::android::JavaParamRef& callback) { + base::android::ScopedJavaGlobalRef java_callback; + java_callback.Reset(env, callback); + + content::WebContents* web_contents = + content::WebContents::FromJavaWebContents(java_web_contents); + + if (web_contents == nullptr) { + PlainCallConnectAccountCallback(env, java_callback, false); + return; + } + + std::string account_address = + base::android::ConvertJavaStringToUTF8(java_account_address); + + content::RenderFrameHost* rfh = web_contents->GetFocusedFrame(); + if (rfh == nullptr) { + PlainCallConnectAccountCallback(env, java_callback, false); + return; + } + + brave_wallet::mojom::CoinType coin = + static_cast(account_id_coin); + CHECK(brave_wallet::mojom::IsKnownEnumValue(coin)); + + auto request_type = brave_wallet::CoinTypeToPermissionRequestType(coin); + auto permission = brave_wallet::CoinTypeToPermissionType(coin); + + if (!request_type || !permission) { + PlainCallConnectAccountCallback(env, java_callback, false); + return; + } + + if (permissions::BraveWalletPermissionContext::HasRequestsInProgress( + rfh, *request_type)) { + PlainCallConnectAccountCallback(env, java_callback, false); + return; + } + + permissions::BraveWalletPermissionContext::RequestPermissions( + *permission, rfh, {account_address}, + base::BindOnce( + [](JNIEnv* env, + base::android::ScopedJavaGlobalRef java_callback, + const std::vector& responses) { + if (responses.empty() || responses.size() != 1u) { + PlainCallConnectAccountCallback(env, java_callback, false); + } else { + PlainCallConnectAccountCallback(env, java_callback, true); + } + }, + env, std::move(java_callback))); +} diff --git a/browser/ui/webui/brave_wallet/panel_handler/BUILD.gn b/browser/ui/webui/brave_wallet/panel_handler/BUILD.gn index d94d9ddf7697..495319c121d3 100644 --- a/browser/ui/webui/brave_wallet/panel_handler/BUILD.gn +++ b/browser/ui/webui/brave_wallet/panel_handler/BUILD.gn @@ -12,6 +12,7 @@ source_set("panel_handler") { "//brave/browser/brave_wallet", "//brave/browser/brave_wallet:tab_helper", "//brave/components/brave_wallet/browser", + "//brave/components/brave_wallet/browser:permission_utils", "//brave/components/brave_wallet/common:mojom", "//chrome/browser/profiles:profile", "//components/permissions", diff --git a/browser/ui/webui/brave_wallet/panel_handler/wallet_panel_handler.cc b/browser/ui/webui/brave_wallet/panel_handler/wallet_panel_handler.cc index 463e275446f8..5de98c558897 100644 --- a/browser/ui/webui/brave_wallet/panel_handler/wallet_panel_handler.cc +++ b/browser/ui/webui/brave_wallet/panel_handler/wallet_panel_handler.cc @@ -9,6 +9,7 @@ #include "base/functional/callback.h" #include "brave/browser/brave_wallet/brave_wallet_tab_helper.h" +#include "brave/components/brave_wallet/browser/permission_utils.h" #include "brave/components/permissions/contexts/brave_wallet_permission_context.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" @@ -83,3 +84,40 @@ void WalletPanelHandler::IsSolanaAccountConnected( std::move(callback).Run( tab_helper->IsSolanaAccountConnected(rfh->GetGlobalId(), account)); } + +void WalletPanelHandler::RequestPermission( + brave_wallet::mojom::AccountIdPtr account_id, + RequestPermissionCallback callback) { + content::RenderFrameHost* rfh = nullptr; + if (!(rfh = active_web_contents_->GetFocusedFrame())) { + std::move(callback).Run(false); + return; + } + + auto request_type = + brave_wallet::CoinTypeToPermissionRequestType(account_id->coin); + auto permission = brave_wallet::CoinTypeToPermissionType(account_id->coin); + if (!request_type || !permission) { + std::move(callback).Run(false); + return; + } + + if (permissions::BraveWalletPermissionContext::HasRequestsInProgress( + rfh, *request_type)) { + std::move(callback).Run(false); + return; + } + + permissions::BraveWalletPermissionContext::RequestPermissions( + *permission, rfh, {account_id->address}, + base::BindOnce( + [](RequestPermissionCallback cb, + const std::vector& responses) { + if (responses.empty() || responses.size() != 1u) { + std::move(cb).Run(false); + } else { + std::move(cb).Run(true); + } + }, + std::move(callback))); +} diff --git a/browser/ui/webui/brave_wallet/panel_handler/wallet_panel_handler.h b/browser/ui/webui/brave_wallet/panel_handler/wallet_panel_handler.h index a40272808fab..beefd42bf743 100644 --- a/browser/ui/webui/brave_wallet/panel_handler/wallet_panel_handler.h +++ b/browser/ui/webui/brave_wallet/panel_handler/wallet_panel_handler.h @@ -44,6 +44,8 @@ class WalletPanelHandler : public brave_wallet::mojom::PanelHandler { void IsSolanaAccountConnected( const std::string& account, IsSolanaAccountConnectedCallback callback) override; + void RequestPermission(brave_wallet::mojom::AccountIdPtr account_id, + RequestPermissionCallback callback) override; private: mojo::Receiver receiver_; diff --git a/build/android/BUILD.gn b/build/android/BUILD.gn index 4b14fef7b5e8..10c8bb241031 100644 --- a/build/android/BUILD.gn +++ b/build/android/BUILD.gn @@ -221,6 +221,7 @@ generate_jni("jni_headers") { "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/KeyringServiceFactory.java", "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/SwapServiceFactory.java", "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/TxServiceFactory.java", + "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/fragments/dapps/ConnectAccountFragment.java", "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/permission/BraveDappPermissionPromptDialog.java", "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/WalletDataFilesInstaller.java", "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/WalletDataFilesInstallerUtil.java", diff --git a/build/android/config.gni b/build/android/config.gni index a2755e3c4f89..79cb5e06ed1d 100644 --- a/build/android/config.gni +++ b/build/android/config.gni @@ -120,6 +120,7 @@ brave_jni_headers_sources = [ "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/KeyringServiceFactory.java", "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/SwapServiceFactory.java", "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/TxServiceFactory.java", + "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/fragments/dapps/ConnectAccountFragment.java", "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/permission/BraveDappPermissionPromptDialog.java", "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/WalletDataFilesInstaller.java", "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/WalletNativeUtils.java", diff --git a/components/brave_wallet/browser/brave_wallet_service.cc b/components/brave_wallet/browser/brave_wallet_service.cc index 1005c04e425e..d2796eb2cc21 100644 --- a/components/brave_wallet/browser/brave_wallet_service.cc +++ b/components/brave_wallet/browser/brave_wallet_service.cc @@ -935,18 +935,6 @@ void BraveWalletService::OnBraveWalletNftDiscoveryEnabled() { } } -void BraveWalletService::AddPermission(mojom::AccountIdPtr account_id, - AddPermissionCallback callback) { - auto origin = delegate_->GetActiveOrigin(); - if (!origin) { - std::move(callback).Run(false); - return; - } - - std::move(callback).Run( - delegate_->AddPermission(account_id->coin, *origin, account_id->address)); -} - void BraveWalletService::HasPermission( std::vector accounts, HasPermissionCallback callback) { diff --git a/components/brave_wallet/browser/brave_wallet_service.h b/components/brave_wallet/browser/brave_wallet_service.h index 4dd185805d01..d09db252f373 100644 --- a/components/brave_wallet/browser/brave_wallet_service.h +++ b/components/brave_wallet/browser/brave_wallet_service.h @@ -173,8 +173,6 @@ class BraveWalletService : public KeyedService, void SetNetworkForSelectedAccountOnActiveOrigin( const std::string& chain_id, SetNetworkForSelectedAccountOnActiveOriginCallback callback) override; - void AddPermission(mojom::AccountIdPtr account_id, - AddPermissionCallback callback) override; void HasPermission(std::vector accounts, HasPermissionCallback callback) override; void ResetPermission(mojom::AccountIdPtr account_id, diff --git a/components/brave_wallet/browser/permission_utils.cc b/components/brave_wallet/browser/permission_utils.cc index cea642821117..556accf11aee 100644 --- a/components/brave_wallet/browser/permission_utils.cc +++ b/components/brave_wallet/browser/permission_utils.cc @@ -218,4 +218,16 @@ absl::optional CoinTypeToPermissionType( } } +absl::optional CoinTypeToPermissionRequestType( + mojom::CoinType coin_type) { + switch (coin_type) { + case mojom::CoinType::ETH: + return permissions::RequestType::kBraveEthereum; + case mojom::CoinType::SOL: + return permissions::RequestType::kBraveSolana; + default: + return absl::nullopt; + } +} + } // namespace brave_wallet diff --git a/components/brave_wallet/browser/permission_utils.h b/components/brave_wallet/browser/permission_utils.h index 00ccf8def642..674de63e7291 100644 --- a/components/brave_wallet/browser/permission_utils.h +++ b/components/brave_wallet/browser/permission_utils.h @@ -81,6 +81,9 @@ GURL GetConnectWithSiteWebUIURL(const GURL& webui_base_url, absl::optional CoinTypeToPermissionType( mojom::CoinType coin_type); +absl::optional CoinTypeToPermissionRequestType( + mojom::CoinType coin_type); + } // namespace brave_wallet #endif // BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_PERMISSION_UTILS_H_ diff --git a/components/brave_wallet/browser/permission_utils_unittest.cc b/components/brave_wallet/browser/permission_utils_unittest.cc index 9e0bd9b298a5..737763e1a918 100644 --- a/components/brave_wallet/browser/permission_utils_unittest.cc +++ b/components/brave_wallet/browser/permission_utils_unittest.cc @@ -373,4 +373,26 @@ TEST(PermissionUtilsUnitTest, SyncingWithCreatePermissionLifetimeOptions) { absl::nullopt); } +TEST(PermissionUtilsUnitTest, CoinTypeToPermissionType) { + auto type = CoinTypeToPermissionType(mojom::CoinType::ETH); + ASSERT_TRUE(type); + EXPECT_EQ(*type, blink::PermissionType::BRAVE_ETHEREUM); + type = CoinTypeToPermissionType(mojom::CoinType::SOL); + ASSERT_TRUE(type); + EXPECT_EQ(*type, blink::PermissionType::BRAVE_SOLANA); + EXPECT_FALSE(CoinTypeToPermissionType(mojom::CoinType::FIL)); + EXPECT_FALSE(CoinTypeToPermissionType(mojom::CoinType::BTC)); +} + +TEST(PermissionUtilsUnitTest, CoinTypeToPermissionRequestType) { + auto request = CoinTypeToPermissionRequestType(mojom::CoinType::ETH); + ASSERT_TRUE(request); + EXPECT_EQ(*request, permissions::RequestType::kBraveEthereum); + request = CoinTypeToPermissionRequestType(mojom::CoinType::SOL); + ASSERT_TRUE(request); + EXPECT_EQ(*request, permissions::RequestType::kBraveSolana); + EXPECT_FALSE(CoinTypeToPermissionType(mojom::CoinType::FIL)); + EXPECT_FALSE(CoinTypeToPermissionType(mojom::CoinType::BTC)); +} + } // namespace brave_wallet diff --git a/components/brave_wallet/common/brave_wallet.mojom b/components/brave_wallet/common/brave_wallet.mojom index 2444c44f5177..6bb211cdf71b 100644 --- a/components/brave_wallet/common/brave_wallet.mojom +++ b/components/brave_wallet/common/brave_wallet.mojom @@ -401,6 +401,13 @@ interface PanelHandler { Focus(); IsSolanaAccountConnected(string account) => (bool connected); + + // Create a permission request for users based on active web contents. + // The flow will be similar to dapp request permission except it is initiated + // from panel. Desktop front end will be opened with same #connectWitSite ref + // and we need to call ConnectToSite or CancelConnectToSite based on user + // decision. + RequestPermission(AccountId account_id) => (bool success); }; // Browser-side handler for requests from WebUI page. @@ -1868,10 +1875,6 @@ interface BraveWalletService { GetNetworkForSelectedAccountOnActiveOrigin() => (NetworkInfo? network); SetNetworkForSelectedAccountOnActiveOrigin(string chain_id) => (bool success); - // Adds the permission for the account on active origin. - AddPermission(AccountId account_id) - => (bool success); - // Filters accounts with permissions on active origin. HasPermission(array accounts) => (bool success, array accounts_with_permission); diff --git a/components/brave_wallet_ui/common/actions/wallet_actions.ts b/components/brave_wallet_ui/common/actions/wallet_actions.ts index cb1c6b91c08e..78504fd9e03b 100644 --- a/components/brave_wallet_ui/common/actions/wallet_actions.ts +++ b/components/brave_wallet_ui/common/actions/wallet_actions.ts @@ -11,7 +11,6 @@ export const { activeOriginChanged, addAccount, addFavoriteApp, - addSitePermission, addUserAsset, addUserAssetError, autoLockMinutesChanged, diff --git a/components/brave_wallet_ui/common/async/handlers.ts b/components/brave_wallet_ui/common/async/handlers.ts index 6ba7cbe3074f..8cac40c56017 100644 --- a/components/brave_wallet_ui/common/async/handlers.ts +++ b/components/brave_wallet_ui/common/async/handlers.ts @@ -8,7 +8,6 @@ import { mapLimit } from 'async' import AsyncActionHandler from '../../../common/AsyncActionHandler' import * as WalletActions from '../actions/wallet_actions' import { - AddSitePermissionPayloadType, RemoveSitePermissionPayloadType, SetUserAssetVisiblePayloadType, UnlockWalletPayloadType, @@ -318,12 +317,6 @@ handler.on(WalletActions.removeSitePermission.type, async (store: Store, payload await refreshWalletInfo(store) }) -handler.on(WalletActions.addSitePermission.type, async (store: Store, payload: AddSitePermissionPayloadType) => { - const braveWalletService = getAPIProxy().braveWalletService - await braveWalletService.addPermission(payload.accountId) - await refreshWalletInfo(store) -}) - handler.on(WalletActions.expandWalletNetworks.type, async (store) => { chrome.tabs.create({ url: 'chrome://settings/wallet/networks' }, () => { if (chrome.runtime.lastError) { diff --git a/components/brave_wallet_ui/common/constants/action_types.ts b/components/brave_wallet_ui/common/constants/action_types.ts index 8c44d08a7b89..d87c24da95a6 100644 --- a/components/brave_wallet_ui/common/constants/action_types.ts +++ b/components/brave_wallet_ui/common/constants/action_types.ts @@ -89,10 +89,6 @@ export type RemoveSitePermissionPayloadType = { accountId: BraveWallet.AccountId } -export type AddSitePermissionPayloadType = { - accountId: BraveWallet.AccountId -} - export type GetCoinMarketPayload = { vsAsset: string limit: number diff --git a/components/brave_wallet_ui/common/slices/wallet.slice.ts b/components/brave_wallet_ui/common/slices/wallet.slice.ts index 4d403a67efdd..b60c1ecb6853 100644 --- a/components/brave_wallet_ui/common/slices/wallet.slice.ts +++ b/components/brave_wallet_ui/common/slices/wallet.slice.ts @@ -15,7 +15,6 @@ import { ImportAccountErrorType } from '../../constants/types' import { - AddSitePermissionPayloadType, DefaultBaseCryptocurrencyChanged, DefaultBaseCurrencyChanged, DefaultEthereumWalletChanged, @@ -196,8 +195,6 @@ export const WalletAsyncActions = { removeSitePermission: createAction( 'removeSitePermission' ), - addSitePermission: - createAction('addSitePermission'), refreshNetworksAndTokens: createAction('refreshNetworksAndTokens'), expandWalletNetworks: createAction('expandWalletNetworks'), // replace with chrome.tabs.create helper diff --git a/components/brave_wallet_ui/components/extension/connected-account-item/index.tsx b/components/brave_wallet_ui/components/extension/connected-account-item/index.tsx index a330780b859b..544a49ffc55b 100644 --- a/components/brave_wallet_ui/components/extension/connected-account-item/index.tsx +++ b/components/brave_wallet_ui/components/extension/connected-account-item/index.tsx @@ -7,6 +7,7 @@ import * as React from 'react' import { useDispatch } from 'react-redux' // Actions +import { PanelActions } from '../../../panel/actions' import { WalletActions } from '../../../common/actions' // Types @@ -83,7 +84,8 @@ export const ConnectedAccountItem = (props: Props) => { // methods const onClickConnect = React.useCallback(() => { - dispatch(WalletActions.addSitePermission({ accountId: account.accountId })) + dispatch(PanelActions + .requestSitePermission({ accountId: account.accountId })) if (selectedCoin !== BraveWallet.CoinType.SOL) { setSelectedAccount(account.accountId) } diff --git a/components/brave_wallet_ui/components/extension/dapp-connection-settings/change-account-button.tsx b/components/brave_wallet_ui/components/extension/dapp-connection-settings/change-account-button.tsx index 6386d117a755..0525c85d4801 100644 --- a/components/brave_wallet_ui/components/extension/dapp-connection-settings/change-account-button.tsx +++ b/components/brave_wallet_ui/components/extension/dapp-connection-settings/change-account-button.tsx @@ -8,6 +8,8 @@ import Button from '@brave/leo/react/button' import { useDispatch } from 'react-redux' // Actions +import { PanelActions } from '../../../panel/actions' + import { WalletActions } from '../../../common/actions' @@ -49,13 +51,15 @@ import { // Styled Components import { + ActiveIndicator, DescriptionText, NameText } from './dapp-connection-settings.style' import { Row, Column, - VerticalSpace + VerticalSpace, + HorizontalSpace } from '../../shared/style' interface Props { @@ -120,8 +124,8 @@ export const ChangeAccountButton = (props: Props) => { // Methods const onClickConnect = React.useCallback(() => { dispatch( - WalletActions - .addSitePermission({ accountId: account.accountId }) + PanelActions + .requestSitePermission({ accountId: account.accountId }) ) if (selectedCoin !== BraveWallet.CoinType.SOL) { setSelectedAccount(account.accountId) @@ -182,12 +186,25 @@ export const ChangeAccountButton = (props: Props) => { > {account.name} - - {reduceAddress(account.accountId.address)} - + + {reduceAddress(account.accountId.address)} + + {isActive && + <> + + + {getLocale('braveWalletActive')} + + + } + {accountFiatValue.isUndefined() ? ( <> diff --git a/components/brave_wallet_ui/components/extension/dapp-connection-settings/dapp-connection-main.tsx b/components/brave_wallet_ui/components/extension/dapp-connection-settings/dapp-connection-main.tsx index fb5d35514b82..59ea87f6be20 100644 --- a/components/brave_wallet_ui/components/extension/dapp-connection-settings/dapp-connection-main.tsx +++ b/components/brave_wallet_ui/components/extension/dapp-connection-settings/dapp-connection-main.tsx @@ -8,6 +8,8 @@ import Button from '@brave/leo/react/button' import { useDispatch } from 'react-redux' // Actions +import { PanelActions } from '../../../panel/actions' + import { WalletActions } from '../../../common/actions' @@ -124,8 +126,8 @@ export const DAppConnectionMain = (props: Props) => { return } dispatch( - WalletActions - .addSitePermission( + PanelActions + .requestSitePermission( { accountId: selectedAccount.accountId } ) ) diff --git a/components/brave_wallet_ui/panel/actions/wallet_panel_actions.ts b/components/brave_wallet_ui/panel/actions/wallet_panel_actions.ts index 353e532a9883..6baa32f6ddaf 100644 --- a/components/brave_wallet_ui/panel/actions/wallet_panel_actions.ts +++ b/components/brave_wallet_ui/panel/actions/wallet_panel_actions.ts @@ -10,6 +10,7 @@ import { DecryptProcessedPayload, ShowConnectToSitePayload, EthereumChainRequestPayload, + RequestSitePermissionPayloadType, SignMessageProcessedPayload, SignAllTransactionsProcessedPayload, SwitchEthereumChainProcessedPayload, @@ -25,6 +26,8 @@ import { HardwareWalletResponseCodeType } from '../../common/hardware/types' export const connectToSite = createAction('connectToSite') export const cancelConnectToSite = createAction('cancelConnectToSite') +export const requestSitePermission + = createAction('requestSitePermission') export const visibilityChanged = createAction('visibilityChanged') export const showConnectToSite = createAction('showConnectToSite') export const addEthereumChain = createAction('addEthereumChain') diff --git a/components/brave_wallet_ui/panel/async/wallet_panel_async_handler.ts b/components/brave_wallet_ui/panel/async/wallet_panel_async_handler.ts index b1b563dca6f9..28280900fde9 100644 --- a/components/brave_wallet_ui/panel/async/wallet_panel_async_handler.ts +++ b/components/brave_wallet_ui/panel/async/wallet_panel_async_handler.ts @@ -18,6 +18,7 @@ import { ConnectWithSitePayloadType, ShowConnectToSitePayload, EthereumChainRequestPayload, + RequestSitePermissionPayloadType, SignMessageProcessedPayload, SignAllTransactionsProcessedPayload, SwitchEthereumChainProcessedPayload, @@ -185,6 +186,12 @@ handler.on(PanelActions.connectToSite.type, async (store: Store, payload: Connec apiProxy.panelHandler.closeUI() }) +handler.on(PanelActions.requestSitePermission.type, + async(store: Store, payload: RequestSitePermissionPayloadType) => { + const apiProxy = getWalletPanelApiProxy() + await apiProxy.panelHandler.requestPermission(payload.accountId) +}) + handler.on(PanelActions.visibilityChanged.type, async (store: Store, isVisible) => { if (!isVisible) { return diff --git a/components/brave_wallet_ui/panel/constants/action_types.ts b/components/brave_wallet_ui/panel/constants/action_types.ts index 696738591573..60ae754e7271 100644 --- a/components/brave_wallet_ui/panel/constants/action_types.ts +++ b/components/brave_wallet_ui/panel/constants/action_types.ts @@ -9,6 +9,10 @@ export type AccountPayloadType = { selectedAccounts: BraveWallet.AccountInfo[] } +export type RequestSitePermissionPayloadType = { + accountId: BraveWallet.AccountId, +} + export type ConnectWithSitePayloadType = { addressToConnect: string, duration: BraveWallet.PermissionLifetimeOption