mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-26 01:24:59 +02:00
* feat: API key gating for desktop cloud fallback + registration system Gate desktop cloud fallback behind WORLDMONITOR_API_KEY — desktop users need a valid key for cloud access, otherwise operate local-only (sidecar). Add email registration system via Convex DB for future key distribution. Client-side: installRuntimeFetchPatch() checks key presence before allowing cloud fallback, with secretsReady promise + 2s timeout. Server-side: origin-aware validation in sebuf gateway — desktop origins require key, web origins pass through. - Add WORLDMONITOR_API_KEY to 3-place secret system (Rust, TS, sidecar) - New "World Monitor" settings tab with key input + registration form - New api/_api-key.js server-side validation (origin-aware) - New api/register-interest.js edge function with rate limiting - Convex DB schema + mutation for email registration storage - CORS headers updated for X-WorldMonitor-Key + Authorization - E2E tests for key gate (blocked without key, allowed with key) - Deployment docs (API_KEY_DEPLOYMENT.md) + updated desktop config docs * fix: harden worldmonitor key + registration input handling * fix: show invalid WorldMonitor API key status * fix: simplify key validation, trim registration checks, add env example vars - Inline getValidKeys() in _api-key.js - Remove redundant type checks in register-interest.js - Simplify WorldMonitorTab status to present/missing - Add WORLDMONITOR_VALID_KEYS and CONVEX_URL to .env.example * feat(sidecar): integrate proto gateway bundle into desktop build The sidecar's buildRouteTable() only discovers .js files, so the proto gateway at api/[domain]/v1/[rpc].ts was invisible — all 45 sebuf RPCs returned 404 in the desktop app. Wire the existing build script into Tauri's build commands and add esbuild as an explicit devDependency.
5.3 KiB
5.3 KiB
API Key Gating & Registration — Deployment Guide
Overview
Desktop cloud fallback is gated on a WORLDMONITOR_API_KEY. Without a valid key, the desktop app operates local-only (sidecar). A registration form collects emails via Convex DB for future key distribution.
Architecture
Desktop App Cloud (Vercel)
┌──────────────────┐ ┌──────────────────────┐
│ fetch('/api/...')│ │ api/[domain]/v1/[rpc]│
│ │ │ │ │ │
│ ┌──────▼───────┐ │ │ ┌──────▼───────┐ │
│ │ sidecar try │ │ │ │ validateApiKey│ │
│ │ (local-first)│ │ │ │ (origin-aware)│ │
│ └──────┬───────┘ │ │ └──────┬───────┘ │
│ fail │ │ │ 401 if invalid │
│ ┌──────▼───────┐ │ fallback │ │
│ │ WM key check │─┼──────────────►│ ┌──────────────┐ │
│ │ (gate) │ │ +header │ │ route handler │ │
│ └──────────────┘ │ │ └──────────────┘ │
└──────────────────┘ └──────────────────────┘
Required Environment Variables
Vercel
| Variable | Description | Example |
|---|---|---|
WORLDMONITOR_VALID_KEYS |
Comma-separated list of valid API keys | wm_abc123def456,wm_xyz789 |
CONVEX_URL |
Convex deployment URL (from npx convex deploy) |
https://xyz-123.convex.cloud |
Generating API keys
Keys must be at least 16 characters (validated client-side). Recommended format:
# Generate a key
openssl rand -hex 24 | sed 's/^/wm_/'
# Example output: wm_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6
Add to WORLDMONITOR_VALID_KEYS in Vercel dashboard (comma-separated, no spaces).
Convex Setup
First-time deployment
# 1. Install (already in package.json)
npm install
# 2. Login to Convex
npx convex login
# 3. Initialize project (creates .env.local with CONVEX_URL)
npx convex init
# 4. Deploy schema and functions
npx convex deploy
# 5. Copy the deployment URL to Vercel env vars
# The URL is printed by `npx convex deploy` and saved in .env.local
Verify Convex deployment
# Typecheck Convex functions
npx convex dev --typecheck
# Open Convex dashboard to see registrations
npx convex dashboard
Schema
The registrations table stores:
| Field | Type | Description |
|---|---|---|
email |
string | Original email (for display) |
normalizedEmail |
string | Lowercased email (for dedup) |
registeredAt |
number | Unix timestamp |
source |
string? | Where the registration came from |
appVersion |
string? | Desktop app version |
Indexed by normalizedEmail for duplicate detection.
Security Model
Client-side (desktop app)
installRuntimeFetchPatch()checksWORLDMONITOR_API_KEYbefore allowing cloud fallback- Key must be present AND valid (min 16 chars)
secretsReadypromise ensures secrets are loaded before first fetch (2s timeout)- Fail-closed: any error in key check blocks cloud fallback
Server-side (Vercel edge)
api/_api-key.jsvalidatesX-WorldMonitor-Keyheader on sebuf routes- Origin-aware: desktop origins (
tauri.localhost,tauri://,asset://) require a key - Web origins (
worldmonitor.app) pass through without a key - Non-desktop origin with key header: key is still validated
- Invalid key returns
401 { error: "Invalid API key" }
CORS
X-WorldMonitor-Key is allowed in both server/cors.ts and api/_cors.js.
Verification Checklist
After deployment:
- Set
WORLDMONITOR_VALID_KEYSin Vercel - Set
CONVEX_URLin Vercel - Run
npx convex deployto push schema - Desktop without key: cloud fallback blocked (console shows
cloud fallback blocked) - Desktop with invalid key: sebuf requests get
401 - Desktop with valid key: cloud fallback works as before
- Web access: no key required, works normally
- Registration form: submit email, check Convex dashboard
- Duplicate email: shows "already registered"
- Existing settings tabs (LLMs, API Keys, Debug) unchanged
Files Reference
| File | Role |
|---|---|
src/services/runtime.ts |
Client-side key gate + header attachment |
src/services/runtime-config.ts |
WORLDMONITOR_API_KEY type, validation, secretsReady |
api/_api-key.js |
Server-side key validation (origin-aware) |
api/[domain]/v1/[rpc].ts |
Sebuf gateway — calls validateApiKey |
api/register-interest.js |
Registration endpoint → Convex |
server/cors.ts / api/_cors.js |
CORS headers with X-WorldMonitor-Key |
src/components/WorldMonitorTab.ts |
Settings UI for key + registration |
convex/schema.ts |
Convex DB schema |
convex/registerInterest.ts |
Convex mutation |