12 Commits

Author SHA1 Message Date
LC mac
81fbd210ca chore: Bump version to 1.4.3 2026-01-30 18:39:30 +08:00
LC mac
5ea3b92ab1 docs: Update version to 1.4.2 in GEMINI.md 2026-01-30 17:33:08 +08:00
LC mac
eec194fbba docs: Revert deployment process and update version in GEMINI.md 2026-01-30 17:26:27 +08:00
LC mac
24c714fb2f update index to 1.4.2 2026-01-30 02:13:53 +08:00
LC mac
eeb5184b8a Cloudflare Pages migration with enforced CSP headers 2026-01-30 02:11:06 +08:00
LC mac
422fe04a12 fix: Copy _headers to dist during build 2026-01-30 01:59:24 +08:00
LC mac
ebeea79a33 chore: Force Cloudflare rebuild with correct base path 2026-01-30 01:49:01 +08:00
LC mac
faf58dc49d fix: Auto-detect base path for Cloudflare vs GitHub Pages 2026-01-30 01:44:53 +08:00
LC mac
46982794cc feat(v1.4): Add 'Encrypted in memory' badge 2026-01-30 01:25:09 +08:00
LC mac
9ffdbbd50f feat(v1.4): Add 'Encrypted in memory' badge 2026-01-30 01:21:28 +08:00
LC mac
b024856c08 docs: update GEMINI.md for v1.4.0 + remove debug logs 2026-01-30 00:44:46 +08:00
LC mac
a919e8bf09 chore: small fix in 1.4.0 2026-01-30 00:36:09 +08:00
8 changed files with 208 additions and 186 deletions

View File

@@ -2,7 +2,7 @@
## Project Overview ## Project Overview
**SeedPGP v1.3.0**: Client-side BIP39 mnemonic encryption webapp **SeedPGP v1.4.3**: Client-side BIP39 mnemonic encryption webapp
**Stack**: Bun + Vite + React + TypeScript + OpenPGP.js + Tailwind CSS **Stack**: Bun + Vite + React + TypeScript + OpenPGP.js + Tailwind CSS
**Deploy**: GitHub Pages (public repo: `seedpgp-web-app`, private source: `seedpgp-web`) **Deploy**: GitHub Pages (public repo: `seedpgp-web-app`, private source: `seedpgp-web`)
**Live URL**: <https://kccleoc.github.io/seedpgp-web-app/> **Live URL**: <https://kccleoc.github.io/seedpgp-web-app/>
@@ -34,7 +34,7 @@
### Directory Structure ### Directory Structure
``` ```BASH
src/ src/
├── components/ # React UI components ├── components/ # React UI components
│ ├── PgpKeyInput.tsx │ ├── PgpKeyInput.tsx
@@ -104,10 +104,11 @@ Core interfaces:
- **Clipboard Tracker**: Monitor clipboard operations on sensitive fields - **Clipboard Tracker**: Monitor clipboard operations on sensitive fields
- **Read-only Mode**: Toggle to clear state + show CSP/build info - **Read-only Mode**: Toggle to clear state + show CSP/build info
### v1.3 - Session-Key Encryption (Current) ### v1.3-v1.4 - Session-Key Encryption
- **Ephemeral encryption**: AES-GCM-256 session key (non-exportable) encrypts sensitive state - **Ephemeral encryption**: AES-GCM-256 session key (non-exportable) encrypts sensitive state
- **Auto-clear**: Plaintext mnemonic cleared from UI immediately after QR generation - **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 - **Encrypted cache**: Only ciphertext stored in React state; key lives in memory only
- **Lock/Clear**: Manual cleanup destroys session key + clears all state - **Lock/Clear**: Manual cleanup destroys session key + clears all state
- **Lifecycle**: Session key auto-destroyed on page close/refresh - **Lifecycle**: Session key auto-destroyed on page close/refresh
@@ -129,9 +130,23 @@ bun run preview # Preview production build
### Deployment Process ### Deployment Process
1. **Private repo** (`seedpgp-web`): Source code, development **Production:** Cloudflare Pages (auto-deploys from `main` branch)
2. **Public repo** (`seedpgp-web-app`): Built files for GitHub Pages **Live URL:** <https://seedpgp-web.pages.dev>
3. **Deploy script** (`scripts/deploy.sh`): Builds + copies to dist/ + pushes to public repo
### 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`
### Benefits Over GitHub Pages
- ✅ Real CSP header enforcement (blocks network requests at browser level)
- ✅ Custom security headers (X-Frame-Options, X-Content-Type-Options)
- ✅ Auto-deploy on push to main
- ✅ Build preview for PRs
- ✅ Better performance (global CDN)
### Git Workflow ### Git Workflow
@@ -140,10 +155,19 @@ bun run preview # Preview production build
git add src/ git add src/
git commit -m "feat(v1.x): description" git commit -m "feat(v1.x): description"
# Tag version # Tag version (triggers auto-deploy to Cloudflare)
git tag v1.x.x git tag v1.x.x
git push origin main --tags 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"
# Deploy to GitHub Pages # Deploy to GitHub Pages
./scripts/deploy.sh v1.x.x ./scripts/deploy.sh v1.x.x
``` ```
@@ -290,27 +314,9 @@ await window.runSessionCryptoTest()
--- ---
## Current Version: v1.3.0 ## Current Version: v1.4.3
### Recent Changes (2026-01-29) *Please update the "Recent Changes", "Known Limitations", and "Next Priorities" sections to reflect the current state of the project.*
- ✅ 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)
--- ---

