# SeedPGP - Gemini Code Assist Project Brief ## Project Overview **SeedPGP v1.3.0**: Client-side BIP39 mnemonic encryption webapp **Stack**: Bun + Vite + React + TypeScript + OpenPGP.js + Tailwind CSS **Deploy**: GitHub Pages (public repo: `seedpgp-web-app`, private source: `seedpgp-web`) **Live URL**: https://kccleoc.github.io/seedpgp-web-app/ ## Core Constraints 1. **Security-first**: Never persist secrets (mnemonic/passphrase/private keys) to localStorage/sessionStorage/IndexedDB 2. **Small PRs**: Max 1-5 files per feature; propose plan before coding 3. **Client-side only**: No backend; all crypto runs in browser (Web Crypto API + OpenPGP.js) 4. **GitHub Pages deploy**: Base path `/seedpgp-web-app/` configured in vite.config.ts 5. **Honest security claims**: Don't overclaim what client-side JS can guarantee ## Non-Negotiables - Small diffs only: one feature slice per PR (1-5 files if possible) - No big code dumps; propose plan first, then implement - Never persist secrets to browser storage - Prefer "explain what you found in the repo" over guessing - TypeScript strict mode; no `any` types without justification --- ## Architecture Map ### Entry Points - `src/main.tsx` → `src/App.tsx` (main application) - Build output: `dist/` (separate git repo for GitHub Pages deployment) ### Directory Structure ``` src/ ├── components/ # React UI components │ ├── PgpKeyInput.tsx │ ├── QrDisplay.tsx │ ├── QrScanner.tsx │ ├── ReadOnly.tsx │ ├── StorageIndicator.tsx │ ├── SecurityWarnings.tsx │ └── ClipboardTracker.tsx ├── lib/ # Core logic & crypto utilities │ ├── seedpgp.ts # Main encrypt/decrypt functions │ ├── sessionCrypto.ts # Ephemeral AES-GCM session keys │ ├── types.ts # TypeScript interfaces │ └── qr.ts # QR code utilities ├── App.tsx # Main app component └── main.tsx # React entry point ``` ### Key Modules #### `src/lib/seedpgp.ts` Core encryption/decryption: - `encryptToSeedPgp()` - Encrypts mnemonic with PGP public key + optional password - `decryptFromSeedPgp()` - Decrypts with PGP private key + optional password - Uses OpenPGP.js for PGP operations - Output format: `SEEDPGP1:version:base64data:fingerprint` #### `src/lib/sessionCrypto.ts` (v1.3.0+) Ephemeral session-key encryption: - `getSessionKey()` - Generates/returns non-exportable AES-GCM-256 key (idempotent) - `encryptJsonToBlob(obj)` - Encrypts to `{v, alg, iv_b64, ct_b64}` - `decryptBlobToJson(blob)` - Decrypts back to original object - `destroySessionKey()` - Drops key reference for garbage collection - Test: `await window.runSessionCryptoTest()` (DEV only) #### `src/lib/types.ts` Core interfaces: - `SeedPgpPlaintext` - Decrypted mnemonic data structure - `SeedPgpCiphertext` - Encrypted payload structure - `EncryptedBlob` - Session-key encrypted cache format --- ## Key Features ### v1.0 - Core Functionality - **Backup**: Encrypt mnemonic with PGP public key + optional password → QR display - **Restore**: Scan/paste QR → decrypt with private key → show mnemonic - **PGP support**: Import public/private keys (.asc files or paste) ### v1.1 - QR Features - **QR Display**: Generate QR codes from encrypted data - **QR Scanner**: Camera + file upload (uses html5-qrcode library) ### v1.2 - Security Monitoring - **Storage Indicator**: Real-time display of localStorage/sessionStorage contents - **Security Warnings**: Context-aware alerts about browser memory limitations - **Clipboard Tracker**: Monitor clipboard operations on sensitive fields - **Read-only Mode**: Toggle to clear state + show CSP/build info ### v1.3 - Session-Key Encryption (Current) - **Ephemeral encryption**: AES-GCM-256 session key (non-exportable) encrypts sensitive state - **Auto-clear**: Plaintext mnemonic cleared from UI immediately after QR generation - **Encrypted cache**: Only ciphertext stored in React state; key lives in memory only - **Lock/Clear**: Manual cleanup destroys session key + clears all state - **Lifecycle**: Session key auto-destroyed on page close/refresh --- ## Development Workflow ### Commands ```bash bun install # Install dependencies bun run dev # Dev server (localhost:5173) bun run build # Build to dist/ bun run typecheck # TypeScript validation (tsc --noEmit) bun run preview # Preview production build ./scripts/deploy.sh v1.x.x # Build + push to public repo ``` ### Deployment Process 1. **Private repo** (`seedpgp-web`): Source code, development 2. **Public repo** (`seedpgp-web-app`): Built files for GitHub Pages 3. **Deploy script** (`scripts/deploy.sh`): Builds + copies to dist/ + pushes to public repo ### Git Workflow ```bash # Commit feature git add src/ git commit -m "feat(v1.x): description" # Tag version git tag v1.x.x git push origin main --tags # Deploy to GitHub Pages ./scripts/deploy.sh v1.x.x ``` --- ## Required Workflow for AI Agents ### 1. Study First Before implementing any feature: - Read relevant files - Explain current architecture + entry points - List files that will be touched - Identify potential conflicts or dependencies ### 2. Plan - Propose smallest vertical slice (1-5 files) - Show API signatures or interface changes first - Get approval before generating full implementation ### 3. Implement - Generate code with TypeScript strict mode - Include JSDoc comments for public APIs - Show unified diffs, not full file rewrites (when possible) - Keep changes under 50-100 lines per file when feasible ### 4. Verify - Run `bun run typecheck` - no errors - Run `bun run build` - successful dist/ output - Provide manual test steps for browser verification - Show build output / console logs / DevTools screenshots --- ## Common Patterns ### State Management - React `useState` + `useEffect` (no Redux/Zustand/external store) - Ephemeral state only; avoid persistent storage for secrets ### Styling - Tailwind utility classes (configured in `tailwind.config.js`) - Responsive design: mobile-first with `md:` breakpoints - Dark theme primary: slate-900 background, blue-400 accents ### Icons - `lucide-react` library - Common: Shield, QrCode, Lock, Eye, AlertCircle ### Crypto Operations - **PGP**: OpenPGP.js (`openpgp` package) - **Session keys**: Web Crypto API (`crypto.subtle`) - **Key generation**: `crypto.subtle.generateKey()` with `extractable: false` - **Encryption**: AES-GCM with random 12-byte IV per operation ### Type Safety - Strict TypeScript (`tsconfig.json`: `strict: true`) - Check `src/lib/types.ts` for core interfaces - Avoid `any`; use `unknown` + type guards when necessary --- ## Security Architecture ### Threat Model (Honest) **What we protect against:** - Accidental persistence to localStorage/sessionStorage - Plaintext secrets lingering in React state after use - Clipboard history exposure (with warnings) **What we DON'T protect against (and must not claim to):** - Active XSS or malicious browser extensions - Memory dumps or browser crash reports - JavaScript garbage collection timing (non-deterministic) ### Memory Handling - **Session keys**: Non-exportable CryptoKey objects (Web Crypto API) - **Plaintext clearing**: Set to empty string + drop references (but GC timing is non-deterministic) - **No guarantees**: Cannot force immediate memory wiping in JavaScript ### Storage Policy - **NEVER write to**: localStorage, sessionStorage, IndexedDB, cookies - **Exception**: Non-sensitive UI state only (theme preferences, etc.) - NOT IMPLEMENTED YET - **Verification**: StorageIndicator component monitors all storage APIs --- ## What NOT to Do ### Code Generation - Don't generate full file rewrites unless necessary - Don't add dependencies without discussing bundle size impact - Don't use `any` types without explicit justification - Don't skip TypeScript strict mode checks ### Security Claims - Don't claim "RAM is wiped" (JavaScript can't force GC) - Don't claim "offline mode" without real CSP headers (GitHub Pages can't set custom headers) - Don't promise protection against active browser compromise (XSS/extensions) ### Storage - Don't write secrets to storage without explicit approval - Don't cache decrypted data beyond immediate use - Don't assume browser storage is secure --- ## Testing & Verification ### Manual Test Checklist (Before Marking Feature Complete) 1. ✅ `bun run typecheck` passes (no TypeScript errors) 2. ✅ `bun run build` succeeds (dist/ generated) 3. ✅ Browser test: Feature works as described 4. ✅ DevTools Console: No runtime errors 5. ✅ DevTools Application tab: No plaintext secrets in storage 6. ✅ DevTools Network tab: No unexpected network calls (if Read-only Mode) ### Session-Key Encryption Test (v1.3+) ```javascript // In browser DevTools console: await window.runSessionCryptoTest() // Expected: ✅ Success: Data integrity verified. ``` --- ## Current Version: v1.3.0 ### Recent Changes (2026-01-29) - ✅ Added `src/lib/sessionCrypto.ts` with ephemeral AES-GCM session keys - ✅ Integrated into Backup flow: plaintext mnemonic auto-cleared after QR generation - ✅ Added Lock/Clear button to destroy session key and clear all state - ✅ Added cleanup on component unmount ### Known Limitations - GitHub Pages cannot set custom CSP headers (need Cloudflare Pages for enforcement) - Read-only Mode is UI-level only (not browser-enforced) - Session-key encryption doesn't protect against active XSS/extensions ### Next Priorities (Suggested) 1. Extend session-key encryption to Restore flow 2. Migrate to Cloudflare Pages for real CSP header enforcement 3. Add "Encrypted in memory" badge when encryptedMnemonicCache exists 4. Document reproducible builds (git hash verification) --- ## Quick Reference ### File a Bug/Feature 1. Describe expected vs actual behavior 2. Include browser console errors (if any) 3. Specify which flow (Backup/Restore/QR Scanner) ### Roll Over to Next Session Always provide: - Current version number - What was implemented this session - Files modified - What still needs work - Any gotchas or edge cases discovered --- ## Example Prompts for Gemini ### Exploration ``` Read GEMINI.md, then explain: 1. Where is the mnemonic textarea and how is its value managed? 2. List all places localStorage/sessionStorage are used 3. Show data flow from "Backup" button to QR display ``` ### Feature Request ``` Task: [Feature description] Requirements: 1. [Specific requirement] 2. [Another requirement] Files to touch: - [List files] Plan first: show proposed API/changes before generating code. ``` ### Verification ``` Audit the codebase to verify [feature] is fully implemented. Check: 1. [Requirement 1] 2. [Requirement 2] Output: ✅ or ❌ for each item + suggest fixes for failures. ``` --- **Last Updated**: 2026-01-29 **Maintained by**: @kccleoc **AI Agent**: Optimized for Gemini Code Assist