mirror of
https://github.com/kccleoc/seedpgp-web.git
synced 2026-03-06 17:37:51 +08:00
chore: Stage all remaining changes before merge
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -22,4 +22,5 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
REFERENCE
|
REFERENCE
|
||||||
|
.Ref
|
||||||
291
DEVELOPMENT.md
291
DEVELOPMENT.md
@@ -1,291 +0,0 @@
|
|||||||
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! 🚀📋
|
|
||||||
121
public/README.md
121
public/README.md
@@ -1,121 +0,0 @@
|
|||||||
# SeedPGP Web App
|
|
||||||
|
|
||||||
**Secure BIP39 mnemonic backup tool using OpenPGP encryption**
|
|
||||||
|
|
||||||
🔗 **Live App**: https://kccleoc.github.io/seedpgp-web-app/
|
|
||||||
|
|
||||||
## About
|
|
||||||
|
|
||||||
Client-side web application for encrypting cryptocurrency seed phrases (BIP39 mnemonics) using OpenPGP encryption with QR code generation and scanning capabilities.
|
|
||||||
|
|
||||||
### ✨ Features
|
|
||||||
|
|
||||||
- 🔐 **OpenPGP Encryption** - Curve25519Legacy (cv25519) encryption
|
|
||||||
- 📱 **QR Code Generation** - High-quality 512x512px PNG with download
|
|
||||||
- 📸 **QR Code Scanner** - Camera or image upload with live preview
|
|
||||||
- 🔄 **Round-trip Flow** - Encrypt → QR → Scan → Decrypt seamlessly
|
|
||||||
- ✅ **BIP39 Support** - 12/18/24-word mnemonics with optional passphrase
|
|
||||||
- 🔒 **Symmetric Encryption** - Optional password-only encryption (SKESK)
|
|
||||||
- 🎯 **CRC16 Validation** - Frame integrity checking
|
|
||||||
- 📦 **Base45 Encoding** - Compact QR-friendly format (RFC 9285)
|
|
||||||
- 🌐 **100% Client-Side** - No backend, no data transmission
|
|
||||||
|
|
||||||
## 🔒 Security Notice
|
|
||||||
|
|
||||||
⚠️ **Your private keys and seed phrases never leave your browser**
|
|
||||||
|
|
||||||
- Static web app with **no backend server**
|
|
||||||
- All cryptographic operations run **locally in your browser**
|
|
||||||
- **No data transmitted** to any server
|
|
||||||
- Camera access requires **HTTPS or localhost**
|
|
||||||
- Always verify you're on the correct URL before use
|
|
||||||
|
|
||||||
### For Maximum Security
|
|
||||||
|
|
||||||
For production use with real funds:
|
|
||||||
- 🏠 Download and run locally (\`bun run dev\`)
|
|
||||||
- 🔐 Use on airgapped device
|
|
||||||
- 📥 Self-host on your own domain
|
|
||||||
- 🔍 Source code: https://github.com/kccleoc/seedpgp-web (private)
|
|
||||||
|
|
||||||
## 📖 How to Use
|
|
||||||
|
|
||||||
### Backup Flow
|
|
||||||
1. **Enter** your 12/24-word BIP39 mnemonic
|
|
||||||
2. **Add** PGP public key and/or message password (optional)
|
|
||||||
3. **Generate** encrypted QR code
|
|
||||||
4. **Download** or scan QR code for backup
|
|
||||||
|
|
||||||
### Restore Flow
|
|
||||||
1. **Scan QR Code** using camera or upload image
|
|
||||||
2. **Provide** private key and/or message password
|
|
||||||
3. **Decrypt** to recover your mnemonic
|
|
||||||
|
|
||||||
### QR Scanner Features
|
|
||||||
- 📷 **Camera Mode** - Live scanning with environment camera (iPhone Continuity Camera supported on macOS)
|
|
||||||
- 📁 **Upload Mode** - Scan from saved images or screenshots
|
|
||||||
- ✅ **Auto-validation** - Verifies SEEDPGP1 format before accepting
|
|
||||||
|
|
||||||
## 🛠 Technical Stack
|
|
||||||
|
|
||||||
- **TypeScript** - Type-safe development
|
|
||||||
- **React 18** - Modern UI framework
|
|
||||||
- **Vite 6** - Lightning-fast build tool
|
|
||||||
- **OpenPGP.js v6** - RFC 4880 compliant encryption
|
|
||||||
- **html5-qrcode** - QR scanning library
|
|
||||||
- **TailwindCSS** - Utility-first styling
|
|
||||||
- **Lucide React** - Beautiful icons
|
|
||||||
|
|
||||||
## 📋 Protocol Format
|
|
||||||
|
|
||||||
\`\`\`
|
|
||||||
SEEDPGP1:0:ABCD:BASE45DATA
|
|
||||||
|
|
||||||
SEEDPGP1 - Protocol identifier + version
|
|
||||||
0 - Frame number (single frame)
|
|
||||||
ABCD - CRC16-CCITT-FALSE checksum
|
|
||||||
BASE45 - Base45-encoded OpenPGP binary message
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
## 🔐 Encryption Details
|
|
||||||
|
|
||||||
- **Algorithm**: AES-256 (preferred symmetric cipher)
|
|
||||||
- **Curve**: Curve25519Legacy for modern security
|
|
||||||
- **Key Format**: OpenPGP RFC 4880 compliant
|
|
||||||
- **Error Correction**: QR Level M (15% recovery)
|
|
||||||
- **Integrity**: CRC16-CCITT-FALSE frame validation
|
|
||||||
|
|
||||||
## 📱 Browser Compatibility
|
|
||||||
|
|
||||||
- ✅ Chrome/Edge (latest)
|
|
||||||
- ✅ Safari 16+ (macOS/iOS)
|
|
||||||
- ✅ Firefox (latest)
|
|
||||||
- 📷 Camera requires HTTPS or localhost
|
|
||||||
|
|
||||||
## 📦 Version
|
|
||||||
|
|
||||||
**Current deployment: v1.2.0**
|
|
||||||
|
|
||||||
### Changelog
|
|
||||||
|
|
||||||
#### v1.2.0 (2026-01-29)
|
|
||||||
- ✨ Added QR scanner with camera/upload support
|
|
||||||
- 📥 Added QR code download with auto-naming
|
|
||||||
- 🔧 Split state for backup/restore tabs
|
|
||||||
- 🎨 Improved QR generation quality
|
|
||||||
- 🐛 Fixed Safari camera permissions
|
|
||||||
- 📱 Added Continuity Camera support
|
|
||||||
|
|
||||||
#### v1.1.0 (2026-01-28)
|
|
||||||
- 🎉 Initial public release
|
|
||||||
- 🔐 OpenPGP encryption/decryption
|
|
||||||
- 📱 QR code generation
|
|
||||||
- ✅ BIP39 validation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Last updated**: 2026-01-29
|
|
||||||
|
|
||||||
**Built with** ❤️ using TypeScript, React, Vite, and OpenPGP.js
|
|
||||||
|
|
||||||
**License**: Private source code - deployment only
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/*
|
|
||||||
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'none'; form-action 'none'; base-uri 'self';
|
|
||||||
X-Frame-Options: DENY
|
|
||||||
X-Content-Type-Options: nosniff
|
|
||||||
X-XSS-Protection: 1; mode=block
|
|
||||||
Referrer-Policy: strict-origin-when-cross-origin
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -161,7 +161,6 @@ export function SeedBlender({ onDirtyStateChange, setMnemonicForBackup, requestT
|
|||||||
const handleScanSuccess = useCallback(async (scannedData: string | Uint8Array) => {
|
const handleScanSuccess = useCallback(async (scannedData: string | Uint8Array) => {
|
||||||
if (scanTargetIndex === null) return;
|
if (scanTargetIndex === null) return;
|
||||||
|
|
||||||
// Convert binary data to hex string if necessary
|
|
||||||
const scannedText = typeof scannedData === 'string'
|
const scannedText = typeof scannedData === 'string'
|
||||||
? scannedData
|
? scannedData
|
||||||
: Array.from(scannedData).map(b => b.toString(16).padStart(2, '0')).join('');
|
: Array.from(scannedData).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import * as openpgp from "openpgp";
|
|||||||
import { base45Encode, base45Decode } from "./base45";
|
import { base45Encode, base45Decode } from "./base45";
|
||||||
import { crc16CcittFalse } from "./crc16";
|
import { crc16CcittFalse } from "./crc16";
|
||||||
import { encryptToKrux, decryptFromKrux } from "./krux";
|
import { encryptToKrux, decryptFromKrux } from "./krux";
|
||||||
|
import { decodeSeedQR } from './seedqr';
|
||||||
import type {
|
import type {
|
||||||
SeedPgpPlaintext,
|
SeedPgpPlaintext,
|
||||||
ParsedSeedPgpFrame,
|
ParsedSeedPgpFrame,
|
||||||
@@ -302,6 +303,25 @@ export async function decryptFromSeed(params: DecryptionParams): Promise<SeedPgp
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode === 'seedqr') {
|
||||||
|
try {
|
||||||
|
const mnemonic = await decodeSeedQR(params.frameText);
|
||||||
|
// Convert to SeedPgpPlaintext format for consistency
|
||||||
|
return {
|
||||||
|
v: 1,
|
||||||
|
t: "bip39",
|
||||||
|
w: mnemonic,
|
||||||
|
l: "en",
|
||||||
|
pp: 0,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(`SeedQR decoding failed: ${error.message}`);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Default to PGP mode
|
// Default to PGP mode
|
||||||
return decryptSeedPgp({
|
return decryptSeedPgp({
|
||||||
|
|||||||
Reference in New Issue
Block a user