From 937fcc67cb685c1edc431d5140095a9aed71fe71 Mon Sep 17 00:00:00 2001 From: Avi Date: Sat, 12 Sep 2026 17:56:08 -0500 Subject: [PATCH] =?UTF-8?q?checkpoint:=20sync=20to=2022d7c01=20=E2=80=94?= =?UTF-8?q?=20QR=20pairing,=20identity=20adoption,=20always-allow=20grants?= =?UTF-8?q?,=20hygiene=20(2026-09-12)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHECKPOINT-encryption.md | 85 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/CHECKPOINT-encryption.md b/CHECKPOINT-encryption.md index fefc63d..16dc98b 100644 --- a/CHECKPOINT-encryption.md +++ b/CHECKPOINT-encryption.md @@ -1,3 +1,88 @@ +# Checkpoint — QR pairing, identity adoption, always-allow grants + hygiene (2026-09-12) + +## Where things are +- Project: `/home/avi/Projects/Keynctr` +- Branch: `master` @ **`22d7c01`** ("chore(hygiene): ignore editor artifacts; + prettier SignerScreen"). Previous feature HEAD: `81b082f`. +- Working tree: clean for tracked files. Untracked intentionally NOT + committed: `COSMIC_THEME.md`, `KeynectrAppIconPossibility02.jpeg`, + `deferred/` (stays deferred). `.directory`, `.opencode/`, `.impeccable/` + are now gitignored. Dead stub `src/signer/nip46_external.rs` **deleted** + (was untracked, never declared in `signer/mod.rs`, superseded by + `nip46_client.rs`). +- Verification (all green at `22d7c01`): `cargo test` **201 unit + 2 e2e + passed / 0 failed**, `cargo clippy --all-targets` 0 warnings, + `cargo fmt --check` clean, `cargo build --release` green. Frontend: + `npm test` **116 passed (16 files)**, `npm run typecheck` clean, + `npm run lint` clean, `npm run format:check` clean, + `npm run electron:build` and `npm run build` green. + +## What was completed since the last checkpoint (7 feature commits + hygiene) +- **QR pairing (`38499d4`)**: Keynctr is the NIP-46 *client*, Amber scans. + Signer screen mints a `nostrconnect://` pairing token (ephemeral key + + secret), renders it as a QR ("Show QR"), copy-link fallback, cancel. + Backend listens for the signer's connect request, echoes the secret + (anti-spoofing), persists the connection, adopts identity via + `get_public_key`. e2e covers scan -> secret echo -> identity -> sign -> + vault persistence with a fake QR scanner. +- **Electron allowlist (`c5004eb`)**: `nip46_pair_start` added to the + main-process renderer allowlist (was rejected with "not permitted"). +- **Lazy signer handle (`dc58f38`)**: all `nip46_*` IPC handlers ensure the + client signer handle exists (fresh backend no longer answers "not + initialized" until the mode is re-saved). +- **Pairing diagnostics (`9cfab4b`)**: pairing start + session failures + logged to stderr (captured by Electron). +- **Real identity adoption (`3d5302f`)**: paired profiles get the signer's + kind-0 display name/picture/nip05 (best-effort, 3s-capped) instead of a + generic pairing label. +- **Instant Connected (`286bbca`)**: session flips to Connected as soon as + identity is verified/persisted; metadata lands in a background task that + never overrides a user-chosen label (fixes "Amber said yes but nothing + changed"). +- **Always-allow grants (`81b082f`)**: standing per-(peer pubkey, method) + permission for external signer requests. Approvals gained an "Always + allow" option; grants listed with Revoke on the Signer screen; persist in + the encrypted vault (`src/vault.rs` grant storage). +- **Hygiene (`22d7c01`)**: gitignore editor artifacts, prettier-fix + `SignerScreen.tsx` (format:check had been failing since `81b082f`), + delete dead `nip46_external.rs` stub. + +## Commits added (newest first) +- `22d7c01` chore(hygiene): ignore editor artifacts; prettier SignerScreen +- `81b082f` feat(signer): always-allow grants for external signer requests +- `286bbca` fix(signer): connect immediately after identity; fetch kind-0 + metadata in background +- `3d5302f` feat(signer): adopt real display name/picture for paired NIP-46 + identities +- `9cfab4b` chore(signer): log pairing start and session failures to stderr +- `dc58f38` fix(ipc): lazily initialize the NIP-46 client signer handle +- `c5004eb` fix(electron): allow nip46_pair_start through the renderer method + allowlist +- `38499d4` feat(signer): QR pairing — client-initiated nostrconnect:// flow + for Amber + +## How to reproduce / exercise +- Dev loop (unchanged): `npx vite --port 5173` in `frontend/` FIRST, then + `NOSTR_GUI_DEV_URL=http://localhost:5173 KEYNCTR_ENABLE_GPU=1 npx electron .`. +- E2E: `cargo test --test nip46_e2e` (no network). +- GUI: Signer mode screen -> "Show QR" -> scan in Amber -> approve -> + identity + display name appear; sign a note; approval dialog offers + "Always allow"; revoke on the Signer screen. + +## Outstanding / next steps +1. **On-device Amber verification** of everything above (QR pair + pasted + bunker://, identity/name/pic, sign + publish, always-allow grant, revoke, + re-prompt). Top item — never run against real Amber since `f917e5e`. +2. `publish_profile_metadata` (kind 0) still signs locally — reroute through + `Signing` for external profiles (P2). +3. Step 5 (KDF upgrade m=64MiB/t=3 + vault header versioning, gate + deprecated `RevealSecretKey`), Step 6 (undo preserves `ProfileSummary` -> + secret lost), Step 7 (Keynctr rename pass incl. `homepage` URL). +4. `wip/pairing-relay-widening` branch parked — needs an env seam before it + can merge (breaks e2e isolation as-is). + +--- + # Checkpoint — NIP-46 e2e test + bunker:// frontend support (2026-09-11) ## Where things are