307
README.md
View File

@@ -1,8 +1,10 @@
# SeedPGP v1.1.0 # SeedPGP v1.4.3
**Secure BIP39 mnemonic backup using PGP encryption and QR codes** **Secure BIP39 mnemonic backup using PGP encryption and QR codes**
A TypeScript/Bun tool for encrypting cryptocurrency seed phrases with OpenPGP and encoding them as QR-friendly Base45 frames with CRC16 integrity checking. A client-side web app for encrypting cryptocurrency seed phrases with OpenPGP and encoding them as QR-friendly Base45 frames with CRC16 integrity checking.
**Live App:** <https://seedpgp-web.pages.dev>
## Features ## Features
@@ -11,7 +13,11 @@ A TypeScript/Bun tool for encrypting cryptocurrency seed phrases with OpenPGP an
-**Integrity Checking**: CRC16-CCITT-FALSE checksums prevent corruption -**Integrity Checking**: CRC16-CCITT-FALSE checksums prevent corruption
- 🔑 **BIP39 Support**: Full support for 12/18/24-word mnemonics with passphrase indicator - 🔑 **BIP39 Support**: Full support for 12/18/24-word mnemonics with passphrase indicator
- 🧪 **Battle-Tested**: Validated against official Trezor BIP39 test vectors - 🧪 **Battle-Tested**: Validated against official Trezor BIP39 test vectors
-**Fast**: Built with Bun runtime for optimal performance -**Fast**: Built with Bun runtime and Vite for optimal performance
- 🔒 **Session-Key Encryption**: Ephemeral AES-GCM-256 encryption for in-memory protection
- 🛡️ **CSP Enforcement**: Real Content Security Policy headers block all network requests
- 📸 **QR Scanner**: Camera and file upload support for scanning encrypted QR codes
- 👁️ **Security Monitoring**: Real-time storage monitoring and clipboard tracking
## Installation ## Installation
@@ -32,7 +38,30 @@ bun run dev
## Usage ## Usage
### Encrypt a Mnemonic ### Web Interface
Visit <https://seedpgp-web.pages.dev> or run locally:
```bash
bun run dev
# Open http://localhost:5173
```
**Backup Flow:**
1. Enter your BIP39 mnemonic (12/18/24 words)
2. Import PGP public key or set encryption password
3. Click "Backup" to encrypt and generate QR code
4. Save/print QR code for offline storage
**Restore Flow:**
1. Scan QR code or paste encrypted text
2. Import PGP private key or enter password
3. Click "Restore" to decrypt mnemonic
4. Mnemonic auto-clears after 10 seconds
### API Usage
```typescript ```typescript
import { encryptToSeedPgp, buildPlaintext } from "./lib/seedpgp"; import { encryptToSeedPgp, buildPlaintext } from "./lib/seedpgp";
@@ -64,106 +93,42 @@ console.log(decrypted.w); // Recovered mnemonic
console.log(decrypted.pp); // BIP39 passphrase indicator (0 or 1) console.log(decrypted.pp); // BIP39 passphrase indicator (0 or 1)
``` ```
## Deployment to GitHub Pages (FREE) ## Deployment
This project uses a two-repository setup to keep source code private while hosting the app for free. **Production:** Cloudflare Pages (auto-deploys from `main` branch)
**Live URL:** <https://seedpgp-web.pages.dev>
### One-Time Setup ### Cloudflare Pages Setup
#### 1. Create Public Deployment Repo This project is deployed on Cloudflare Pages for enhanced security features:
Go to https://github.com/new and create: 1. **Repository:** `seedpgp-web` (private repo)
- **Name**: `seedpgp-web-app` (or any name you prefer) 2. **Build command:** `bun run build`
- **Visibility**: **Public** 3. **Output directory:** `dist/`
- **Don't** initialize with README, .gitignore, or license 4. **Security headers:** Automatically enforced via `public/_headers`
#### 2. Configure Vite Base Path ### Benefits Over GitHub Pages
Edit `vite.config.ts`: - ✅ Real CSP header enforcement (blocks network requests at browser level)
- ✅ Custom security headers (X-Frame-Options, X-Content-Type-Options)
- ✅ Auto-deploy on push to main
- ✅ Build preview for PRs
- ✅ Better performance (global CDN)
- ✅ Cost: $0/month
```typescript ### Deployment Workflow
export default defineConfig({
plugins: [react()],
base: '/seedpgp-web-app/', // Match your public repo name
})
```
#### 3. Build and Deploy
```bash ```bash
# Build the production bundle # Commit feature
bun run build git add src/
git commit -m "feat(v1.x): description"
# Initialize git in dist folder # Tag version (triggers auto-deploy to Cloudflare)
cd dist git tag v1.x.x
git init git push origin main --tags
git add .
git commit -m "Deploy seedpgp v1.1.0"
# Push to your public repo
git remote add origin https://github.com/kccleoc/seedpgp-web-app.git
git branch -M main
git push -u origin main
# Return to project root
cd ..
``` ```
#### 4. Enable GitHub Pages **No manual deployment needed!** Cloudflare Pages auto-deploys when you push to `main`.
1. Go to `https://github.com/kccleoc/seedpgp-web-app/settings/pages`
2. **Source**: Deploy from a branch
3. **Branch**: Select `main``/` (root)
4. Click **Save**
Wait 1-2 minutes, then visit: **https://kccleoc.github.io/seedpgp-web-app/**
---
### Deploying Updates (v1.2.0, v1.3.0, etc.)
Create `scripts/deploy.sh` in your project root:
```bash
#!/bin/bash
set -e
VERSION=$1
if [ -z "$VERSION" ]; then
echo "Usage: ./scripts/deploy.sh v1.2.0"
exit 1
fi
echo "🔨 Building $VERSION..."
bun run build
echo "📦 Deploying to GitHub Pages..."
cd dist
git add .
git commit -m "Deploy $VERSION" || echo "No changes to commit"
git push
cd ..
echo "✅ Deployed to https://kccleoc.github.io/seedpgp-web-app/"
echo "🏷️ Don't forget to tag: git tag $VERSION && git push --tags"
```
Make executable and use:
```bash
chmod +x scripts/deploy.sh
./scripts/deploy.sh v1.2.0
```
---
### Repository Structure
- **seedpgp-web** (Private) - Your source code, active development
- **seedpgp-web-app** (Public) - Built files only, served via GitHub Pages
**Cost: $0/month**
## Frame Format ## Frame Format
@@ -183,6 +148,7 @@ BASE45 - Base45-encoded PGP message
Creates a SeedPGP plaintext object. Creates a SeedPGP plaintext object.
**Parameters:** **Parameters:**
- `mnemonic` (string): BIP39 mnemonic phrase (12/18/24 words) - `mnemonic` (string): BIP39 mnemonic phrase (12/18/24 words)
- `bip39PassphraseUsed` (boolean): Whether a BIP39 passphrase was used - `bip39PassphraseUsed` (boolean): Whether a BIP39 passphrase was used
- `recipientFingerprints` (string[]): Optional array of recipient key fingerprints - `recipientFingerprints` (string[]): Optional array of recipient key fingerprints
@@ -194,6 +160,7 @@ Creates a SeedPGP plaintext object.
Encrypts a plaintext object to SeedPGP format. Encrypts a plaintext object to SeedPGP format.
**Parameters:** **Parameters:**
```typescript ```typescript
{ {
plaintext: SeedPgpPlaintext; plaintext: SeedPgpPlaintext;
@@ -203,6 +170,7 @@ Encrypts a plaintext object to SeedPGP format.
``` ```
**Returns:** **Returns:**
```typescript ```typescript
{ {
framed: string; // SEEDPGP1 frame framed: string; // SEEDPGP1 frame
@@ -216,6 +184,7 @@ Encrypts a plaintext object to SeedPGP format.
Decrypts a SeedPGP frame. Decrypts a SeedPGP frame.
**Parameters:** **Parameters:**
```typescript ```typescript
{ {
frameText: string; // SEEDPGP1 frame frameText: string; // SEEDPGP1 frame
@@ -256,6 +225,8 @@ bun test --watch
- **cv25519** provides ~128-bit security level - **cv25519** provides ~128-bit security level
- **CRC16** detects QR scan errors (not cryptographic) - **CRC16** detects QR scan errors (not cryptographic)
- Key fingerprint validation prevents wrong-key usage - Key fingerprint validation prevents wrong-key usage
- **Session-key encryption**: Ephemeral AES-GCM-256 for in-memory protection
- **CSP headers**: Browser-enforced network blocking via Cloudflare Pages
### ⚠️ Important Notes ### ⚠️ Important Notes
@@ -267,50 +238,129 @@ bun test --watch
### 🔒 Production Deployment Warning ### 🔒 Production Deployment Warning
The GitHub Pages deployment at **https://kccleoc.github.io/seedpgp-web-app/** is for: The Cloudflare Pages deployment at **<https://seedpgp-web.pages.dev>** is for:
- ✅ Testing and demonstration
-Convenient access for personal use -Personal use with enhanced security
- ✅ CSP enforcement blocks all network requests
- ✅ Convenient access from any device
- ⚠️ Always verify the URL before use - ⚠️ Always verify the URL before use
For maximum security with real funds: For maximum security with real funds:
- Run locally: `bun run dev` - Run locally: `bun run dev`
- Or self-host on your own domain with HTTPS - Or self-host on your own domain with HTTPS
- Use an airgapped device for critical operations
### 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:**
- Active XSS or malicious browser extensions
- Memory dumps or browser crash reports
- JavaScript garbage collection timing (non-deterministic)
## Project Structure ## Project Structure
``` ```
seedpgp-web/ seedpgp-web/
├── src/ ├── src/
│ ├── components/
│ │ ├── PgpKeyInput.tsx # PGP key import UI
│ │ ├── QrDisplay.tsx # QR code generation
│ │ ├── QrScanner.tsx # Camera + file scanner
│ │ ├── ReadOnly.tsx # Read-only mode toggle
│ │ ├── StorageIndicator.tsx # Storage monitoring
│ │ ├── SecurityWarnings.tsx # Context alerts
│ │ └── ClipboardTracker.tsx # Clipboard monitoring
│ ├── lib/ │ ├── lib/
│ │ ├── seedpgp.ts # Core encryption/decryption │ │ ├── seedpgp.ts # Core encryption/decryption
│ │ ├── seedpgp.test.ts # Test vectors │ │ ├── seedpgp.test.ts # Test vectors
│ │ ├── base45.ts # Base45 codec │ │ ├── sessionCrypto.ts # Ephemeral session keys
│ │ ├── crc16.ts # CRC16-CCITT-FALSE │ │ ├── base45.ts # Base45 codec
│ │ ── types.ts # TypeScript definitions │ │ ── crc16.ts # CRC16-CCITT-FALSE
└── App.tsx # React UI │ ├── qr.ts # QR utilities
├── scripts/ │ │ └── types.ts # TypeScript definitions
── deploy.sh # Deployment automation ── App.tsx # Main application
│ └── main.tsx # React entry point
├── public/
│ └── _headers # Cloudflare CSP headers
├── package.json ├── package.json
├── DEVELOPMENT.md # Development guide ├── vite.config.ts # Vite configuration
── README.md # This file ── GEMINI.md # AI agent project brief
└── README.md # This file
``` ```
## Tech Stack ## Tech Stack
- **Runtime**: [Bun](https://bun.sh) v1.3.6+ - **Runtime**: [Bun](https://bun.sh) v1.3.6+
- **Language**: TypeScript - **Language**: TypeScript (strict mode)
- **Crypto**: [OpenPGP.js](https://openpgpjs.org) v6.3.0 - **Crypto**: [OpenPGP.js](https://openpgpjs.org) v6.3.0
- **Framework**: React + Vite - **Framework**: React + Vite
- **UI**: Tailwind CSS
- **Icons**: lucide-react
- **QR**: html5-qrcode, qrcode
- **Testing**: Bun test runner - **Testing**: Bun test runner
- **Deployment**: Cloudflare Pages
## Version History
### v1.4.3 (2026-01-30)
- ✅ Fixed textarea contrast for readability
- ✅ Fixed overlapping floating boxes
- ✅ Polished UI with modern crypto wallet design
- ✅ Updated background color to be lighter
### v1.4.2 (2026-01-30)
- ✅ Migrated to Cloudflare Pages for real CSP enforcement
- ✅ Added "Encrypted in memory" badge when mnemonic locked
- ✅ Improved security header configuration
- ✅ Updated deployment documentation
### v1.4.0 (2026-01-29)
- ✅ Extended session-key encryption to Restore flow
- ✅ Added 10-second auto-clear timer for restored mnemonic
- ✅ Added manual Hide button for immediate clearing
- ✅ Removed debug console logs from production
### v1.3.0 (2026-01-28)
- ✅ Implemented ephemeral session-key encryption (AES-GCM-256)
- ✅ Auto-clear mnemonic after QR generation (Backup flow)
- ✅ Encrypted cache for sensitive state
- ✅ Manual Lock/Clear functionality
### v1.2.0 (2026-01-27)
- ✅ Added storage monitoring (StorageIndicator)
- ✅ Added security warnings (context-aware)
- ✅ Added clipboard tracking
- ✅ Implemented read-only mode
### v1.1.0 (2026-01-26)
- ✅ Initial public release
- ✅ QR code generation and scanning
- ✅ Full BIP39 mnemonic support
- ✅ Trezor test vector validation
- ✅ Production-ready implementation
## Roadmap ## Roadmap
- [ ] QR code generation UI - [ ] UI polish (modern crypto wallet design)
- [ ] QR code scanner with camera support
- [ ] Multi-frame support for larger payloads - [ ] Multi-frame support for larger payloads
- [ ] Hardware wallet integration - [ ] Hardware wallet integration
- [ ] Mobile scanning app - [ ] Mobile scanning app
- [ ] Shamir Secret Sharing support - [ ] Shamir Secret Sharing support
- [ ] Reproducible builds with git hash verification
## License ## License
@@ -320,47 +370,6 @@ MIT License - see LICENSE file for details
**kccleoc** - [GitHub](https://github.com/kccleoc) **kccleoc** - [GitHub](https://github.com/kccleoc)
## Version History
### v1.1.0 (2026-01-28)
- Initial public release
- Full BIP39 mnemonic support
- Trezor test vector validation
- Production-ready implementation
- GitHub Pages deployment guide
--- ---
⚠️ **Disclaimer**: This software is provided as-is. Always test thoroughly before trusting with real funds. The author is not responsible for lost funds due to software bugs or user error. ⚠️ **Disclaimer**: This software is provided as-is. Always test thoroughly before trusting with real funds. The author is not responsible for lost funds due to software bugs or user error.
Now create the deployment script:
```bash
mkdir -p scripts
cat > scripts/deploy.sh << 'EOF'
#!/bin/bash
set -e
VERSION=$1
if [ -z "$VERSION" ]; then
echo "Usage: ./scripts/deploy.sh v1.2.0"
exit 1
fi
echo "🔨 Building $VERSION..."
bun run build
echo "📦 Deploying to GitHub Pages..."
cd dist
git add .
git commit -m "Deploy $VERSION" || echo "No changes to commit"
git push
cd ..
echo "✅ Deployed to https://kccleoc.github.io/seedpgp-web-app/"
echo "🏷️ Don't forget to tag: git tag $VERSION && git push --tags"
EOF
chmod +x scripts/deploy.sh
```

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SeedPGP v1.1</title> <title>SeedPGP v1.4.2</title>
</head> </head>
<body> <body>

View File

@@ -1,7 +1,7 @@
{ {
"name": "seedpgp-web", "name": "seedpgp-web",
"private": true, "private": true,
"version": "1.3.0", "version": "1.4.3",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

6
public/_headers Normal file
View File

@@ -0,0 +1,6 @@
/*
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; 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

View File

@@ -216,6 +216,12 @@ import { getSessionKey, encryptJsonToBlob, destroySessionKey, EncryptedBlob } fr
<span>Read-only</span> <span>Read-only</span>
</div> </div>
)} )}
{encryptedMnemonicCache && (
<div className="flex items-center gap-2 text-sm text-green-400 bg-slate-800/50 px-3 py-1.5 rounded-lg">
<Shield size={16} />
<span>Encrypted in memory</span>
</div>
)}
<div className="flex bg-slate-800/50 rounded-lg p-1 backdrop-blur"> <div className="flex bg-slate-800/50 rounded-lg p-1 backdrop-blur">
<button <button
onClick={() => { onClick={() => {

View File

@@ -56,13 +56,10 @@ export interface EncryptedBlob {
* @returns A promise that resolves to the generated or existing CryptoKey. * @returns A promise that resolves to the generated or existing CryptoKey.
*/ */
export async function getSessionKey(): Promise<CryptoKey> { export async function getSessionKey(): Promise<CryptoKey> {
console.log('getSessionKey called.');
if (sessionKey) { if (sessionKey) {
console.log('Session key already exists.');
return sessionKey; return sessionKey;
} }
console.log('Generating new session key...');
const key = await window.crypto.subtle.generateKey( const key = await window.crypto.subtle.generateKey(
{ {
name: KEY_ALGORITHM, name: KEY_ALGORITHM,
@@ -72,7 +69,6 @@ export async function getSessionKey(): Promise<CryptoKey> {
['encrypt', 'decrypt'], ['encrypt', 'decrypt'],
); );
sessionKey = key; sessionKey = key;
console.log('New session key generated and stored.');
return key; return key;
} }
@@ -82,9 +78,7 @@ export async function getSessionKey(): Promise<CryptoKey> {
* @returns A promise that resolves to an EncryptedBlob. * @returns A promise that resolves to an EncryptedBlob.
*/ */
export async function encryptJsonToBlob<T>(data: T): Promise<EncryptedBlob> { export async function encryptJsonToBlob<T>(data: T): Promise<EncryptedBlob> {
console.log('encryptJsonToBlob called.');
if (!sessionKey) { if (!sessionKey) {
console.error('ERROR: Session key not initialized when encryptJsonToBlob was called.');
throw new Error('Session key not initialized. Call getSessionKey() first.'); throw new Error('Session key not initialized. Call getSessionKey() first.');
} }

View File

@@ -12,7 +12,8 @@ const gitHash = execSync('git rev-parse --short HEAD').toString().trim()
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
base: '/seedpgp-web-app/', base: process.env.CF_PAGES ? '/' : '/seedpgp-web-app/',
publicDir: 'public', // ← Explicitly set (should be default)
build: { build: {
outDir: 'dist', outDir: 'dist',
emptyOutDir: false, emptyOutDir: false,