diff --git a/CHANGELOG.md b/CHANGELOG.md index bd4aed73..f28ca796 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,5 +13,6 @@ ### Changed - Suggest running a recovery when facing account or identity creation errors - Baker/baking renamed to Validator/validating +- WalletConnect session proposals are now rejected if the namespace or methods are not supported, or if the wallet contains no accounts. [Unreleased]: https://github.com/Concordium/cryptox-android/compare/0.6.1-qa.5...HEAD diff --git a/app/src/main/java/com/concordium/wallet/ui/walletconnect/WalletConnectView.kt b/app/src/main/java/com/concordium/wallet/ui/walletconnect/WalletConnectView.kt index 338946b6..72cacfe9 100644 --- a/app/src/main/java/com/concordium/wallet/ui/walletconnect/WalletConnectView.kt +++ b/app/src/main/java/com/concordium/wallet/ui/walletconnect/WalletConnectView.kt @@ -163,6 +163,9 @@ class WalletConnectView( WalletConnectViewModel.Error.NoSupportedChains -> R.string.wallet_connect_error_no_supported_chains + + WalletConnectViewModel.Error.UnsupportedMethod -> + R.string.wallet_connect_error_unsupported_methods } Toast.makeText(activity, errorRes, Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/com/concordium/wallet/ui/walletconnect/WalletConnectViewModel.kt b/app/src/main/java/com/concordium/wallet/ui/walletconnect/WalletConnectViewModel.kt index 24f29158..f686bcc8 100644 --- a/app/src/main/java/com/concordium/wallet/ui/walletconnect/WalletConnectViewModel.kt +++ b/app/src/main/java/com/concordium/wallet/ui/walletconnect/WalletConnectViewModel.kt @@ -106,6 +106,11 @@ private constructor( ), ) + private val allowedRequestMethods = setOf( + REQUEST_METHOD_SIGN_AND_SEND_TRANSACTION, + REQUEST_METHOD_SIGN_MESSAGE, + ) + private val accountRepository: AccountRepository by lazy { AccountRepository(WalletDatabase.getDatabase(getApplication()).accountDao()) } @@ -289,15 +294,30 @@ private constructor( allowedChains.contains(chain) } + val proposerPublicKey = sessionProposal.proposerPublicKey + if (singleNamespaceEntry == null || singleNamespaceChain == null) { Log.e("cant_find_supported_chain") - mutableEventsFlow.tryEmit( Event.ShowFloatingError( Error.NoSupportedChains ) ) - mutableStateFlow.tryEmit(State.Idle) + rejectSession(proposerPublicKey, "The session proposal did not contain a valid namespace. Allowed namespaces are: $allowedChains") + return@launch + } + + // Check if the proposer requests unsupported methods, and reject the session proposal + // if that is the case. + val requestedMethods = singleNamespaceEntry.value.methods + if (!allowedRequestMethods.containsAll(requestedMethods)) { + Log.e("Received an unsupported request method: $requestedMethods") + mutableEventsFlow.tryEmit( + Event.ShowFloatingError( + Error.UnsupportedMethod + ) + ) + rejectSession(proposerPublicKey, "An unsupported method was requested: $requestedMethods, supported methods are $allowedRequestMethods") return@launch } @@ -306,17 +326,16 @@ private constructor( val accounts = getAvailableAccounts() if (accounts.isEmpty()) { Log.d("there_are_no_accounts") - mutableEventsFlow.tryEmit( Event.ShowFloatingError( Error.NoAccounts ) ) - mutableStateFlow.tryEmit(State.Idle) + rejectSession(proposerPublicKey, "The wallet does not contain any accounts to open a session for") return@launch } - this@WalletConnectViewModel.sessionProposalPublicKey = sessionProposal.proposerPublicKey + this@WalletConnectViewModel.sessionProposalPublicKey = proposerPublicKey this@WalletConnectViewModel.sessionProposalNamespaceKey = singleNamespaceEntry.key this@WalletConnectViewModel.sessionProposalNamespace = singleNamespaceEntry.value this@WalletConnectViewModel.sessionProposalNamespaceChain = singleNamespaceChain @@ -375,20 +394,14 @@ private constructor( mutableStateFlow.tryEmit(State.Idle) } - fun rejectSessionProposal() { - check(state is State.SessionProposalReview || state is State.AccountSelection) { - "Session proposal rejection is only possible in the proposal review " + - "or account selection states" - } + private fun rejectSession(proposerPublicKey: String, reason: String) { + val rejectParams = Sign.Params.Reject( + proposerPublicKey = proposerPublicKey, + reason = reason + ) - SignClient.rejectSession( - Sign.Params.Reject( - proposerPublicKey = sessionProposalPublicKey, - reason = "Rejected by user", - ) - ) { error -> + SignClient.rejectSession(rejectParams) { error -> Log.e("failed_rejecting_session", error.throwable) - mutableEventsFlow.tryEmit( Event.ShowFloatingError( Error.ResponseFailed @@ -399,6 +412,14 @@ private constructor( mutableStateFlow.tryEmit(State.Idle) } + fun rejectSessionProposal() { + check(state is State.SessionProposalReview || state is State.AccountSelection) { + "Session proposal rejection is only possible in the proposal review " + + "or account selection states" + } + rejectSession(sessionProposalPublicKey, "Rejected by user") + } + fun onChooseAccountClicked() { val reviewState = checkNotNull(state as? State.SessionProposalReview) { "Choose account button can only be clicked in the proposal review state" @@ -1243,6 +1264,11 @@ private constructor( */ object NoSupportedChains : Error + /** + * The dApp sent a session proposal requesting an unsupported method. + */ + object UnsupportedMethod : Error + /** * The dApp sent a request that can't be parsed. */ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a1d4af96..9a4e7874 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -552,6 +552,7 @@ Could not submit the transaction You must have at least one active account to continue The wallet does not support the requested chains + The wallet does not support the requested methods Choose another account Connect to %1$s? @string/allow