GitHub description: π GhostChat β Encrypted Chat System. Powered by No Location. Built with React, TypeScript, Tailwind and Convex.
GhostChat is a privacy-first encrypted messaging web app. Every message is sealed on your device with AES-256-GCM, keys are derived on-device through ECDH P-256, and the server only ever relays ciphertext and wrapped keys β it cannot read what you send. Your identity is a ghost handle and an on-device keypair: no phone number, no email required for the chat layer.
- π End-to-end encryption β AES-256-GCM with ECDH P-256 key agreement, sealed on-device
- π Wrapped conversation keys β each conversation key is sealed separately per member; the server never sees raw keys
- π¬ Real-time delivery β reactive subscriptions push messages instantly, no polling
- β³ Disappearing messages β per-conversation timer (Off / 1h / 24h / 7d), filtered server-side
- β©οΈ Replies & reactions β quote any message; react with emoji, tally visible to everyone
- π₯ Group-ready conversations β try-each-member key unwrap supports DMs and groups
- π« Blocking & reporting β block any handle (their conversations are hidden) and report abuse
- π‘οΈ Verify keys β compare per-contact key fingerprints out-of-band to detect MITM
- π Privacy-focused notifications β only when the tab is hidden, and the body never contains plaintext
- π΅ Secure storage toggle β choose whether encrypted history is backed up to the cloud or stays on-device
- π± Device log β see every device logged into your encrypted chats, keyed by fingerprint
- πͺ Remote logout β revoke unfamiliar devices from Settings
- π VPN settings β on/off tunnel toggle with fastest-server auto-selection
- π Server browser β US, Europe, South America and Asia-Pacific endpoints
- π Private VPN API β point GhostVPN at your own WireGuard/OpenVPN manager
- π¨ Profile with attachable avatar β display name + 96Γ96 avatar, stored client-resized
- π Dark mode β on/off/auto, follows your system preference by default
| Layer | Tech |
|---|---|
| Frontend | Vite Β· React 19 Β· TypeScript Β· Tailwind v4 |
| UI | shadcn/ui Β· Lucide icons Β· Framer Motion |
| Backend | Convex (queries, mutations, reactive subs) |
| Auth | Convex Auth (anonymous β free & accountless) |
| Crypto | WebCrypto (ECDH P-256, AES-256-GCM, PBKDF2) |
bun install
bun dev # Vite dev server + Convex dev- Identity β on first run the app generates an ECDH P-256 keypair. The private key is wrapped with PBKDF2 (310,000 iterations) from your passphrase and stored only in your browser. The server receives the public key and your handle β nothing else.
- Conversations β the creator generates a random 256-bit conversation key and wraps it once per member (ECDH-derived KEK). Members unwrap it with their own private key.
- Messages β every message is sealed with AES-256-GCM using the conversation key. The server stores ciphertext, IVs and wrapped keys only.
β οΈ Your passphrase is unrecoverable. If you lose it, your messages cannot be decrypted on that device β there is no backdoor by design.
src/
βββ convex/ # Convex backend (schema, chat, settings, auth)
βββ pages/ # Landing, Auth, Chat, Dashboard, NotFound
βββ components/ # SettingsDialog (profile/storage/security/keys/VPN) + ui/
βββ lib/ # crypto.ts β E2E identity, key wrapping, message crypto
βββ hooks/ # use-auth, use-mobile
- Use bun as the package manager.
- All Convex functions live in
src/convex/; push them withbunx convex dev. - Auth is pre-wired with email OTP and anonymous providers via Convex Auth
(
src/convex/auth.ts). Environment variablesCONVEX_DEPLOYMENTandVITE_CONVEX_URLare already configured on the client; the backend has its own auth keys (JWKS, JWT_PRIVATE_KEY, SITE_URL). - Frontend typecheck:
bunx tsc -b --noEmitΒ· Backend push:bunx convex dev --once