fix: gate DFX auth at the source instead of HomeBloc only#304
Merged
TaprootFreak merged 1 commit intoMay 8, 2026
Merged
Conversation
bitbox_flutter's ETHSignMessage panics on a NACK from the device and crashes the Flutter engine. The HomeBloc check from RealUnitCH#301 only blocks the auto-auth on Home, but the same call path is reachable from DfxKycService, DfxSupportService, DfxWidgetService, and any future DFXAuthService consumer — every one of them would crash the app for a BitBox-backed wallet. Move the BitBox short-circuit into DFXAuthService.getAuthToken() itself: it returns null for BitBox wallets, which the existing callers already handle as "not authenticated". Removed the now redundant guard in HomeBloc._setupFiatService.
9 tasks
TaprootFreak
added a commit
that referenced
this pull request
May 12, 2026
> [!IMPORTANT] > **Merge-blocked on DFXswiss/bitbox_flutter#11.** Without that SDK PR's per-message scoped dedup + 60 s BLE read timeout, the EIP-712 sign aborts at step 1→2 (BLE-layer retransmit corrupts the U2F HID frame stream) and / or after the 10 s timeout fires mid-confirmation. Sequence: merge #11 → tag `v0.0.3` → bump this PR's `pubspec.yaml` from `v0.0.2` to `v0.0.3` → merge here. ## Summary - `KycCubit` hoists the disclaimer + form (name/address) + EIP-712 13-step BitBox sign in front of every state past the email step. Returning users at `level >= requiredLevel` previously dropped straight into `KycCompleted` without ever touching the BitBox; the hardware-wallet ceremony is the security gate, not the backend KYC level. `_bitboxConfirmed` is per-`KycCubit` instance and resets on every KYC entry, so each entry forces a fresh confirmation. - `KycRegistrationSubmitCubit` treats every `ApiException` raised after a successful EIP-712 sign as `RegistrationStatus.completed`. The user has proven hardware-wallet control on the device — the backend's logical reply (already registered, wallet linked to another account, merge required, …) is informational. `KycCubit.checkKyc()` then resolves the next state from the refreshed status, including the existing `KycAccountMergeRequested` page when the wallet is bound to another DFX user. Network / parse / sign errors raise non-`ApiException` types and still surface as a `KycRegistrationSubmitFailure` SnackBar. - `Eip712Signer._signTypedData` now throws when the signature comes back empty or `'0x'`. The bitbox_flutter iOS bridge returns empty bytes when the user cancels mid-sign or the BLE link drops; before this PR the empty signature was POSTed and silently accepted as a successful sign. - TFA handling: the cubit recognises both `statusCode == 403` and `code == 'TFA_REQUIRED'` as the trigger for routing to the 2FA step (paired with #310's `httpStatusCode` fallback so the code path is reachable). - `checkKyc` is wrapped in a 30 s top-level timeout. The email-auto-registration recursion has a one-shot guard so a backend that does not bump the level after `registerEmail` cannot keep the loading spinner alive forever. An `isClosed` guard after the API fetch in `_runCheckKyc` prevents a slow response from overwriting a timeout failure. - `DFXAuthService`: removed the BitBox auth skip from #304 (no longer needed after the v0.0.2 SDK fixes — see inline comment for context). Added a 3 min sign timeout for the BitBox 13-step ceremony, 20 s HTTP timeouts, and an empty-signature guard for personal-message signing. - Email verification shows a localized BitBox sign hint (`registerEmailVerificationBitboxSignHint`) below the confirm button while the signature ceremony is running. ## Test plan - [x] `flutter analyze` — no issues - [x] `flutter test` — 188 tests pass - [ ] Fresh wallet without RealUnit registration: email → disclaimer → form → BitBox 13 fields + sign → ident - [ ] Wallet already attached to the same RealUnit user, KYC level < 30: disclaimer → form → BitBox 13 fields + sign → ident (backend's already-registered reply tolerated, KYC continues) - [ ] **Wallet attached to a different DFX user**: disclaimer → form → BitBox 13 fields + sign → `KycAccountMergePage` ("Identität in anderem Konto gefunden, Merge per Email bestätigen") instead of the generic failure screen - [ ] Returning user already at `level >= 30`: disclaimer + form + BitBox sign first, then `KycCompleted` (no silent grant) - [ ] Cancel the BitBox sign mid-ceremony → `Signature was empty` SnackBar, no silent success - [ ] BitBox not connected on submit → existing modal sheet pops (light theme), reconnect → retry - [ ] Backend response with `code: TFA_REQUIRED` → cubit emits `KycSuccess(twoFa)` instead of `KycFailure` --------- Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com>
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.
Summary
HomeBloc._setupFiatServiceand intoDFXAuthService.getAuthToken()so every caller is coveredgetAuthToken()returnsnullforBitboxCredentialswallets, which the existing callers already treat as "not authenticated"Why
bitbox_flutter'sETHSignMessagepanics on a NACK from the device and crashes the Flutter engine (panics in gomobile bindings cannot be caught from Dart). #301 added a guard insideHomeBloc._setupFiatServiceso the auto-auth on Home would not crash a BitBox-backed wallet, but the samegetAuthToken()path is reachable fromDfxKycService,DfxSupportService,DfxWidgetService, and every futureDFXAuthServiceconsumer — each one would still crash the app the moment the user touched that feature.Putting the check at the source means the workaround can stay in one place until the SDK returns the error gracefully (tracked in DFXswiss/bitbox_flutter).
Changes
lib/packages/service/dfx/dfx_auth_service.dart:getAuthToken()short-circuits tonullwhen the active credentials areBitboxCredentialslib/screens/home/bloc/home_bloc.dart: drop the now-redundant guard and thebitbox_credentialsimportTest plan