mirror of
https://code.gri.mw/GUI/grim.git
synced 2026-07-16 19:58:54 +00:00
Build 9: QR scan, camera fixes, first-run onboarding, sweep fixes
Camera/QR (validated live with a v4l2loopback virtual camera): - decode non-MJPEG frames on Linux (raw YUYV was undecodable: eternal spinner), enumerate devices off the UI thread without unwrap, open cameras by their real device index (list position broke whenever /dev/video0 was absent), show "No camera found" after 5s - scan-to-pay: QR button in the send recipient search row and the mobile home header; in-surface camera panel feeding recipient resolution; only text payloads accepted (seeds/slatepacks refused) - receive QR was unscannable: full cells (0.5px gaps fragmented finder patterns at 4.5px cells), always ink-on-white plate (inverted codes fail many scanners), center mark 26% -> 19% (zbar chokes above); rqrr+zbar both decode the live card now; unit tests cover the exact widget geometry First-run onboarding (replaces the stock empty state only; the wallet list, add-wallet modal and GRIM creation flow stay for later wallets): - intro -> node choice (Private integrated / Instant external with URL) -> create or restore (wraps MnemonicSetup; word grid, paste, SeedQR scan) -> optional @username claim with prominent skip - fonts bind at creation context so frame one can use Geist families Sweep fixes (22 confirmed findings, the simple ones): - yellow theme: active sidebar nav was dark-on-dark (P1) - window frame ring painted with theme bg: transparent clear color rendered as a black band without a compositor (P2) - import/rotate identity inputs get visible field wells (P2) - receive buttons: verb labels + transient "Copied" feedback - review hero card fills the column; fee row copy; pay-tab stale and duplicated hints; unlock modal copy; node card subtitle truncation - build number stays current (.git/logs/HEAD rerun trigger) Backup restore: import accepts the export-time password and re-encrypts under the current wallet password; cross-device restores work. 31 lib tests green. Mainnet-validated: both flows restored real wallets; 0.1 grin sent B->A through NIP-17 over Tor with async open/close ping-pong; tx 71fbfce4f591 posted on-chain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+29
-8
@@ -540,25 +540,46 @@ impl Wallet {
|
||||
/// or an exported identity-backup JSON (which restores the username and
|
||||
/// rotation history too). The current identity is overwritten; its npub
|
||||
/// is kept in `prev_npubs` for reference. Blocking-safe (no network).
|
||||
pub fn import_nostr_identity(&self, input: String, password: String) -> Result<String, String> {
|
||||
pub fn import_nostr_identity(
|
||||
&self,
|
||||
input: String,
|
||||
password: String,
|
||||
backup_password: Option<String>,
|
||||
) -> Result<String, String> {
|
||||
let svc = self
|
||||
.nostr_service()
|
||||
.ok_or_else(|| "nostr is not running".to_string())?;
|
||||
// Prove the password against the current identity before replacing.
|
||||
// Prove THIS wallet's password against the current identity first.
|
||||
let old = svc.identity.read().clone();
|
||||
old.unlock(&password)
|
||||
.map_err(|_| "Wrong password".to_string())?;
|
||||
let input = input.trim();
|
||||
let (mut new_identity, new_keys) = if input.starts_with('{') {
|
||||
// Identity backup JSON: the ncryptsec inside stays as exported;
|
||||
// it must decrypt with the provided (= export-time) password.
|
||||
let ident: NostrIdentity =
|
||||
// Identity backup JSON: decrypt with the password it was exported
|
||||
// under (may differ on a new device), then RE-ENCRYPT under this
|
||||
// wallet's password so future unlocks use the current one.
|
||||
let backup: NostrIdentity =
|
||||
serde_json::from_str(input).map_err(|_| "Invalid identity backup".to_string())?;
|
||||
let keys = ident.unlock(&password).map_err(|_| {
|
||||
"Backup password mismatch (use the wallet password from when \
|
||||
it was exported)"
|
||||
let bpw = backup_password
|
||||
.as_deref()
|
||||
.filter(|s| !s.is_empty())
|
||||
.unwrap_or(&password);
|
||||
let keys = backup.unlock(bpw).map_err(|_| {
|
||||
"Couldn't decrypt the backup — if it was exported on another \
|
||||
device, enter that wallet's password in the backup-password \
|
||||
field"
|
||||
.to_string()
|
||||
})?;
|
||||
let mut ident = NostrIdentity::from_unlocked_keys(
|
||||
&keys,
|
||||
&password,
|
||||
backup.source,
|
||||
backup.derivation_account,
|
||||
)
|
||||
.map_err(|e| format!("re-encryption failed: {e}"))?;
|
||||
ident.nip05 = backup.nip05.clone();
|
||||
ident.anonymous = backup.anonymous;
|
||||
ident.prev_npubs = backup.prev_npubs.clone();
|
||||
(ident, keys)
|
||||
} else {
|
||||
NostrIdentity::create_imported(input, &password)
|
||||
|
||||
Reference in New Issue
Block a user