feat: otp-display-grant#84
Draft
lwin-kyaw wants to merge 8 commits into
Draft
Conversation
…t/otp-display-grant
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Implements an opt-in strict untrusted connection flow that defers wallet OTP display until the dapp explicitly grants it for the accepted handshake offer. The default untrusted flow is unchanged.
ADDED
packages/core)SessionRequest.capabilities.otpDisplayGrantHandshakeOfferPayload.otpDisplayGrantRequiredOtpDisplayGrantmessage type ({ type: "otp-display-grant" })OTP_DISPLAY_GRANT_REQUIRED,OTP_DISPLAY_GRANT_TIMEOUTpackages/dapp-client)DappConnectOptions.requireOtpDisplayGrant— advertises capability on the session request whenmode: "untrusted"otpDisplayGrantRequiredotp-display-granton the handshake channel after accepting the offersendMessagecan encrypt to the accepted wallet)packages/wallet-client)capabilities.otpDisplayGrantis present on the session request: sendhandshake-offerwithotpDisplayGrantRequired: true, wait forotp-display-grant, then emitdisplay_otpotp-display-grantduringCONNECTINGtootp_display_grant_receiveddocs/otp-display-grant-plan.md— design, compatibility matrix, security notesdocs/otp-display-grant-implementation-plan.md— phased implementation checklistapps/integration-testsfor strict connect, compatibility matrix rows, anddisplay_otptimingCHANGED
requireOtpDisplayGrantis omitted orfalse.Issue
In the current untrusted flow, the wallet displays the OTP before the dapp has accepted a specific
handshake-offer. In a same-room scenario, an attacker can scan the same QR code, front-run the real wallet with an attacker-controlled offer, and potentially cause the dapp to bind to the attacker's session if the user enters an OTP matching that offer.Solution
Strict mode is opt-in:
When enabled:
display_otpyet.handshake-offerwithotpDisplayGrantRequired: trueon the handshake channel.otp-display-granton the handshake channel.display_otp.handshake-ackon the session channel.The grant is encrypted to the accepted offer's wallet public key. A front-running attacker may still cause timeout/DoS, but the legitimate wallet should not display an OTP for an offer the dapp did not accept.
Design note:
otp-display-grantis sent on the handshake channel (not the session channel).handshake-ackremains on the session channel and still means "OTP verified; finalize connection."Compatibility matrix
requireOtpDisplayGrant: true+ old walletOTP_DISPLAY_GRANT_REQUIREDrequireOtpDisplayGrant: true+ new walletStrict mode does not silently fall back.
Strict flow sequence
Handshake channel:
handshake-offer,otp-display-grantSession channel:
handshake-ack, then application trafficSessionRequestwithcapabilities.otpDisplayGrant = true.display_otp.handshake-offerwithotpDisplayGrantRequired: trueon the handshake channel.otpDisplayGrantRequired, dapp rejects.otp-display-granton the handshake channel.display_otp.handshake-ackon the session channel.Test plan
display_otp, grant timeout, legacy regression, full strict happy pathhandleMessageroutesotp-display-grantapps/integration-tests, requires local Centrifugo relay):connectClientsStrict()helperOTP_DISPLAY_GRANT_REQUIREDdisplay_otpfires after dapp receives handshake offer in strict modeRun locally:
Follow-ups (out of scope for this PR)
apps/web-demotoggle forrequireOtpDisplayGrantdocs/02-connection-flow.mdwith strict-flow subsectionChecklist