diff --git a/CHECKPOINT-encryption.md b/CHECKPOINT-encryption.md index 7585613..ab2b078 100644 --- a/CHECKPOINT-encryption.md +++ b/CHECKPOINT-encryption.md @@ -1,4 +1,4 @@ -# Checkpoint — Secret-key reveal after unlock (2026-08-04) +# Checkpoint — Compose preview with image attachments (2026-08-04) A stopping point you can return to if this session is closed. Everything below was verified green at the moment this file was written. @@ -6,87 +6,72 @@ verified green at the moment this file was written. ## Where things are - Project: `/home/avi/Projects/skills/nost-feed-manager` -- Git repo: `master` -- The reveal feature is **uncommitted** — all changes are in the working tree. +- Git repo: `master` @ `3e3467b` ("Add compose preview with image attachments (NIP-92 imeta)"), + on top of `17e8ace` ("Clarify the Profiles subtitle about private keys") and `8eb6685` + ("Add reveal-secret-key after unlock (CLI + GUI)"). +- The working tree is **clean** — everything from this session is committed. - `/home/avi/Projects/nostr_backend/nostr_backendmanager.md` (old-CLI docs) has been updated - to match reality; it lives outside this repo so it is not part of the commit. + to match reality; it lives outside this repo so it is not part of any commit. - `/home/avi/Projects/nostr_backend/vlog-website/` (separate, untouched). -## What was completed in this session: reveal a secret key after unlock +## What was completed: compose preview + image attachments -Building on the existing password-encrypted vault (AES-256-GCM + Argon2id), owners can now view a -profile's secret key after entering the vault password: +The Compose screen now has a **Write / Preview** tab split. The preview renders the note as it +will appear (profile avatar + npub, the text, and any images), without publishing anything. -- Backend: `profiles::reveal_secret_key` returns the key in both hex and `nsec1...` forms, gated on - an unlocked vault (`VaultLocked` when encrypted + locked). New CLI command `show-secret `, - which prompts for the password when locked (via `NFM_PASSWORD` env or hidden prompt). -- IPC: new `reveal_secret_key { npub }` method. Error replies now carry a machine-readable `code` - field (ErrorKind serialised as snake_case, e.g. `vault_locked`), so the GUI can branch without - string-matching on user-facing messages. -- GUI: a "Secret key" button on every profile card opens `ShowSecretKeyModal`, which shows hex + - nsec with copy buttons and a warning. When the vault is locked the modal asks for the password - inline, unlocks, then reveals. -- Key is only ever fetched after unlock; never stored in state before reveal. +- **Photos from hyperlinks**: pasting an image URL (`.jpg/.jpeg/.png/.gif/.webp/.avif`) anywhere in + the note shows the picture in the preview. On publish, the backend detects the same URLs and tags + the event with NIP-92 `imeta` (`url`, `m`) plus the legacy `image` tag, so both new and older + Nostr clients render the images. Detection is by extension only — nothing is downloaded to decide. +- **Attach images**: an "Attach image" button opens the native file dialog (multi-select), + uploads each file to nostr.build (anonymous `POST /api/v2/upload/files`, field `fileToUpload`), + and shows a removable thumbnail chip. The hosted URLs are appended to the note on publish. +- **Where upload lives**: `pick_image` / `upload_image` are handled by the Electron main process + (native dialog + `fetch`), not the Rust backend — they need a file dialog and a one-off HTTP + upload. The renderer still calls them through the same `window.backend.request` envelope. +- The reveal-secret-key feature from the previous commit (`8eb6685`) is unchanged and still works. -## Files changed (16 modified, 2 new) +## Commits this session (newest first) -Modified: -- `README.md` — documented the reveal feature + `show-secret` -- `src/errors.rs` — `ErrorKind` now serialises as snake_case for the IPC error code -- `src/profiles.rs` — `RevealedKey`, `reveal_secret_key`, `profile_label` + tests -- `src/ipc.rs` — `RevealSecretKey` request, `code` on error replies -- `src/main.rs` — `show-secret` CLI command -- `frontend/src/components/Icon.tsx` — new `key` icon -- `frontend/src/lib/api.ts` — `revealSecretKey`, `BackendError.code` -- `frontend/src/lib/types.ts` — `RevealedKey`, error `code` in `BackendResponse` -- `frontend/src/screens/ProfilesScreen.tsx` — "Secret key" button per profile -- `frontend/src/state/AppProvider.tsx` — `revealSecretKey` in context -- `frontend/src/test/{App,ProfilesScreen,apiMock,fakeBackend}` — updated for new UI + error codes - -New: -- `frontend/src/components/ShowSecretKeyModal.tsx` -- `frontend/src/test/ShowSecretKey.test.tsx` - -Also updated (outside repo): `/home/avi/Projects/nostr_backend/nostr_backendmanager.md`. - -## New backend API (IPC + CLI) - -IPC: `reveal_secret_key { npub }` → `{ hex, nsec }`. Error replies now include -`"code": "vault_locked"` (etc.) alongside `message`/`details`. - -CLI: `show-secret ` prints hex + nsec after unlocking. `create`, `publish`, and -`show-secret` all auto-prompt for the vault password when it is encrypted. +- `3e3467b` "Add compose preview with image attachments (NIP-92 imeta)" — 11 files, 1 new. + Backend: `src/publish.rs` (`extract_image_urls`, `image_mime_from_url`, `image_tags` + tests). + Electron: `frontend/electron/main.ts` (`pickImage`, `uploadImage`, routed from `backend:request`). + Renderer: `frontend/src/lib/media.ts` (new), `api.ts`, `types.ts`, `AppProvider.tsx`, + `ComposeScreen.tsx`, `styles.css`. Tests: `ComposeScreen.test.tsx`, `apiMock.ts`, `fakeBackend.ts` + (adds request recording + `pick_image`/`upload_image`). +- `17e8ace` "Clarify the Profiles subtitle about private keys" — `ProfilesScreen.tsx` copy. +- `8eb6685` "Add reveal-secret-key after unlock (CLI + GUI)" — previous feature, see history. ## How it was verified (all green) ``` -cargo test # 55 passed +cargo test # 60 passed cargo clippy --all-targets # clean cargo fmt --check # clean -cargo build --release # builds +cargo build --release # builds (rebuilt so the GUI runs the new backend) npm run typecheck # clean (frontend/) npm run lint # clean (pre-existing module warning only) npm run format:check # clean -npm test # 56 passed (11 files) +npm test # 60 passed (11 files) +npm run build # rebuilds the React bundle (dist/) +npm run electron:build # compiles the Electron main process ``` -Plus a manual IPC end-to-end smoke test: reveal on plaintext → OK; set-password → lock → -reveal returns `code: "vault_locked"`; unlock → reveal returns the same hex. Temp data cleaned up. - ## How to resume 1. Open the repo: `cd /home/avi/Projects/skills/nost-feed-manager` -2. Inspect the diff: `git diff` (work is still uncommitted) +2. State is committed: `git status` should be clean; `git log --oneline -5` shows the three commits. 3. To try it: - - CLI: `cargo build --release`, then - `XDG_DATA_HOME=/tmp/nfm-smoke ./target/release/nostr-manager-backend create "Alice"` and - `./target/release/nostr-manager-backend show-secret ` - - GUI: `cd frontend && npm start`, Profiles → "Secret key" on a card + - GUI: `cd frontend && npm start` — Compose → "Attach image" or paste an image URL → Preview tab. + (Note: `npm start` alone does NOT rebuild the React bundle — run `npm run build` first, or use + `npm run dev` + `NOSTR_GUI_DEV_URL=http://localhost:5173 npm start` for live reload.) + - CLI: `cargo build --release`, then `./target/release/nostr-manager-backend list` and + `./target/release/nostr-manager-backend show-secret ` (no angle brackets). 4. Re-run verification with the commands above. ## Outstanding / next steps (if you continue) -- Decide whether to **commit** the reveal work (nothing is committed yet). -- Consider a small UI hint that profiles with an unencrypted vault can be revealed with no prompt. -- Relay defaults are currently `relay.damus.io` (503 upstream) and `relay.nostr.band` (timeout); - user's local settings already point at `nos.lol` + `relay.primal.net` instead. +- Nothing uncommitted. Possible follow-ups: a real feed view (currently Home only shows the last + publication); optional NIP-98 auth for nostr.build uploads; relay defaults in code still point at + `relay.damus.io` (503 upstream) and `relay.nostr.band` (timeout) — user's local settings already + use `nos.lol` + `relay.primal.net` instead.