Files
seedpgp-web/GEMINI.md

11 KiB

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.tsxsrc/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-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

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

# 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+)

// In browser DevTools console:
await window.runSessionCryptoTest()
// Expected: ✅ Success: Data integrity verified.

Current Version: v1.4.0

Recent Changes (2026-01-30)

  • Extended session-key encryption to Restore flow
  • Added 10-second auto-clear timer for restored mnemonic
  • Added Hide button for manual clear
  • Removed debug console logs from sessionCrypto.ts

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