Repository navigation
fix(mobile): restore keysForNsec after the native key derivation change - #9085
Conversation
#8965 removed AccountIdentityStore._keys, but keysForNsec (added by #9029, which merged first) still called it, so main fails flutter analyze. Build the keys through keysForHex, which applies the same scalar validation. Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tom Brow <tomb@squareup.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
🔐 Codex Security Review
Review SummaryOverall Risk: NONE
FindingsNo concrete security, correctness, or reliability findings were identified. Notes
Generated by Codex Security Review | |
## What changes Mobile now finds a person who has a relay-verified profile (NIP-FI, kind 30382) but never published a kind:0 profile. This happens, for example, when someone skips profile setup. The relay's `POST /profiles/search` already finds such people by their verified name. Each one comes back as a kind:30382 head with no kind:0. Mobile kept only kind:0 results, so these people did not appear. - `RelaySessionNotifier.searchProfiles` keeps kind:30382 heads from the endpoint. - `VerifiedProfilesNotifier.searched` turns a search page into people: - If the relay authority is not known yet, it first waits for NIP-11 discovery. Otherwise, a search that finished first would drop these people for that query. - It checks each head's signature with the directory's off-isolate proof checker. - Proven heads go into the verified directory, so the rows show verified names right away. - `searchedPeople` (in `verified_profile.dart`) builds one row per person, in the relay's order: - If the person has a kind:0, the newest kind:0 is used, as before. - If not, it uses the proven head that the authority signed, provided it parses as an active verified profile. - These cases add no row: - a head signed by another key; - a head that names the relay key but has a bad signature; - a retraction; - a malformed subject. - **Behavior change for all mobile mentions:** every verified person now matches in mention ranking by their verified full name and username, as well as by display name, including people who have a kind:0. The relay's search matches these same three names. Without this, a person whose display name is their username (`glilienfeld`, full name "Gabi Lilienfeld") came back from the relay for "gabi", and then the local filter dropped them. - Callers: - Mention search, which also serves Add members and New DM. - The user rows in global search, through `directoryUsersFromSearch`. The desktop app has the same fix for Manage members: block/buzz-app#2554 ## Screenshots These come from the real Add members sheet on an Android emulator. Only the relay session, verified-profile discovery and the member actions are faked. The names are made up. Jordan Park has a kind:0. jrivera has only a verified profile, with the full name "Jordan Rivera". The search is "jordan". The row shows the verified display name, which here is the same as the username. | Search finds jrivera | After tapping + on jrivera | | --- | --- | | <img width="300" alt="jrivera is found next to Jordan Park" src="https://github.com/user-attachments/assets/d93b77b1-1bc7-4d09-afc1-f359616a192a" /> | <img width="300" alt="jrivera is selected to add" src="https://github.com/user-attachments/assets/ce6c7a71-b098-434e-8b0e-ed0de8d1a5a2" /> | ## Tests - `add_members_sheet_names_test.dart`: a journey in which Gabi has `display_name` = `glilienfeld` and `full_name` = "Gabi Lilienfeld", and NIP-11 discovery is slow. - While discovery is pending, typing "gabi" shows nothing yet. - When discovery finishes, Gabi appears with no further keystroke. - A head from another key does not appear, and neither does a head that names the relay key but has a bad signature. - **Add member** adds Gabi's key. - I removed each fix in turn: the full-name alias, the signature proof, and the wait for discovery. The journey fails each time, for the expected reason. - `verified_profile_test.dart`: a table of `searchedPeople` cases. - A kind:0 wins over a head, and the newest kind:0 counts. - These find nobody: another signer, a retraction, an uppercase subject, a non-profile kind, and any head when the authority is unknown. - `relay_session_test.dart` and `channel_management_provider_test.dart`: rows for the kept heads and the directory row. - `flutter analyze` is clean, and the full `flutter test` passes on 6efef79: 4,462 tests. **Note:** mobile on `main` does not compile at e558f15. `account_identity_store.dart` calls the removed `_keys`. That fix is #9085. The local runs above had that one-line fix applied but not committed. Until it lands, mobile CI on this PR will fail. ## Not covered - **Search during a reconnect:** discovery starts only when the relay session is connected. If an HTTP search succeeds while the session is reconnecting, that search leaves these people out. - **Discovery failure:** if NIP-11 discovery fails, the search also leaves these people out. - In both cases the mention cache keeps that partial page for the query, and the next search tries discovery again. People who have a kind:0 show as before. Showing the left-out people when the authority arrives later would need the cached results to be rebuilt; that is a possible follow-up. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Logan Johnson <loganj@squareup.com> Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Summary
#8965 native key derivation removed
AccountIdentityStore._keys.keysForNsec, added by #9029 nsec backup, which merged first, still called it. The two PRs didn't conflict textually, somainnow failsflutter analyze(_keysisn't defined ataccount_identity_store.dart:356) and mobile CI is red.This builds the keys through
keysForHex(_nsecHex(nsec)), the same pathwithKeysuses since #8965. It applies the same bech32 decoding and secp256k1 scalar validation that_keysdid.Testing
just mobile-check: no issues found.flutter test(full mobile suite): 4460 passed, 49 skipped. No UI change, so no app run.🤖 Generated with Claude Code