diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..b6aeba5 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,330 @@ +# 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