This commit applies the actionable plan from docs/plans/2026-04-29-encrypted-p2p-chat-audit-fixes.md.
Backend
- Delete server-side X3DH/Double Ratchet (`app/core/encryption/*`); the server is now an opaque relay for client-encrypted messages.
- Drop `private_key` columns from IdentityKey/SignedPrekey/OneTimePrekey; prekey-bundle endpoint serves only public material.
- Remove RatchetState and SkippedMessageKey models and the deprecated server-encryption code path in message_service.
- Fix the broken `not OneTimePrekey.is_used` SQL filter (`Column.is_(False)` instead of Python `not`); repair the silent OPK-replenish amplification by deleting the server-generated path entirely.
- Stop calling `prekey_service.initialize_user_keys` from registration/login. Server never holds private key material again.
- Add session-cookie auth: opaque token issued in Redis on register/auth complete, `current_user` dependency on every protected route, `/auth/me`, `/auth/logout`. WebSocket authenticates via the same cookie.
- Add room membership checks to WS encrypted_message + typing handlers, GET/DELETE /rooms/{id}, GET /rooms/{id}/messages. broadcast_to_room now filters by participants, not presence.
- Add slowapi rate limits to register/auth/search; per-user sliding-window cap on WS messages.
- WebAuthn: replace username with a 64-byte random `webauthn_user_handle` for `user.id`; fix `backup_eligible` to read `credential_backup_eligible`; switch UserVerificationRequirement to REQUIRED; key authentication challenges by challenge bytes (no more "discoverable" collision).
- Implement GET /rooms/{id} and DELETE /rooms/{id} (cascade delete with ownership check) and fix the N+1 in list_rooms by batching User lookups.
- Remove broken/obsolete tests; add regression tests for the OPK filter bug and session-protected endpoints (401 without cookie).
- Sanitize WebSocket error responses; correlation IDs replace stack-trace leaks.
Frontend
- X3DH: prepend the 32-byte 0xff F prefix to the HKDF input per spec section 2.2.
- Double Ratchet: switch KDF_RK to spec form (HKDF salt=root_key, IKM=dh_output) and use 0x01/0x02 byte tags for KDF_CK.
- Replace base64 helpers in `crypto/primitives.ts` with the URL-safe codec from `lib/base64.ts` (single source of truth, no spread-stack hazard).
- Update auth.service to issue a session via cookies (no more dead token store), call `/auth/me` on app boot, clear crypto state on logout. Delete unused `session.store.ts`.
- Update room.service / Chat page to drop client-supplied user_id arguments; the cookie now identifies the caller.
- Better forward-secrecy UX text for messages predating the device.
- Add Vitest with X3DH and Double Ratchet round-trip + tamper-detection tests.
Tooling
- Add `slowapi>=0.1.9` to backend deps; add `vitest` to frontend devDeps with `pnpm test` script.
- justfile: `test-frontend`, `dev-reset`.
- Adjust `.gitignore` so the Python `lib/` rules no longer hide `frontend/src/lib`.
Migration: existing dev volumes hold private-key columns and KDF-incompatible ratchet states; run `just dev-reset` and re-register before hitting the new code path.
|
||
|---|---|---|
| .. | ||
| public/assets | ||
| src | ||
| .gitignore | ||
| .prettierignore | ||
| .prettierrc | ||
| README.md | ||
| biome.json | ||
| eslint.config.js | ||
| index.html | ||
| package.json | ||
| pnpm-lock.yaml | ||
| tsconfig.json | ||
| vite.config.ts | ||
README.md
Encrypted P2P Chat - Frontend
SolidJS frontend with Vite, TypeScript, and Tailwind CSS v4.
Requirements
- Node.js 20.19+ or 22.12+ (required for Vite 7)
Tech Stack
- SolidJS 1.9.10 - Fine-grained reactivity
- TypeScript 5.9 - Type safety
- Vite 7 - Build tool (ESM only, requires Node 20.19+)
- Tailwind CSS v4.1 - Utility-first CSS (stable release)
- @solidjs/router - Client-side routing
- @tanstack/solid-query 5.90 - Data fetching and caching
- nanostores 1.1 - State management
Development
npm install
npm run dev
Frontend runs on http://localhost:3000
Build
npm run build
Output in dist/ directory.
SolidJS Routing
Unlike React Router, SolidJS uses:
<A>component for navigation (not<Link>)useNavigate()for programmatic navigationuseParams()for route parametersuseSearchParams()for query parameters
Environment Variables
Copy .env.example to .env and configure:
VITE_API_URL- Backend API URLVITE_WS_URL- WebSocket URLVITE_RP_ID- WebAuthn Relying Party ID