mirror of
https://github.com/block/buzz.git
synced 2026-11-02 23:41:08 +00:00
bfc79dfb593be7aef6fa4e06a1345da74908a8ef
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
88d08e426c |
feat(desktop): guide and verify password-protected backups (#3617)
**Category:** improvement **User Impact:** Users can create a password-protected key backup, save it locally, and prove that it works before finishing onboarding or signing out. **Problem:** Tyler's NIP-49 foundation made encrypted local backup possible, but the end-to-end ceremony still needed clearer progression, trustworthy verification, and a Settings treatment consistent with the rest of Identity. **Solution:** This stack adds a guided create/download/test flow, verifies the actual saved backup through Rust without returning secret key material, minimizes password lifetime in the webview, and restores warm, plain-language presentation across onboarding and Settings. > [!NOTE] > This PR is intentionally stacked on #2937 (`eva/nip49-local-backup`). Review only the 19 commits in this stack. <details> <summary>File changes</summary> **desktop/src-tauri/src/commands/identity.rs** Adds off-thread verification of NIP-49 backups and returns public identity details only. **desktop/src-tauri/src/commands/identity_key_backup_tests.rs** Covers verification, identity matching, and failure behavior at the command boundary. **desktop/src-tauri/src/egress_guard_tests.rs** Keeps the NIP-49 source inventory aligned with the new verification path. **desktop/src-tauri/src/key_backup.rs** Supports real backup decryption for verification while zeroizing submitted passwords. **desktop/src-tauri/src/key_backup_tests.rs** Exercises valid, wrong-password, damaged, and different-identity backups. **desktop/src-tauri/src/lib.rs** Registers the verification command with the desktop runtime. **desktop/src/features/communities/ui/WelcomeSetup.tsx** Routes community onboarding through the revised backup ceremony. **desktop/src/features/onboarding/lib/encryptedBackup.test.mjs** Covers the hardened backup state model and password-clearing behavior. **desktop/src/features/onboarding/lib/encryptedBackup.ts** Models creation and verification with opaque request correlation and short-lived passwords. **desktop/src/features/onboarding/ui/BackupStep.tsx** Presents the backup choice clearly and advances into the dedicated download step. **desktop/src/features/onboarding/ui/BackupTestFlow.tsx** Adds the polished select-file, enter-password, verification, error, and success experience. **desktop/src/features/onboarding/ui/CommunityOnboardingFlow.tsx** Connects community onboarding to the updated backup steps. **desktop/src/features/onboarding/ui/DownloadKeyStep.tsx** Adds the dedicated encrypted-backup download step and pre-creation skip escape hatch. **desktop/src/features/onboarding/ui/EncryptedBackupCreator.tsx** Guides password generation, backup creation, native saving, safe retry, and re-download. **desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx** Sequences chooser, download, exact-file test, and setup progression. **desktop/src/features/onboarding/ui/NostrKeyImportForm.tsx** Aligns encrypted-key import behavior with the backup flow. **desktop/src/features/onboarding/ui/NsecMaskedDisplay.tsx** Improves masked/revealed key presentation and safely wraps long private keys. **desktop/src/features/onboarding/ui/OnboardingChrome.tsx** Supports the revised onboarding layout and transitions. **desktop/src/features/onboarding/ui/SetupStep.tsx** Integrates the completed backup ceremony with final setup. **desktop/src/features/onboarding/ui/onboardingFlowSteps.test.mjs** Updates flow-level assertions for the new step sequence. **desktop/src/features/settings/ui/EncryptedBackupRow.tsx** Adds sibling Create and Test rows that match the surrounding Identity settings rhythm. **desktop/src/features/settings/ui/ProfileSettingsCard.tsx** Places password-backup controls in the Identity card. **desktop/src/features/settings/ui/SignOutSection.tsx** Uses explicit backup self-attestation plus the existing wipe phrase without requiring a raw-key reveal first. **desktop/src/shared/api/tauriIdentity.ts** Exposes typed backup verification to the frontend. **desktop/src/shared/lib/ncryptsecSourceScan.test.mjs** Updates the frontend source allowlist for the verification path. **desktop/src/testing/e2eBridge.ts** Models creation, saving, and verification for browser coverage. **desktop/tests/e2e/onboarding-backup.spec.ts** Covers backup creation, exact-file testing, errors, retries, and completion. **desktop/tests/e2e/onboarding-docked-cta-screenshots.spec.ts** Updates docked CTA visual coverage for the revised progression. **desktop/tests/e2e/onboarding.spec.ts** Keeps broader onboarding coverage aligned with the backup ceremony. **desktop/tests/e2e/profile-nsec-reveal.spec.ts** Covers Settings create/test behavior and updated success copy. **desktop/tests/e2e/signout-confirmation.spec.ts** Covers backup self-attestation, wipe phrase confirmation, and reset behavior. **desktop/tests/helpers/fileDrag.ts** Adds reusable file-drop support for backup test coverage. **desktop/tests/helpers/onboarding.ts** Routes tests through chooser, download, and skip behavior consistently. </details> ## Reproduction steps 1. Start fresh onboarding and choose the password-protected backup path. 2. Continue to **Backup your key**, create a password, save the `.ncryptsec` file, and confirm that **Next** remains gated until testing succeeds. 3. Select that exact file, enter its password, and verify the **Your backup works!** success state. 4. Open **Settings → Identity** and confirm that **Create password backup** and **Test password backup** appear as sibling rows. 5. Test a valid backup, then test wrong-password and different-identity cases to confirm clear, non-secret-bearing outcomes. 6. Open sign out and confirm that backup self-attestation plus typing `wipe all my data` remain required. ## Screenshots ### Onboarding flow | 1. Creating your key | 2. Key created | 3. Create backup password | |---|---|---| | <img width="1280" height="720" alt="image" src="https://github.com/user-attachments/assets/fe5ebf60-02ad-4584-8e64-ff137bafac02" /> | <img width="1280" height="720" alt="image" src="https://github.com/user-attachments/assets/0b8c7c6c-2ae5-494e-bb81-0a7b47ea1b66" /> | <img width="1280" height="720" alt="image" src="https://github.com/user-attachments/assets/9fa8f6c0-832a-46ec-9af8-55dcae0adbb8" /> | | **4. Select the saved backup** | **5. Enter its password** | **6. Verification succeeds** | | <img width="1280" height="720" alt="image" src="https://github.com/user-attachments/assets/7ed1528c-6a1f-4411-bd3e-c57413320cdf" /> | <img width="1280" height="720" alt="image" src="https://github.com/user-attachments/assets/088ec3ed-2735-4b9a-a0c5-6d176b3f06c5" /> | <img width="1280" height="720" alt="image" src="https://github.com/user-attachments/assets/7081ce32-9371-46b2-9692-23ff77c39d35" /> | ### Settings flow | Create and Test tools | Tested backup success | |---|---| | <img width="1280" height="720" alt="image" src="https://github.com/user-attachments/assets/978ab672-5510-46d8-9116-6df4f1bda34c" /> | <img width="1280" height="720" alt="image" src="https://github.com/user-attachments/assets/56a1764d-3c3e-40e2-9f4b-962c5e96a36c" /> | ## Verification - Desktop typecheck - Full desktop JS: 3,733/3,733 - `pnpm check` - Rust desktop lib: 1,862 passed, 14 ignored; diagnostic: 3/3 - Focused Playwright: 16/16 with one worker Native save/cancel remains the residual smoke-test risk: browser E2E mocks the KDF/native save-dialog boundary, while real decrypt and identity matching are covered in Rust. --------- Signed-off-by: Taylor Ho <taylorkmho@gmail.com> Co-authored-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@buzz.block.builderlab.xyz> |
||
|
|
51ea1b18f3 |
fix(desktop): rename settings row to Password Backup per spec
Tyler's spec names the settings entry "Password Backup". Rename the row title and align its description (password, not passphrase) plus the two doc comments that referenced the old row name. No behavior change; test ids unchanged. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz> |
||
|
|
dde37183e3 |
Address implementation-review blockers: import ordering, site-granular inventory, uppercase bech32
Blocker 1: import_identity persisted-before-cleanup ordering. New commit_imported_identity helper runs durable persistence FIRST; a failed different-key import now leaves both the old in-memory identity and its valid canonical identity.ncryptsec intact. Stale-backup cleanup runs after the durable commit and is deliberately best-effort (logged, not surfaced as a half-applied-import error). Regression tests cover the failure path and prove cleanup cannot precede persist. Blocker 2: the /events inventory tripwire is now site-granular. Each inventoried file pairs an expected non-comment /events occurrence count with an expected egress-guard call count, so an unguarded ninth site in an already-listed file (or a deleted guard call) fails the scan. The scan core is pure over (path, content) pairs, with mutation-style tests demonstrating all three drift classes. Hardening: bech32 permits an all-uppercase encoding, so the egress guard now rejects NCRYPTSEC1... too (mixed case stays unblocked - it cannot decode), and both import classifiers (Rust recover_keys_from_input, TS classifyKeyImportInput/isPlausibleNcryptsec) route uppercase-valid blobs to the encrypted path consistently. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz> |
||
|
|
1c01889929 |
Encrypted-by-default key backup UI + ncryptsec import (frontend half)
Frontend half of PLANS/NIP49_LOCAL_BACKUP_PLAN.md Rev 3 (D3): - BackupStep: encrypted by default. The default path never invokes get_nsec — the webview only ever sees the finished ncryptsec1 blob returned by create_ncryptsec_backup. The raw key path survives behind an explicit 'Show raw key instead' click with its previous loading/error/skip semantics. - EncryptedBackupCreator (shared by onboarding + settings): generated 6-word passphrase default with cannot-be-recovered copy, 'choose my own' = min 12 chars + confirmation, create -> masked display + copy + 'Save a copy…' via the native dialog. - encryptedBackup.ts: pure reducer/validation model, unit-tested without a DOM; keyImportInput.ts: HRP classification + submit gating. - NsecMaskedDisplay: kind='nsec'|'ncryptsec' drives labels/aria/testids; existing nsec call sites unchanged. - NostrKeyImportForm: ncryptsec1 paste switches to encrypted mode (passphrase field, no npub preview possible), decrypt errors surface; raw nsec flow untouched. import_identity plumbs the optional password through OnboardingFlow/MachineOnboardingFlow/KeyringLockedScreen. - ProfileSettingsCard: 'Encrypted backup' row alongside the raw reveal. - ncryptsecSourceScan.test.mjs: TS-side source-allowlist tripwire mirroring the Rust scan (defense-in-depth per plan D4). - e2e: mock bridge learns the three backup commands + ncryptsec import; onboarding-backup.spec.ts covers the encrypted happy path (asserting get_nsec is never called), custom-passphrase validation, raw fallback, and error/retry; onboarding.spec.ts adds encrypted-import happy path including a wrong-passphrase rejection. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz> |