mirror of
https://github.com/kccleoc/seedpgp-web.git
synced 2026-03-07 09:57:50 +08:00
This commit addresses several issues related to the QR code scanner: - Fixes a build failure by defining stable handlers (`handleRestoreClose`, `handleRestoreError`) for the QRScanner component in `App.tsx` using `useCallback`. - Resolves a race condition that caused an `AbortError` when the scanner was initialized, particularly in React Strict Mode. This was fixed by ensuring all props passed to the scanner are stable. - Implements more robust error handling within the `QRScanner` component to prevent crashes when `null` or `undefined` errors are caught. - Updates documentation (`README.md`, `GEMINI.md`) to version 1.4.5.
386 lines
11 KiB
Markdown
386 lines
11 KiB
Markdown
# SeedPGP - Gemini Code Assist Project Brief
|
|
|
|
## Project Overview
|
|
|
|
**SeedPGP v1.4.5**: Client-side BIP39 mnemonic encryption webapp
|
|
**Stack**: Bun + Vite + React + TypeScript + OpenPGP.js + Tailwind CSS
|
|
**Deploy**: Cloudflare Pages (private repo: `seedpgp-web`)
|
|
**Live URL**: <https://seedpgp-web.pages.dev/>
|
|
|
|
## 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. **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/`
|
|
|
|
### Directory Structure
|
|
|
|
```BASH
|
|
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-v1.4 - Session-Key Encryption
|
|
|
|
- **Ephemeral encryption**: AES-GCM-256 session key (non-exportable) encrypts sensitive state
|
|
- **Backup flow (v1.3)**: Mnemonic auto-clears immediately after QR generation
|
|
- **Restore flow (v1.4)**: Decrypted mnemonic auto-clears after 10 seconds + manual Hide button
|
|
- **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
|
|
```
|
|
|
|
### Deployment Process
|
|
|
|
**Production:** Cloudflare Pages (auto-deploys from `main` branch)
|
|
**Live URL:** <https://seedpgp-web.pages.dev>
|
|
|
|
### Cloudflare Pages Setup
|
|
|
|
1. **Repository:** `seedpgp-web` (private repo)
|
|
2. **Build command:** `bun run build`
|
|
3. **Output directory:** `dist/`
|
|
4. **Security headers:** Automatically enforced via `public/_headers`
|
|
|
|
### Git Workflow
|
|
|
|
```bash
|
|
# Commit feature
|
|
git add src/
|
|
git commit -m "feat(v1.x): description"
|
|
|
|
# Push to main branch (including tags) triggers auto-deploy to Cloudflare
|
|
git tag v1.x.x
|
|
git push origin main --tags
|
|
|
|
# **IMPORTANT: Update README.md before tagging**
|
|
# Update the following sections in README.md:
|
|
# - Current version number in header
|
|
# - Recent Changes section with new features
|
|
# - Any new usage instructions or screenshots
|
|
# Then commit the README update:
|
|
git add README.md
|
|
git commit -m "docs: update README for 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 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.4.5
|
|
|
|
**Recent Changes (v1.4.5):**
|
|
- Fixed QR Scanner bugs related to camera initialization and race conditions.
|
|
- Improved error handling in the scanner to prevent crashes and provide better feedback.
|
|
- Stabilized component props to prevent unnecessary re-renders and fix `AbortError`.
|
|
|
|
**Known Limitations (Critical):**
|
|
1. **Browser extensions** can read DOM, memory, keystrokes - use dedicated browser
|
|
2. **Memory persistence** - JavaScript cannot force immediate memory wiping
|
|
3. **XSS attacks** if hosting server is compromised - host locally
|
|
4. **Hardware keyloggers** - physical device compromise not protected against
|
|
5. **Supply chain attacks** - compromised dependencies possible
|
|
6. **Quantum computers** - future threat to current cryptography
|
|
|
|
**Next Priorities:**
|
|
1. Enhanced BIP39 validation (full wordlist + checksum)
|
|
2. Multi-frame support for larger payloads
|
|
3. Hardware wallet integration (Trezor/Keystone)
|
|
|
|
---
|
|
|
|
## 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
|