Commit graph

11 commits

Author SHA1 Message Date
Avi
7891ccce1a docs: Step 7 rename/hygiene pass
- package.json homepage: github.com/avi/Keynctr -> git.atitlan.io/avi/Keynctr
- README: title 'Nostr Feed Manager' -> 'Keynctr', resolve all
  [YOUR_FORGEJO_INSTANCE_URL]/<OWNER>/<REPO> placeholders with the real
  Forgejo URL, fix clone dir and packaged-binary name (nost-feed-manager
  -> keynectr), data dir default ~/.local/share/keynectr, refresh test
  counts (cargo 225+6 e2e, npm 139/19 files) and project layout
  (audit/bunker/feed/updates modules, signer/ dir, Feed+SignerMode screens)
- PRODUCT.md: data dir corrected with migration note
2026-09-30 11:57:49 -05:00
Avi
38499d4506 feat(signer): QR pairing — client-initiated nostrconnect:// flow for Amber
Keynctr is the NIP-46 client; Amber is the scanner. Amber hands out no
link — it scans one — so the signer screen now mints a pairing token:

- start_pairing(): ephemeral key + secret, nostrconnect:// token via
  NostrConnectUri::client_with_secret, status().pairing_uri for the GUI
- run_pairing_task(): listens for the signer's connect request, echoes
  the secret (anti-spoofing), persists the connection row + secret,
  then adopts identity via get_public_key and hands to the demux loop
- pairing subscription is closed at handoff so the demux loop owns the
  conversation (relay could otherwise deliver signer replies under the
  stale pairing sub id where nobody routes them)
- IPC: nip46_pair_start; status carries pairing_uri
- SignerModeScreen: 'Show QR' button, QR render (qrcode) of the token,
  copy-link fallback, cancel; paste-link flow unchanged
- e2e: fake QR scanner consumes the real pairing token end-to-end
  (scan -> secret echo -> identity -> sign -> vault persistence)
2026-09-12 04:47:20 -05:00
Avi
2c61830390 feat: add per-profile signer modes with persisted NIP-46 connections
Introduce three coexisting signing modes:
- Embedded (INTERNAL): vault-held nsec, decrypted in Rust, signs locally.
- Nip46Client (EXTERNAL): Keynctr is the NIP-46 CLIENT; the key never
  touches this machine.
- Nip46Bunker: legacy inverted mode (Keynctr as signer serving others).

Data model:
- StoredProfile gains signer_mode (serde-defaults to Embedded for legacy
  profiles); SignerMode moves from app.rs to vault.rs to break a circular
  dependency; app.rs re-exports it.
- Vault gains nip46_connections (profile-owned) and bumps VAULT_VERSION to
  3; migrate_vault_signer_modes() normalises on load (idempotent).
- Nip46Connection gains profile_npub ownership, parsed permissions,
  expires_at, and revoked_at.

Signer abstraction (src/signer):
- Signer trait gains pubkey_for() identity validation, a Signing enum
  (Local vs External) that re-verifies the returned event, and a permission
  surface (permissions/can_*/is_connection_valid) with safe defaults.
- permissions.rs: NIP-46 per-connection permission model (parse, validate,
  deny-by-default, no-broadening checks) with 52 unit tests.
- Nip46ClientSigner parses perms from nostrconnect:// URIs, enforces
  permissions on every gated request, persists/revokes connections in the
  vault, and audits permission denials via the app's audit log.
- App gains audit_log and a nip46_bunker_signer handle; default mode is
  Nip46Client (most secure).

Frontend: SignerModeScreen redesigned for the three modes with a
nostr-tools-based SignerManager client, new IPC allowlist entries, and
signer-mode styling.

Verified: cargo test --release 186 passed; clippy/fmt clean; frontend tsc
clean, vitest 110 passed.
2026-09-03 09:47:19 -05:00
Avi
0207636a7a feat: expose profile import over IPC
Wire the existing profiles::import_profile through the JSON-lines IPC
protocol so the GUI can add an existing account: ImportProfile request
and handler in src/ipc.rs, import_profile added to the Electron method
allowlist, api/AppProvider importProfile, and the Add existing account
buttons in ProfilesScreen.

Also add the active signing identity card on Home and fix the HomeScreen
tests whose text queries now match the identity card as well as the
profile row.
2026-09-01 10:41:28 -05:00
Avi
a3b509cb09 feat: rename app to Keynctr 2026-08-31 13:13:47 -05:00
Avi
cbbe779faa Desktop entry + Wayland app id so the taskbar shows the app icon 2026-08-24 11:46:48 -05:00
Avi
8a644afd80 App icon: hummingbird-key mark for window and packaged Linux builds 2026-08-24 11:33:45 -05:00
Avi
c11ab9f735 Security: major dependency upgrades clearing all npm advisories; show per-advisory fix paths 2026-08-24 11:00:18 -05:00
Avi
24b34b6f93 Remove duplicate productName entries from package.json 2026-08-23 11:06:32 -05:00
Avi
7c6a085bf1 Rename the app to Keynectr
- Crate/binary: nostr-manager-backend -> keynectr
- Data directory: nost-feed-manager -> keynectr, migrated automatically
  on first data_dir() call (existing vaults, settings and backups move)
- Electron extraResources/spawn path, executableName, productName,
  window title and CLI usage strings updated to match
- Deliberately unchanged: crypto.rs KDF verifier string, so previously
  encrypted vault backups remain decryptable

Verified live: existing vault with two profiles migrated to
~/.local/share/keynectr and loads correctly.
2026-08-23 10:22:25 -05:00
Avi
7e3bac345c Add Nostr Feed Manager: Rust backend with Electron + React GUI
- Rust library (nostr-manager-backend) with CLI and JSON-lines IPC serve mode:
  profiles, publishing with per-relay reports, relays, settings, vault storage
  and legacy-vault migration
- Electron + React + TypeScript desktop GUI using the same backend over stdio IPC
- Vitest suite with a fake backend speaking the real protocol
- electron-builder linux packaging; README with build and usage instructions
2026-08-03 16:05:59 -05:00