Skip to content

apps: ask the user before signing a message for an app (#1881) - #2156

Open
profinch wants to merge 1 commit into
BeamMW:masterfrom
profinch:fix/1881-sign-message-consent
Open

profinch wants to merge 1 commit into
BeamMW:masterfrom
profinch:fix/1881-sign-message-consent

Conversation

@profinch

@profinch profinch commented Oct 7, 2026

Copy link
Copy Markdown

Fixes #1881.

Problem

sign_message is allowed for apps (APPS_ALLOWED), and AppsApi::AnyThread_callWalletApiChecked asks the user only for tx_send and process_invoke_data. Any other allowed method runs right away. So a DApp could get a signature made with a key derived from the wallet's master key, for any message and any key_material, without the user seeing anything.

Change

  • AppsApi sends sign_message to a consent step, like tx_send and contract calls. The method runs only after the wallet calls AnyThread_callWalletApiDirectly(request) (approve). A rejection goes through AnyThread_sendApiError(..., UserRejected), as for the other consents.
  • New virtual ClientThread_getSignConsent(request, info). info has message, keyMaterial and isSignMessage: true.
  • No wallet changes needed. By default the hook calls the existing ClientThread_getContractConsent with the message as comment, fee: 0, isSpend: false, isEnough: true and no amounts. beam-ui, Android (android/dao) and the web wallet (wasmclient) already implement that dialog (checked against beam-ui 1cc4d1a, AppView.qml → send_confirm.qml), so they ask the user right away. A wallet can override the hook later for a dedicated "sign message" dialog.
  • CheckInfo uses an enum instead of the send bool, since there are now three kinds of consent.

wallet-api itself (API key owner, not an app) is unchanged.

Tests

New TestAppsApiSignMessage in wallet_test. It runs end to end: a real WalletClient with its wallet thread, an app created via AppsApi::ClientThread_Create, and client-context calls run on the main reactor, as the UI thread does. The test checks that:

  1. the app's sign_message produces no response and asks for consent, with the message, key material, no fee and no amounts;
  2. after approval the app gets the signature.

Without the fix the test fails: the app gets the signature immediately and no consent is requested. With the fix, wallet_test and wallet_api_test pass (macOS arm64, Ninja RelWithDebInfo). The Android and wasm builds are not built here. They don't override the new hook, so they use the default.

An app could call sign_message and get a signature with no user
interaction. AppsApi now asks for consent first, like for tx_send and
contract calls.

The wallets get a new virtual ClientThread_getSignConsent with the message
and the key material. Its default shows the existing contract consent dialog
with the message as the comment, no amounts and no fee, so beam-ui, Android
and the web wallet ask the user without any change on their side. A wallet
can override it for a dedicated dialog.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API. Add user confirmation to sign_message

1 participant