mirror of
https://github.com/kccleoc/seedpgp-web.git
synced 2026-03-07 09:57:50 +08:00
- Update version to v1.4.4 - Add explicit threat model documentation - Document known limitations prominently - Include air-gapped usage recommendations - Polish all documentation for clarity and examples - Update README, DEVELOPMENT.md, GEMINI.md, RECOVERY_PLAYBOOK.md
292 lines
7.2 KiB
Markdown
292 lines
7.2 KiB
Markdown
Here's your `DEVELOPMENT.md`:
|
|
|
|
```markdown
|
|
# Development Guide - SeedPGP v1.4.4
|
|
|
|
## Architecture Quick Reference
|
|
|
|
### Core Types
|
|
|
|
```typescript
|
|
// src/lib/types.ts
|
|
interface SeedPgpPlaintext {
|
|
v: number; // Version (always 1)
|
|
t: string; // Type ("bip39")
|
|
w: string; // Mnemonic words (normalized)
|
|
l: string; // Language ("en")
|
|
pp: number; // BIP39 passphrase used? (0 or 1)
|
|
fpr?: string[]; // Optional recipient fingerprints
|
|
}
|
|
|
|
interface ParsedSeedPgpFrame {
|
|
kind: "single"; // Frame type
|
|
crc16: string; // 4-digit hex checksum
|
|
b45: string; // Base45 payload
|
|
}
|
|
```
|
|
|
|
### Frame Format
|
|
|
|
```
|
|
SEEDPGP1:0:ABCD:BASE45DATA
|
|
|
|
SEEDPGP1 - Protocol identifier + version
|
|
0 - Frame number (single frame)
|
|
ABCD - CRC16-CCITT-FALSE checksum (4 hex digits)
|
|
BASE45 - Base45-encoded PGP binary message
|
|
```
|
|
|
|
### Key Functions
|
|
|
|
#### Encryption Flow
|
|
```typescript
|
|
buildPlaintext(mnemonic, bip39PassphraseUsed, recipientFingerprints?)
|
|
→ SeedPgpPlaintext
|
|
|
|
encryptToSeedPgp({ plaintext, publicKeyArmored?, messagePassword? })
|
|
→ { framed: string, pgpBytes: Uint8Array, recipientFingerprint?: string }
|
|
```
|
|
|
|
#### Decryption Flow
|
|
```typescript
|
|
decryptSeedPgp({ frameText, privateKeyArmored?, privateKeyPassphrase?, messagePassword? })
|
|
→ SeedPgpPlaintext
|
|
|
|
frameDecodeToPgpBytes(frameText)
|
|
→ Uint8Array (with CRC16 validation)
|
|
```
|
|
|
|
#### Encoding/Decoding
|
|
```typescript
|
|
frameEncode(pgpBinary: Uint8Array) → "SEEDPGP1:0:CRC16:BASE45"
|
|
frameParse(text: string) → ParsedSeedPgpFrame
|
|
frameDecodeToPgpBytes(frameText: string) → Uint8Array
|
|
```
|
|
|
|
### Dependencies
|
|
|
|
```json
|
|
{
|
|
"openpgp": "^6.3.0", // PGP encryption (curve25519Legacy)
|
|
"bun-types": "latest", // Bun runtime types
|
|
"react": "^18.x", // UI framework
|
|
"vite": "^5.x" // Build tool
|
|
}
|
|
```
|
|
|
|
### OpenPGP.js v6 Quirks
|
|
|
|
⚠️ **Important compatibility notes:**
|
|
|
|
1. **Empty password array bug**: Never pass `passwords: []` to `decrypt()`. Only include if non-empty:
|
|
```typescript
|
|
if (msgPw) {
|
|
decryptOptions.passwords = [msgPw];
|
|
}
|
|
```
|
|
|
|
2. **Curve naming**: Use `curve25519Legacy` (not `curve25519`) in `generateKey()`
|
|
|
|
3. **Key validation**: Always call `getEncryptionKey()` to verify public key has usable subkeys
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
seedpgp-web/
|
|
├── src/
|
|
│ ├── lib/
|
|
│ │ ├── seedpgp.ts # Core encrypt/decrypt logic
|
|
│ │ ├── seedpgp.test.ts # Test vectors (15 tests)
|
|
│ │ ├── base45.ts # Base45 encoder/decoder
|
|
│ │ ├── crc16.ts # CRC16-CCITT-FALSE
|
|
│ │ └── types.ts # TypeScript interfaces
|
|
│ ├── App.tsx # React UI entry
|
|
│ └── main.tsx # Vite bootstrap
|
|
├── package.json
|
|
├── tsconfig.json
|
|
├── vite.config.ts
|
|
├── README.md
|
|
└── DEVELOPMENT.md # This file
|
|
```
|
|
|
|
## Development Workflow
|
|
|
|
### Running Tests
|
|
|
|
```bash
|
|
# All tests
|
|
bun test
|
|
|
|
# Watch mode
|
|
bun test --watch
|
|
|
|
# Verbose output
|
|
bun test --verbose
|
|
```
|
|
|
|
### Development Server
|
|
|
|
```bash
|
|
bun run dev # Start Vite dev server
|
|
bun run build # Production build
|
|
bun run preview # Preview production build
|
|
```
|
|
|
|
### Adding Features
|
|
|
|
1. **Write tests first** in `seedpgp.test.ts`
|
|
2. **Implement in** `src/lib/seedpgp.ts`
|
|
3. **Update types** in `types.ts` if needed
|
|
4. **Run full test suite**: `bun test`
|
|
5. **Commit with conventional commits**: `feat: add QR generation`
|
|
|
|
## Feature Agenda
|
|
|
|
### 🚧 v1.2.0 - QR Code Round-Trip
|
|
|
|
**Goal**: Read back QR code and decrypt with user-provided credentials
|
|
|
|
**Tasks**:
|
|
- [ ] Add QR code generation from `encrypted.framed`
|
|
- Library: `qrcode` or `qr-code-styling`
|
|
- Input: SEEDPGP1 frame string
|
|
- Output: QR code image/canvas/SVG
|
|
|
|
- [ ] Add QR code scanner UI
|
|
- Library: `html5-qrcode` or `jsqr`
|
|
- Camera/file upload input
|
|
- Parse scanned text → `frameText`
|
|
|
|
- [ ] Build decrypt UI form
|
|
- Input fields:
|
|
- Scanned QR text (auto-filled)
|
|
- Private key (file upload or paste)
|
|
- Key passphrase (password input)
|
|
- OR message password (alternative)
|
|
- Call `decryptSeedPgp()`
|
|
- Display recovered mnemonic + metadata
|
|
|
|
- [ ] Add visual feedback
|
|
- CRC16 validation status
|
|
- Key fingerprint match indicator
|
|
- Decryption success/error states
|
|
|
|
**API Usage**:
|
|
```typescript
|
|
// Generate QR
|
|
import QRCode from 'qrcode';
|
|
const { framed } = await encryptToSeedPgp({ ... });
|
|
const qrDataUrl = await QRCode.toDataURL(framed);
|
|
|
|
// Scan and decrypt
|
|
const scannedText = "SEEDPGP1:0:ABCD:..."; // from scanner
|
|
const decrypted = await decryptSeedPgp({
|
|
frameText: scannedText,
|
|
privateKeyArmored: userKey,
|
|
privateKeyPassphrase: userPassword,
|
|
});
|
|
console.log(decrypted.w); // Recovered mnemonic
|
|
```
|
|
|
|
**Security Notes**:
|
|
- Never log decrypted mnemonics in production
|
|
- Clear sensitive data from memory after use
|
|
- Validate CRC16 before attempting decrypt
|
|
- Show key fingerprint for user verification
|
|
|
|
---
|
|
|
|
### 🔮 Future Ideas (v1.3+)
|
|
|
|
- [ ] Multi-frame support (for larger payloads)
|
|
- [ ] Password-only (SKESK) encryption flow
|
|
- [ ] Shamir Secret Sharing integration
|
|
- [ ] Hardware wallet key generation
|
|
- [ ] Mobile companion app (React Native)
|
|
- [ ] Printable paper backup templates
|
|
- [ ] Encrypted cloud backup with PBKDF2
|
|
- [ ] BIP85 child mnemonic derivation
|
|
|
|
## Debugging Tips
|
|
|
|
### Enable verbose PGP logging
|
|
|
|
Uncomment in `seedpgp.ts`:
|
|
```typescript
|
|
console.log("Raw PGP hex:", Array.from(pgpBytes).map(...));
|
|
console.log("SeedPGP: message packets:", ...);
|
|
console.log("SeedPGP: encryption key IDs:", ...);
|
|
```
|
|
|
|
### Test with known vectors
|
|
|
|
Use Trezor vectors from test file:
|
|
```bash
|
|
bun test "Trezor" # Run only Trezor tests
|
|
```
|
|
|
|
### Validate frame manually
|
|
|
|
```typescript
|
|
import { frameParse } from "./lib/seedpgp";
|
|
const parsed = frameParse("SEEDPGP1:0:ABCD:...");
|
|
console.log(parsed); // Check structure
|
|
```
|
|
|
|
## Code Style
|
|
|
|
- **Functions**: Async by default, explicit return types
|
|
- **Errors**: Throw descriptive Error objects with context
|
|
- **Naming**: `camelCase` for functions, `PascalCase` for types
|
|
- **Comments**: Only for non-obvious crypto/encoding logic
|
|
- **Testing**: One test per edge case, descriptive names
|
|
|
|
## Git Workflow
|
|
|
|
```bash
|
|
# Feature branch
|
|
git checkout -b feat/qr-generation
|
|
|
|
# Conventional commits
|
|
git commit -m "feat(qr): add QR code generation"
|
|
git commit -m "test(qr): add QR round-trip test"
|
|
|
|
# Tag releases
|
|
git tag -a v1.2.0 -m "Release v1.2.0 - QR round-trip"
|
|
git push origin main --tags
|
|
```
|
|
|
|
## Questions for Next Session
|
|
|
|
When continuing development, provide:
|
|
|
|
1. **Feature context**: "Adding QR code generation for v1.2.0"
|
|
2. **Current code**: Paste relevant files you're modifying
|
|
3. **Specific question**: "How should I structure the QR scanner component?"
|
|
|
|
Example starter prompt:
|
|
```
|
|
I'm working on seedpgp-web v1.1.0 (BIP39 PGP encryption tool).
|
|
|
|
[Paste this DEVELOPMENT.md section]
|
|
[Paste relevant source files]
|
|
|
|
I want to add QR code generation. Here's my current seedpgp.ts...
|
|
```
|
|
|
|
---
|
|
|
|
**Last Updated**: 2026-01-28
|
|
**Maintainer**: @kccleoc
|
|
```
|
|
|
|
Now commit it:
|
|
|
|
```bash
|
|
git add DEVELOPMENT.md
|
|
git commit -m "docs: add development guide with v1.2.0 QR agenda"
|
|
git push origin main
|
|
```
|
|
|
|
Ready for your next feature sprint! 🚀📋
|