feat: X25519 ECDH sealed-box E2E encryption, zero-knowledge key exchange

- Replace libsodium with pure Web Crypto X25519 ECDH for key exchange
- Sealed-box pattern: ephemeral keypair + HKDF + AES-256-GCM for each recipient
- Store encrypted conversation key per-user so each party decrypts with their own private key
- PBKDF2-derived master key wraps X25519 private key (pkcs8) server-side for cross-device login
- Fix health endpoint ordering so it never hits auth middleware (401 bug)
- Fix postgres port exposure in docker-compose for backend connectivity
- Fix DrivePage react-query v5 onSuccess → useEffect migration
- Fix MessagesPage: use <Link> instead of <a href> to avoid page reload losing in-memory keys
- Fix formatDistanceToNow crash on WebSocket messages lacking sent_at (add fallback + null guard)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 4.6 committed 2026-08-28 10:10:40 -04:00
1 parent 937bf8ad2d
commit 46f0a4b71e
10 files changed
+308 -185

No files matched your search

+4 -4
View File
@@ -79,12 +79,12 @@ CREATE TABLE IF NOT EXISTS files (
CREATE INDEX IF NOT EXISTS idx_files_owner ON files(owner_id) WHERE deleted_at IS NULL;
-- Public keys for E2E key exchange
-- Public/private keys for X25519 ECDH key exchange
CREATE TABLE IF NOT EXISTS user_keys (
user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
-- X25519 public key for ECDH (base64)
-- X25519 public key (base64) — shared with other users
public_key TEXT NOT NULL,
-- Signed with user's identity key so others can verify
key_signature TEXT NOT NULL,
-- X25519 private key encrypted with master key (base64) — loaded on login for cross-device support
encrypted_private_key TEXT NOT NULL,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);