Version 2.51.0 | A privacy-first, federated communication platform inspired by Google Wave.
"Can't stop the signal."
| Term | Description |
|---|---|
| Wave | A conversation container |
| Ping | An individual message |
| Thread | An isolated reply chain within a wave |
| Crew | A user group |
cd server
npm install
cp .env.example .env # Edit with your settings
npm startServer runs at http://localhost:3001
cd client
npm install
npm run devClient runs at http://localhost:3000
Demo accounts (password: Demo123!, requires SEED_DEMO_DATA=true):
mal- Malcolm Reynolds (Admin)zoe,wash,kaylee,jayne,inara,simon,river
- Waves — Conversation containers with threaded pings
- Focus View — View any ping with replies as its own wave-like context
- Threading — Isolate reply chains within a wave for focused conversations
- Untabbed navigation — Wave list clicks open a preview; pin to promote to a persistent tab (max 10)
- Crews & Contacts — Organize connections with request/invitation workflows
- Wave Categories — User-defined categories with drag-and-drop organization
- Search — Full-text search across all pings (SQLite FTS5)
- Inline emoji autocomplete — Type
:shortcode:to pick from 826 emoji; closing colon auto-inserts - PWA — Installable app with offline support and push notifications
- Notification Sync — Client-side polling catches missed notifications when push is unreliable
- Notification Preferences — Per-type controls (mentions, replies, wave activity) with always/app-closed/never levels
- Collapsible Messages — Collapse long messages to compact previews
- Support Tickets — Unauthenticated ticket submission from the login screen; admin management panel
- Wave calendar — Attach events to any wave with date, time, location, and description
- Recurring events — Daily, weekly, monthly, and yearly recurrence patterns
- RSVP — Accept, decline, or mark tentative; organizer sees attendee responses
- Reminders — Configurable push notifications before events
- ECDH P-384 + AES-256-GCM — Per-wave symmetric keys distributed via key exchange
- Zero-knowledge server — Server never sees plaintext message content
- Key rotation — Automatic re-encryption when participants are removed
- Migration UI — Bulk re-encryption of existing messages when enabling E2EE on a wave
- Web Crypto API — Native browser cryptography, no external libraries
- Email protection — Hashed (SHA-256) + encrypted (AES-256-GCM), never stored in plaintext
- IP anonymization — Truncated to /24 subnet before storage
- User-Agent truncation — Only browser and OS retained
- Timestamp rounding — Activity rounded to 15-min windows, sessions to 5-min
- Encrypted metadata — Wave participation, crew membership, push subscriptions encrypted at rest
- Client-encrypted contacts — Only the user can decrypt their own contact list
- Ghost Protocol — PIN-protected hidden waves with cryptographic participation deniability
- Data retention — Activity logs and sessions auto-deleted after 30 days (configurable)
- No third-party tracking — No analytics, no ads, no third-party cookies
See docs/PRIVACY.md for the full privacy policy.
- Server-to-server — Multiple Cortex instances exchange pings across the Verse
- Federated users — Add
@user@other-server.comas wave participants - HTTP Signatures — RSA-SHA256 signed requests for server authentication
- Cover traffic — Decoy messages, message padding, and queue jitter resist traffic analysis
- Trust model — Manual allowlist of trusted federation partners (Allied Ports)
- Voice/Video messages — Record and send audio (5 min) and video messages
- Voice/Video calls — Real-time calls via LiveKit with screen sharing
- Rich embeds — YouTube, Spotify, Vimeo, Twitter, SoundCloud
- Images & GIFs — Upload, paste, or search via Tenor/GIPHY
- Media server integration — Jellyfin, Emby, and Plex with OAuth and HLS transcoding
- S3-compatible storage — Optional S3/MinIO backend for uploads
- Stock ticker — Real-time quotes from Finnhub API
- Weather data — Current conditions from OpenWeatherMap
- Breaking news — Headlines from NewsAPI.org and GNews.io
- Admin alerts — Scheduled system alerts with priority levels
- Holiday effects — Automatic seasonal celebrations with themed alerts and visual effects
- Custom themes — Visual theme editor, gallery, create/share/install themes
- Firefly personality — Easter eggs and themed UI throughout
- Outgoing webhooks — Forward wave messages to Discord, Slack, Teams
- Incoming webhooks — Discord-compatible webhook URLs; point GitHub, Grafana, Uptime Kuma, etc. at Cortex with no code changes
- JWT authentication with configurable session duration, silent renewal, and grace-period re-auth
- End-to-end encryption (ECDH P-384 + AES-256-GCM)
- Multi-factor authentication (TOTP and email-based 2FA)
- Role-based access control (Admin / Moderator / User)
- Password recovery via email
- Rate limiting on all endpoints with persistent account lockout
- HTML sanitization, Helmet.js security headers, HSTS
- HTTP Signature verification for federation
- GDPR compliance — data export ("Ship's Manifest") and account deletion ("Abandon Ship")
- Post pings to waves using
Authorization: Bearer bot_<key>authentication - Wave-scoped posting tokens as a lightweight alternative to full bot accounts
- New keys use
bot_prefix; legacyfh_bot_andcx_bot_keys remain valid
Both native clients are thin wrappers that load https://cortex.farhold.com (or a configured server URL) directly — there are no bundled web assets. UI updates are live on next launch without reinstalling.
- Loads the configured server URL in a BrowserWindow (
https://cortex.farhold.comby default) - External links and embedded media open in the OS default browser via
shell.openExternal() - Custom server URL saved to
~/.config/Cortex/server-url.txt - macOS:
hiddenInsettitle bar with inset traffic lights - Deep links via
cortex://protocol
See docs/BUILD-NATIVE.md for build instructions.
capacitor.config.tssetsserver.url: 'https://cortex.farhold.com'— the WebView loads from the live server- Push notifications via FCM with
priority: highto bypass Android Doze mode - Links open in the system browser; media plays natively
See docs/BUILD-NATIVE.md for build instructions.
cortex/
├── server/
│ ├── server.js # Express + WebSocket server
│ ├── database-sqlite.js # SQLite database layer
│ ├── email-service.js # Email provider abstraction
│ ├── storage.js # File/S3 storage abstraction
│ ├── schema.sql # Database schema
│ ├── holidays.js # Holiday detection for alerts
│ └── data/ # Data storage
├── client/
│ ├── CortexApp.jsx # Root React component
│ ├── electron/
│ │ ├── main.js # Electron main process
│ │ └── preload.cjs # Electron preload (IPC bridge)
│ ├── capacitor.config.ts # Capacitor config (iOS/Android)
│ └── src/
│ ├── views/ # Page-level components
│ ├── components/ # Feature components (admin, calls, media, etc.)
│ ├── hooks/ # Custom React hooks (API, WebSocket, etc.)
│ ├── services/ # Voice call service
│ ├── config/ # Constants, emoji data, holidays, theme config
│ └── utils/ # Shared utilities
├── landing/
│ ├── index.html # Landing page (static)
│ └── nginx.conf # Nginx config for landing + app
└── docs/ # API docs, privacy policy, build instructions
Create server/.env (see .env.example for full list):
# Required
PORT=3001
JWT_SECRET=your-secret-key # Generate: node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
# Database
USE_SQLITE=true # SQLite (recommended)
SEED_DEMO_DATA=true # Create demo accounts
# Security
ALLOWED_ORIGINS=https://your-domain.com
# Privacy encryption keys (generate each: openssl rand -hex 32)
EMAIL_ENCRYPTION_KEY=<32-byte-hex>
WAVE_PARTICIPATION_KEY=<32-byte-hex>
PUSH_SUBSCRIPTION_KEY=<32-byte-hex>
CREW_MEMBERSHIP_KEY=<32-byte-hex>
# GIF Search
GIF_PROVIDER=tenor # giphy, tenor, or both
TENOR_API_KEY=your-key
GIPHY_API_KEY=your-key
# Push Notifications (optional)
VAPID_PUBLIC_KEY=your-public-key
VAPID_PRIVATE_KEY=your-private-key
VAPID_EMAIL=mailto:admin@example.com
# Federation (optional)
FEDERATION_ENABLED=false
FEDERATION_NODE_NAME=cortex.example.com
# Email Service (optional — required for password reset and email MFA)
EMAIL_PROVIDER=smtp # smtp, sendgrid, or mailgun
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
EMAIL_FROM=noreply@yourdomain.com
# Crawl Bar APIs (optional)
FINNHUB_API_KEY=your-key # Stock quotes
OPENWEATHERMAP_API_KEY=your-key # Weather data
NEWSAPI_KEY=your-key # News headlines
GNEWS_API_KEY=your-key # News headlines (backup)
# Support tickets (optional)
SUPPORT_WAVE_ID=thread-xxxxxxxx # Wave to post ticket notifications to
SUPPORT_POSTING_TOKEN=bot_... # Preferred: wave-scoped posting token
SUPPORT_BOT_KEY=bot_... # Fallback: bot API key| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/register |
Create account |
| POST | /api/auth/login |
Login (returns JWT) |
| POST | /api/auth/logout |
Logout current session |
| POST | /api/auth/renew |
Silent token renewal (no password) |
| POST | /api/auth/reauth |
Grace-period re-authentication (requires password) |
| GET | /api/auth/me |
Current user info |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/waves |
List waves |
| POST | /api/waves |
Create wave |
| GET | /api/waves/:id |
Get wave with pings |
| POST | /api/waves/:id/pings |
Send ping |
| PUT | /api/pings/:id |
Edit ping (supports E2EE fields) |
| DELETE | /api/pings/:id |
Delete ping |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/waves/:id/events |
List wave events |
| POST | /api/waves/:id/events |
Create event |
| PUT | /api/events/:id |
Update event |
| DELETE | /api/events/:id |
Delete event |
| POST | /api/events/:id/rsvp |
RSVP to event |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/contacts/request |
Send contact request |
| POST | /api/contacts/requests/:id/accept |
Accept request |
| POST | /api/crews/:id/invite |
Invite to crew |
| POST | /api/crews/invitations/:id/accept |
Accept invitation |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/notifications |
List notifications |
| GET | /api/notifications/count |
Get unread count by type |
| GET | /api/notifications/pending |
Poll for undelivered notifications |
| PUT | /api/notifications/preferences |
Update notification preferences |
| POST | /api/notifications/read-all |
Mark all read |
| DELETE | /api/notifications |
Dismiss all notifications |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/bot/ping |
Post a ping as a bot (Authorization: Bearer bot_<key>) |
| GET | /api/bot/waves |
List bot-accessible waves |
| GET | /api/bot/waves/:id |
Get wave details |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/support/ticket |
Submit ticket (public, rate-limited 5/hr) |
| GET | /api/admin/support/tickets |
List tickets — admin only |
| PATCH | /api/admin/support/tickets/:id/resolve |
Resolve ticket — admin only |
| PATCH | /api/admin/support/tickets/:id/reopen |
Reopen ticket — admin only |
See docs/API.md for complete API documentation.
# Install PM2
npm install -g pm2
# Build client
cd client && npm run build
# Start server
cd server && pm2 start server.js --name cortex-api
# Auto-start on boot
pm2 startup && pm2 saveA reference nginx config is provided at landing/nginx.conf. It sets up:
- farhold.com — serves the landing page from
landing/index.html - cortex.farhold.com — proxies to client (port 3000) and server API/WebSocket/uploads (port 3001)
- HTTP → HTTPS redirect for all domains
# Symlink into nginx sites
sudo ln -s /path/to/cortex/landing/nginx.conf /etc/nginx/sites-enabled/cortex
# Get SSL certs
sudo certbot --nginx -d farhold.com -d www.farhold.com -d cortex.farhold.com
# Test and reload
sudo nginx -t && sudo nginx -s reloadTo adapt for your own domain, replace farhold.com / cortex.farhold.com with your domains and update the SSL cert paths.
Nginx Proxy Manager Note: Disable "Cache Assets" to prevent profile images from breaking.
| Level | Icon | Description |
|---|---|---|
| Private | ◉ | Only invited participants |
| Crew | ◈ | All crew members |
| Cross-Server | ◇ | Federated across the Verse |
| Public | ○ | Public waves |
- CHANGELOG.md — Complete version history
- docs/API.md — API endpoint documentation
- docs/BUILD-NATIVE.md — Desktop and mobile build instructions
- docs/DEPLOYMENT.md — Hardened VPS deployment guide (LUKS, SQLCipher, backups)
- docs/PRIVACY.md — Privacy policy
- OUTSTANDING-FEATURES.md — Future roadmap
MIT License — See LICENSE file for details.