mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-30 07:37:38 +00:00
Reworks the Desktop new-account key backup after testing surfaced that the original card never rendered and the settings entry sat on dead code. - Guided 3-step "Save your keys" onboarding (NewKeyOnboardingScreen), full window + scrollable so it never clips. Used by BOTH the cold-start login and the in-app "+ Add Account" generate paths. Retires NewKeyWarningCard. - Split key generation from activation (AccountManager.buildNewAccount + activateAccount + begin/finish/cancelNewAccountOnboarding). generateNewAccount previously flipped account state immediately, tearing down the screen before any backup UI could show — the root cause of "no save-your-keys prompt". - Move BackupKeysCard into the reachable Settings screen (RelaySettingsScreen); the old ProfileScreen host had no call sites. - Fix the password show/hide eye (was a non-clickable Icon) in both the onboarding and settings encrypted-copy sections. - Run NIP-49 encryption off the UI thread so the "Copy encrypted" button stays responsive and reliably flips to "Copied!"; match the plain copy button style. - Add EncryptedKeyBackupTest: nsec -> hex -> Nip49 encrypt -> decrypt round-trip (and wrong-password fails). - Plans + manual testing sheet under desktopApp/plans/. Known follow-up: Desktop loginWithKey does not yet import ncryptsec1, so encrypted backups can't be restored on Desktop yet (Android already handles it). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
140 lines
7.5 KiB
Markdown
140 lines
7.5 KiB
Markdown
# Key Backup & nsec Exposure — Manual Testing Sheet
|
|
|
|
Branch: `feat/key-backup-nsec-exposure` (worktree `.claude/worktrees/feat-key-backup`)
|
|
Date: 2026-08-11
|
|
Build: Desktop `./gradlew :desktopApp:run` · Android `./gradlew :amethyst:installPlayDebug`
|
|
|
|
Legend: ✅ pass · ❌ fail (note what happened) · ⏭️ skipped
|
|
|
|
Design invariants to keep verifying throughout:
|
|
- **npub** = shareable → plain, copyable, QR OK.
|
|
- **nsec** = unrecoverable password → masked by default, gated reveal + gated copy,
|
|
encrypted (NIP-49) option, **NEVER shown as a QR code**.
|
|
|
|
---
|
|
|
|
## A. Desktop — New-account warning card (`NewKeyWarningCard`)
|
|
|
|
Precondition: launch Desktop, log out / add account, choose **Generate New Account**.
|
|
|
|
- [ ] A1. Card shows title + strengthened warning wording ("can never be reset/recovered").
|
|
- [ ] A2. **npub** shown; its **Copy** button copies → paste elsewhere matches the npub.
|
|
- [ ] A3. **nsec** shown; its **Copy** button copies → paste matches the nsec (`nsec1…`).
|
|
- [ ] A4. **Copy encrypted (recommended)**: type a password → button copies an `ncryptsec1…`
|
|
string (paste to verify prefix). Empty password → button disabled / no-op.
|
|
- [ ] A5. **"I have saved my keys"** checkbox: Continue is disabled until checked (soft gate);
|
|
checking it enables Continue.
|
|
- [ ] A6. Continue proceeds into the app with the generated account logged in.
|
|
- [ ] A7. **No QR code** anywhere on this card.
|
|
|
|
## B. Desktop — Backup Keys card in Settings/Profile (`BackupKeysCard`)
|
|
|
|
Precondition: logged in with an **internal-key** account (has nsec). Open Settings → Profile.
|
|
|
|
- [ ] B1. "Backup Keys" card is visible in the profile/settings screen (discoverable — the
|
|
original complaint was "couldn't find it in settings").
|
|
- [ ] B2. **npub** row: monospace value + **Copy** works; **Show QR** renders a QR; **Hide QR** hides it.
|
|
- [ ] B3. QR scans/points to the npub (optional: scan with a phone).
|
|
- [ ] B4. **nsec** section: warning banner shown; key is **masked** ("hidden" placeholder),
|
|
not revealed on load.
|
|
|
|
### B-lock. Reveal gating via PrivacyLock
|
|
|
|
Case 1 — PrivacyLock **NOT** set up (no master password configured):
|
|
- [ ] B5. Click **Reveal secret key** → nsec reveals immediately (baseline: masked + explicit
|
|
toggle, no password). Acceptable per design.
|
|
|
|
Case 2 — PrivacyLock **enabled** (set a master password in Messages/Wallet privacy-lock settings first):
|
|
- [ ] B6. Click **Reveal secret key** → a **modal Dialog** appears asking to unlock (does NOT
|
|
take over / expand the whole settings pane).
|
|
- [ ] B7. Wrong password → stays locked; **Cancel/dismiss** the dialog → nsec stays masked.
|
|
- [ ] B8. Correct password → dialog closes, nsec reveals.
|
|
|
|
### B-copy. Revealed secret-key actions
|
|
- [ ] B9. **Copy secret key** (plaintext) copies the `nsec1…`; a red plaintext warning is visible.
|
|
- [ ] B10. **Clipboard auto-clear**: after copying plaintext nsec, wait ~60s without copying
|
|
anything else → paste → clipboard is **empty**. If you copy something else within 60s,
|
|
that value is **preserved** (auto-clear only wipes if clipboard still holds the nsec).
|
|
- [ ] B11. **Copy encrypted (recommended)**: enter password → copies `ncryptsec1…`; toggle the
|
|
password visibility eye works; wrong/blank handled (button disabled while blank; failure
|
|
shows the error supporting text). Encrypted copy is **not** auto-cleared (it's password-safe).
|
|
- [ ] B12. **Hide** returns the section to masked state; leaving the screen and returning re-hides.
|
|
- [ ] B13. **No QR** is ever offered for the nsec.
|
|
|
|
## C. Desktop — External-signer / read-only account
|
|
|
|
Precondition: log in with an **external signer / bunker (NIP-46)** or a **read-only npub**.
|
|
|
|
- [ ] C1. Backup Keys card shows the npub section normally.
|
|
- [ ] C2. nsec section is replaced by the "This account uses an external signer — no secret key
|
|
is stored here" note. No reveal/copy controls, no masked field.
|
|
|
|
---
|
|
|
|
## D. Android — Post-signup backup nudge
|
|
|
|
Precondition: fresh install or logged out. **Create a NEW account** (generate).
|
|
|
|
- [ ] D1. After signup lands on the home feed, a dismissible **"Back up your keys"** nudge/banner
|
|
appears (top of feed, above the algo-feed status banner; does not block navigation).
|
|
- [ ] D2. **Back up now** → opens the existing Account Backup screen; returning home, the nudge
|
|
is gone (flag flipped).
|
|
- [ ] D3. Re-create another new account → **I saved them** (or the X) dismisses the nudge.
|
|
- [ ] D4. Kill & relaunch the app → the dismissed nudge does **not** reappear for that account
|
|
(per-account `hasBackedUpKeys` persisted in encrypted prefs).
|
|
|
|
## E. Android — Which accounts get nudged
|
|
|
|
- [ ] E1. Log in with an **existing nsec** (paste key) → **no** nudge (treated as already backed up).
|
|
- [ ] E2. Log in with **bunker / external signer** → **no** nudge.
|
|
- [ ] E3. Read-only **npub** login → **no** nudge (no private key).
|
|
- [ ] E4. Multiple accounts: a freshly-generated account is nudged; switching to a
|
|
pre-existing account shows no nudge (flag is per-account).
|
|
|
|
## F. Android — Backup screen hardening (`AccountBackupScreen`)
|
|
|
|
- [ ] F1. **FLAG_SECURE**: on the Account Backup screen, attempt a screenshot → blocked by the OS
|
|
("can't take screenshots due to security policy") and the app-switcher/recents preview shows
|
|
a blank/black thumbnail for this screen.
|
|
- [ ] F2. Navigating away from the backup screen → screenshots work again elsewhere (flag cleared,
|
|
no leak to other screens).
|
|
- [ ] F3. Existing **biometric gate** on copy/QR still prompts and works.
|
|
- [ ] F4. **Copy secret key** (plaintext) → toast shown; **clipboard auto-clear** after ~60s
|
|
empties the clipboard if unchanged; a value copied in the meantime is preserved.
|
|
- [ ] F5. **Encrypted (ncryptsec1) copy** and the **plaintext / encrypted QR codes** still work
|
|
as before (regression check — these are pre-existing).
|
|
|
|
---
|
|
|
|
## G. Cross-cutting — NIP-49 round trip (correctness)
|
|
|
|
- [ ] G1. Desktop: encrypted-copy the nsec with password `P` → you have an `ncryptsec1…`.
|
|
- [ ] G2. Log in (Desktop or Android) using that `ncryptsec1…` + password `P` → succeeds and
|
|
resolves to the **same** account (same npub). Confirms the nsec→hex decode + Nip49 encrypt
|
|
are correct end-to-end.
|
|
- [ ] G3. Wrong password on login with the ncryptsec → rejected (no crash).
|
|
|
|
## H. Regression / smoke
|
|
|
|
- [ ] H1. Desktop **Developer Settings** key rows still copy (shared `copyToClipboard` refactor
|
|
didn't break them).
|
|
- [ ] H2. Privacy lock still gates **Messages** and **Wallet** as before (adding `KeyBackup`
|
|
scope didn't disturb existing scopes).
|
|
- [ ] H3. Normal posting on Android still works (paste-guard was **deferred** — a note containing
|
|
an `nsec1…` currently posts without a warning; confirm posting itself is unaffected).
|
|
|
|
---
|
|
|
|
## Known limitations / deferred (expected, not bugs)
|
|
- **Compose paste-guard** (warn before posting a note that contains an `nsec1…`) is **deferred** —
|
|
the send path is reimplemented across ~17 `*PostViewModel`s with no shared choke point.
|
|
- **Desktop reveal without PrivacyLock** is protected only by masked + explicit toggle (no
|
|
password), by design — the master-password gate only engages if the user set one up.
|
|
- **Clipboard auto-clear** is best-effort (equality-guarded, 60s); the OS may surface its own
|
|
sensitive-clipboard UI on Android 13+.
|
|
|
|
## Sign-off
|
|
- Tester: __________ Date: __________
|
|
- Desktop OS: __________ Android version/device: __________
|
|
- Overall: ☐ ready for PR ☐ needs fixes (list): __________
|