Conversation
Add runtime status updates and an open-wallet UX for NFT operations. - NftService: added an optional onStatus(String) callback and invoke it at key steps (uploading asset, preparing metadata, approving FULA, waiting for approval/mint confirmations, prompting wallet confirmation) so callers can surface progress to the user. - WalletService: import url_launcher and add connectedWalletName getter and tryOpenWallet() to launch the wallet app (native/universal link). Send-contract flow now logs debug info, applies a timeout to the request, attempts to open the wallet after sending the request, and surfaces clearer timeout errors. - NftProvider: pass the onStatus callback into NftService calls and update provider state.statusMessage; set context-aware status messages depending on walletSource (internal vs external) for mint/claim/burn/transfer/cancel flows. - NftDetailScreen: make the progress dialog reactive to the provider's statusMessage and show an "Open <Wallet>" button when the step indicates a wallet confirmation and a wallet is connected; move file resolution into the progress dialog so the UI shows preparation status during mint startup. These changes improve user feedback during long-running blockchain flows and make it easier for users to jump to their wallet to confirm transactions.
ehsan6sha
added a commit
that referenced
this pull request
May 19, 2026
Four client-side fixes for the seed-auth flow. Pairs with the matching server-side fixes in https://github.com/functionland/pinning-service (see those commit messages for the full audit narrative). ## #1 — Registration replay (CRITICAL) `signInModeB` and `signInModeC` previously generated their own challenge via `Random.secure()` and signed it locally before POSTing register-mode-{b,c}. The server accepted the client-supplied challenge without tracking it as single-use, so a captured request body could be replayed to mint fresh (perpetually-valid, DT-1) JWTs. Fix: both methods now fetch a server-issued challenge first (`IssuerClient.challenge(uid, purpose: 'register-mode-{b,c}')`) and sign that. The server consumes the same nonce in its store; replay returns HTTP 401 CHALLENGE_INVALID. `IssuerClient.challenge` gained a `purpose` parameter; the previous default behavior (`'sign-in'`) is preserved when the parameter is omitted. The now-unused `_randomBytes` helper was removed. ## #2 — NFKC inconsistency between KEK and effective_user_id (CRITICAL) `_canonicalKekInputModeB` / `_canonicalKekInputModeC` in `auth_service.dart` passed `utf8.encode(seed)` raw to Argon2id. The matching `fula.computeEffectiveUserIdModeB/c` and `fula.deriveSigningSeed` Rust FFI calls NFC-normalize the seed internally. Consequence: a Mode B user typing a non-ASCII password in NFC on Device A vs NFD on Device B got the SAME `effective_user_id` (same vault on the server) but DIFFERENT master KEKs → permanent cross-device decryption failure. Fix: extracted the canonical-input logic to a new helper `lib/core/utils/canonical_kek_input.dart` that NFC-normalizes the seed using the `unorm_dart` package (pure Dart, no native deps — the upstream `unicode_normalization` package doesn't exist on pub.dev under that name). 8 unit tests cover NFC=NFD equivalence, separator-injection resistance, determinism, and distinct-input distinctness. Note: my commit messages on `7fa2f32` and the audit transcript use "NFKC"; the Rust code calls `.nfc()` (canonical-composed NFC, not the compatibility-decomposing NFKC). Both are fine; the code is self-consistent; the Dart side now uses the same NFC. ## #3 — Mode B signing key not OAuth-bound (CRITICAL) `fula.deriveSigningSeed(seed)` derives the 32-byte Ed25519 seed from `BLAKE3_derive_key("fula:signing-key:v2", NFC(seed))` — the password ONLY. Two Mode B users under different OAuth identities but the same password derived IDENTICAL keypairs. Combined with the public users-index CBOR (which exposes effective_user_ids), this would let one of them sign in to the other's vault: read the target's effective_user_id from the public CBOR, sign the sign-in transcript with their own (identical) keypair, server verifies, mints JWT. Fix: new helper `lib/core/utils/seed_signing_input.dart` constructs a tagged-and-length-separated string for Mode B (`'b\x00$provider\x00$oauthSub\x00$password'`) that's passed to `deriveSigningSeed` instead of the raw password. The signing seed is now bound to the full `(provider, oauth_sub, password)` tuple. Mode C stays seed-only (no OAuth to bind to); the leading `'b\x00'` tag guarantees Mode B inputs can't collide with Mode C inputs. 6 unit tests cover the distinctness and collision-resistance properties. ## #4 — `has_mode_a` flag wiring + logic The server's `has_mode_a` field on the register-mode-b response was both miscomputed (counted seed_users rows for the same oauth_sub, which detects "other seed vaults" not "Mode A account") AND ignored by the client (`SeedAuthResult.hasModeA` was returned by `IssuerClient` but `signInModeB`/`signInGoogleModeB`/`signInAppleModeB` dropped it when returning `AuthUser?`). Fix server-side (separate pinning-service commit): replaced the helper with `checkModeAExistsForEmail` doing a direct PK lookup on `webui_users` keyed by `SHA-256(lowercase(email))`. Fix client-side: `signInModeB` / `signInGoogleModeB` / `signInAppleModeB` now return `({AuthUser user, bool hasModeA})?`. The Mode B sign-in screen checks `result.hasModeA` and shows an "Existing vault detected" warning dialog ("Your existing files are NOT in this vault — to access them, sign out and use Standard security") before navigating home. ## Files New: - `lib/core/utils/canonical_kek_input.dart` + unit test (8 cases) - `lib/core/utils/seed_signing_input.dart` + unit test (6 cases) Modified: - `lib/core/services/auth_service.dart` — challenge round-trip, canonical KEK helper usage, Mode B signing input, record-typed return values for the convenience wrappers. - `lib/core/services/issuer_client.dart` — `purpose` param on `challenge()`. - `lib/features/onboarding/screens/mode_b_signin_screen.dart` — Existing-vault warning dialog wired to `result.hasModeA`. - `pubspec.yaml` — `unorm_dart: ^0.3.0` for Dart-side NFC. `flutter analyze` clean on all touched files (2 pre-existing INFO warnings on auth_service.dart, neither from this change). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ehsan6sha
added a commit
that referenced
this pull request
Jun 23, 2026
Mirror the category tabs: file rows in the Cloud Files manager now show compact tag chips under the name, reusing WebTagService.tagsForObjects. - _fileTags map refreshed after each listing (indexed over the WHOLE flat bucket, so subfolder rows resolve without a reload) and after a tag edit - chips rendered in the row subtitle (up to 2 + "+N"), only when present - _fileTags cleared on bucket switch to avoid a stale cross-bucket flash - _TagChipRow duplicated from WebBucketScreen (copy #2; extract on #3) No SDK / shared-service changes; tagsForObjects + _bareKey untouched, so chips compute identically to the already-shipped Tags action. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.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.
rest is in nft-plan.md