# πŸ”΄ Redlight A modern, self-hosted BigBlueButton frontend with beautiful themes, federation, and powerful features. ![Node.js](https://img.shields.io/badge/Node.js-20+-green) ![React](https://img.shields.io/badge/React-18+-blue) ![License](https://img.shields.io/badge/License-MIT-yellow) ![BigBlueButton](https://img.shields.io/badge/BigBlueButton-Compatible-red) ## ✨ Features ### Core Features - πŸŽ₯ **Video Conferencing** – Integrated BigBlueButton support for professional video meetings - 🎨 **15+ Themes** – Dracula, Nord, Catppuccin, RosΓ© Pine, Gruvbox, and more (extensible via volume mount) - πŸ“ **Room Management** – Create unlimited rooms with custom settings, access codes, and moderator codes - πŸ” **User Management** – Registration, login, role-based access control (Admin/User) - πŸ“Ή **Recording Management** – View, publish, and delete meeting recordings per room - 🌍 **Multi-Language Support** – German (Deutsch) and English built-in, easily extensible - βœ‰οΈ **Email Verification** – Optional SMTP-based email verification for user registration - πŸ‘€ **User Profiles** – Customizable avatars, themes, and language preferences - πŸ“± **Responsive Design** – Works seamlessly on mobile, tablet, and desktop - 🌐 **Federation** – Invite users from remote Redlight instances via RSA-signed messages - πŸ‰ **DragonflyDB / Redis** – JWT blacklisting for secure token revocation on logout ### Admin Features - πŸ‘₯ **User Administration** – Manage users and roles - 🏒 **Branding Customization** – Custom app name, logos, and default theme - πŸ“Š **Dashboard** – Overview of system statistics - πŸ”§ **Settings Management** – System-wide configuration ### Room Features - πŸ”‘ **Access Codes** – Restrict room access with optional passwords - πŸ” **Moderator Codes** – Separate code to grant moderator privileges - πŸšͺ **Guest Access** – Allow unauthenticated users to join meetings (rate-limited) - ⏱️ **Max Participants** – Set limits on concurrent participants - 🎀 **Mute on Join** – Automatically mute new participants - βœ… **Approval Mode** – Require moderator approval for participants - πŸŽ™οΈ **Anyone Can Start** – Allow participants to start the meeting - πŸ“Ή **Recording Settings** – Control whether meetings are recorded - πŸ“Š **Presentation Upload** – Upload PDF, PPTX, ODP, or image files as default slides - 🀝 **Room Sharing** – Share rooms with other registered users ### Security - πŸ›‘οΈ **Comprehensive Rate Limiting** – Login, register, profile, avatar, guest-join, and federation endpoints - πŸ”’ **Input Validation** – Email format, field length limits, theme/language allowlists, color format validation - πŸ• **Timing-Safe Comparisons** – Access codes and moderator codes compared with `crypto.timingSafeEqual` - πŸ“ **Streaming Upload Limits** – Avatar (5 MB) and presentation (50 MB) uploads reject early without buffering - 🧹 **XSS Prevention** – HTML-escaped emails, XML-escaped BBB parameters, SVG sanitization - πŸ” **JWT Blacklist** – Token revocation via DragonflyDB/Redis on logout - 🌐 **CORS Restriction** – Locked to `APP_URL` in production - βš™οΈ **Configurable Trust Proxy** – `TRUST_PROXY` env var for reverse proxy setups ### Developer Features - 🐳 **Docker Support** – Easy deployment with Docker Compose (includes PostgreSQL + DragonflyDB) - πŸ—„οΈ **Database Flexibility** – SQLite (default) or PostgreSQL support - πŸ”Œ **REST API** – Comprehensive API for custom integrations - πŸ“¦ **Open Source** – Full source code transparency - πŸ› οΈ **Self-Hosted** – Complete data privacy and control --- ## πŸ“Š Comparison: Redlight vs Greenlight | Feature | Redlight | Greenlight | |---------|----------|-----------| | **Theme System** | 15+ customizable themes | Limited theming | | **Federation** | βœ… Cross-instance invites | ❌ Not supported | | **Language Support** | Multi-language ready | Multi-language ready | | **UI Framework** | React + Tailwind (Modern) | Rails-based (Traditional) | | **User Preferences** | Theme, language, avatar | Limited customization | | **Database Options** | SQLite / PostgreSQL | PostgreSQL only | | **Docker** | βœ… Supported | βœ… Supported | | **Admin Dashboard** | Modern React UI | Legacy Rails interface | | **Room Sharing** | βœ… Share rooms with users | βœ… Supported | | **Recording Management** | Full control per room | Standard management | | **API** | RESTful JSON API | RESTful API | | **Setup Complexity** | Simple (5 min) | Moderate (10-15 min) | | **Customization** | Easy (Tailwind CSS) | Requires Ruby/Rails | | **Community** | doesn't exist lol | Established | --- ## πŸš€ Quick Start ### Prerequisites - Docker & Docker Compose - BigBlueButton server (with API access) - SMTP server (optional, for email verification) ### Installation 1. **Clone the repository** ```bash git clone https://git.scrunkly.cat/Michelle/redlight cd redlight ``` 2. **Configure environment** ```bash cp .env.example .env ``` Edit `.env` with your settings: ```env BBB_URL=https://your-bbb-server.com/bigbluebutton/api/ BBB_SECRET=your-bbb-shared-secret JWT_SECRET=your-secret-key # REQUIRED – app won't start without this APP_URL=https://your-domain.com # Used for CORS and email links DATABASE_URL=postgres://user:password@postgres:5432/redlight POSTGRES_USER=redlight POSTGRES_PASSWORD=redlight POSTGRES_DB=redlight # DragonflyDB / Redis (JWT blacklist for logout) REDIS_URL=redis://dragonfly:6379 # Reverse proxy trust (default: loopback) # TRUST_PROXY=loopback # Optional: Email verification SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_USER=your-email@gmail.com SMTP_PASS=your-app-password # Optional: Federation (cross-instance room invites) # FEDERATION_DOMAIN=your-domain.com ``` 3. **Start the application** ```bash docker-compose up -d ``` 4. **Access the application** - Open `http://localhost:3001` in your browser - Default admin: `admin@example.com` / `admin123` - Change password immediately! --- ## πŸ› οΈ Development ### Local Setup 1. **Install dependencies** ```bash npm install ``` 2. **Start development server** ```bash npm run dev ``` - Frontend: http://localhost:5173 - Backend: http://localhost:3001 3. **Build for production** ```bash npm run build npm run preview ``` ### Tech Stack - **Frontend**: React 18, Tailwind CSS, React Router, Lucide Icons - **Backend**: Node.js 20, Express, JWT, Bcrypt - **Database**: SQLite / PostgreSQL with better-sqlite3 / pg - **Cache**: DragonflyDB / Redis (ioredis) – JWT blacklisting - **Email**: Nodemailer - **Build**: Vite --- ## πŸ“ Project Structure ``` redlight/ β”œβ”€β”€ server/ # Node.js/Express backend β”‚ β”œβ”€β”€ config/ # Database, Redis, mailer, BBB & federation config β”‚ β”œβ”€β”€ middleware/ # JWT authentication & token blacklisting β”‚ β”œβ”€β”€ routes/ # API endpoints (auth, rooms, recordings, admin, branding, federation) β”‚ └── index.js # Server entry point β”œβ”€β”€ src/ # React frontend β”‚ β”œβ”€β”€ components/ # Reusable components β”‚ β”œβ”€β”€ contexts/ # React context (Auth, Language, Theme, Branding) β”‚ β”œβ”€β”€ i18n/ # Translations (DE, EN) β”‚ β”œβ”€β”€ pages/ # Page components β”‚ β”œβ”€β”€ services/ # API client β”‚ β”œβ”€β”€ themes/ # Tailwind theme config (volume-mountable) β”‚ └── main.jsx # Frontend entry point β”œβ”€β”€ public/ # Static assets β”œβ”€β”€ uploads/ # User avatars, branding & presentations (runtime) β”œβ”€β”€ compose.yml # Docker Compose (Redlight + PostgreSQL + DragonflyDB) β”œβ”€β”€ Dockerfile # Multi-stage container image └── package.json # Dependencies ``` --- ## πŸ” Security - **JWT Authentication** – Secure token-based auth with 7-day expiration and `jti`-based blacklisting via DragonflyDB/Redis - **Mandatory JWT Secret** – Server refuses to start without a `JWT_SECRET` env var - **HTTPS Ready** – Configure behind reverse proxy (nginx, Caddy); trust proxy via `TRUST_PROXY` env - **Password Hashing** – bcryptjs with salt rounds 12, minimum 8-character passwords - **Email Verification** – Optional SMTP-based email verification with resend support - **CORS Protection** – Restricted to `APP_URL` in production, open in development - **Rate Limiting** – Login, register, profile, password, avatar, guest-join, and federation endpoints - **Input Validation** – Email regex, field length limits, theme/language allowlists, hex-color format checks - **Timing-Safe Comparisons** – Access codes and moderator codes compared via `crypto.timingSafeEqual` - **Upload Safety** – Streaming body size limits (avatar 5 MB, presentation 50 MB) abort early without buffering - **XSS / Injection Prevention** – HTML-escaped emails, XML-escaped BBB API parameters, SVG logos served as `attachment` - **Admin Isolation** – Role-based access control with strict admin checks --- ## πŸ“¦ API Endpoints ### Authentication - `POST /api/auth/register` – Register new user - `POST /api/auth/login` – Login user - `POST /api/auth/logout` – Logout (blacklists JWT) - `GET /api/auth/verify-email?token=...` – Verify email with token - `POST /api/auth/resend-verification` – Resend verification email - `GET /api/auth/me` – Get current user info - `PUT /api/auth/profile` – Update profile (theme, language, display name) - `PUT /api/auth/password` – Change password - `POST /api/auth/avatar` – Upload avatar image - `DELETE /api/auth/avatar` – Remove avatar image ### Rooms - `GET /api/rooms` – List user's rooms (owned + shared) - `POST /api/rooms` – Create new room - `GET /api/rooms/:uid` – Get room details - `PUT /api/rooms/:uid` – Update room - `DELETE /api/rooms/:uid` – Delete room - `POST /api/rooms/:uid/start` – Start meeting - `POST /api/rooms/:uid/join` – Join meeting as authenticated user - `POST /api/rooms/:uid/guest-join` – Join meeting as guest (rate-limited) - `POST /api/rooms/:uid/end` – End meeting - `GET /api/rooms/:uid/running` – Check if meeting is running - `GET /api/rooms/:uid/shares` – List shared users - `POST /api/rooms/:uid/shares` – Share room with user - `DELETE /api/rooms/:uid/shares/:userId` – Remove share - `POST /api/rooms/:uid/presentation` – Upload default presentation (PDF, PPTX, ODP, images) - `DELETE /api/rooms/:uid/presentation` – Remove presentation ### Recordings - `GET /api/recordings/:roomUid` – List room recordings - `PUT /api/recordings/:recordingId` – Publish/unpublish recording - `DELETE /api/recordings/:recordingId` – Delete recording ### Admin - `GET /api/admin/users` – List all users - `GET /api/admin/stats` – System statistics - `POST /api/admin/users` – Create user (admin) - `PUT /api/admin/users/:id` – Update user - `DELETE /api/admin/users/:id` – Delete user ### Branding - `GET /api/branding` – Get branding settings - `PUT /api/branding` – Update branding (admin only) - `POST /api/branding/logo` – Upload custom logo - `DELETE /api/branding/logo` – Remove custom logo ### Federation - `GET /.well-known/redlight` – Instance discovery (domain, public key) - `POST /api/federation/invite` – Send invitation to remote user - `POST /api/federation/receive` – Receive invitation from remote instance (rate-limited) - `GET /api/federation/invitations` – List received invitations - `PUT /api/federation/invitations/:id` – Accept / decline invitation - `DELETE /api/federation/invitations/:id` – Delete invitation --- ## 🌍 Internationalization (i18n) Redlight comes with built-in support for multiple languages. Currently supported: - πŸ‡©πŸ‡ͺ Deutsch (German) - πŸ‡¬πŸ‡§ English ### Adding a new language 1. Create `src/i18n/xx.json` (e.g., `fr.json` for French) 2. Copy structure from `de.json` or `en.json` 3. Translate all strings 4. Update `src/i18n/index.js` to include the new language --- ## 🎨 Themes Redlight includes the following themes: - πŸŒ™ Dracula - ❄️ Nord - 🐱 Catppuccin - 🌹 RosΓ© Pine - πŸ‚ Gruvbox (Dark, Light) - πŸ’œ One Dark - 🌊 Tokyo Night - And more... Themes are fully customizable by editing `src/themes/index.js`. --- ## 🐳 Docker Deployment ### Using Docker Compose (Recommended) ```bash docker-compose up -d ``` Services: - **redlight** – Node.js application - **postgres** – PostgreSQL database - **dragonfly** – DragonflyDB (Redis-compatible) for JWT blacklisting ### Environment Variables | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `BBB_URL` | Yes | – | BigBlueButton API URL | | `BBB_SECRET` | Yes | – | BigBlueButton shared secret | | `JWT_SECRET` | Yes | – | Secret for signing JWTs (server won't start without it) | | `APP_URL` | Recommended | – | Public URL of the app (used for CORS + email links) | | `DATABASE_URL` | No | SQLite | PostgreSQL connection string | | `REDIS_URL` | No | `redis://localhost:6379` | DragonflyDB / Redis URL | | `TRUST_PROXY` | No | `loopback` | Express trust proxy setting (number or string) | | `SMTP_HOST` | No | – | SMTP server for email verification | | `SMTP_PORT` | No | `587` | SMTP port | | `SMTP_USER` | No | – | SMTP username | | `SMTP_PASS` | No | – | SMTP password | | `FEDERATION_DOMAIN` | No | – | Domain for federation (enables cross-instance invites) | ### Production Deployment Behind a reverse proxy (nginx example): ```nginx upstream redlight { server localhost:3001; } server { listen 443 ssl http2; server_name your-domain.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; client_max_body_size 5M; location / { proxy_pass http://redlight; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` > **Note:** When running behind a reverse proxy, set `TRUST_PROXY=1` (or the appropriate value) in `.env` so Express reads the correct client IP for rate limiting. --- ## 🌐 Federation Federation allows users on different Redlight instances to invite each other into rooms. ### Setup 1. Set `FEDERATION_DOMAIN=your-domain.com` in `.env`. 2. On first start, an RSA 2048-bit key pair is generated automatically and stored in `server/config/federation_key.pem`. 3. Other instances discover your public key via `GET /.well-known/redlight`. ### How it works 1. **User A** on `instance-a.com` sends an invite to `userB@instance-b.com`. 2. Redlight looks up `instance-b.com/.well-known/redlight` to discover the federation API. 3. The invite payload is signed with instance A's private key and POSTed to instance B's `/api/federation/receive`. 4. Instance B verifies the RSA signature against instance A's public key. 5. **User B** sees the invitation and can accept or decline. Accepting provides a join link to the remote room. --- ## πŸ› Troubleshooting ### Issue: "ERR_ERL_PERMISSIVE_TRUST_PROXY" **Solution**: Set `TRUST_PROXY` in `.env`. Use `loopback` (default) or `1` when behind a single reverse proxy. ### Issue: "JWT_SECRET is not set" **Solution**: The server requires a `JWT_SECRET` environment variable and will refuse to start without one. Add it to your `.env` file. ### Issue: "Email verification not working" **Solution**: Ensure SMTP is configured in `.env`. If `SMTP_HOST` is not set, email verification is disabled. ### Issue: "BigBlueButton API error" **Solution**: Verify `BBB_URL` and `BBB_SECRET` are correct. Test the connection with: ```bash curl "https://your-bbb-server/bigbluebutton/api/getMeetings?checksum=..." ``` ### Issue: "Database connection failed" **Solution**: Check `DATABASE_URL` format. For PostgreSQL: `postgres://user:password@host:5432/redlight` ### Issue: "Theme not applying" **Solution**: Clear browser cache (Ctrl+Shift+Del) or restart dev server with `npm run dev`. ### Issue: "DragonflyDB connection error" **Solution**: Ensure DragonflyDB (or Redis) is running and `REDIS_URL` is correct. If unavailable, the app still works β€” JWT blacklisting degrades gracefully (logout won't revoke tokens immediately). --- ## πŸ“ License This project is licensed under the MIT License – see [LICENSE](LICENSE) file for details. --- ## 🀝 Contributing Contributions are welcome! Please feel free to submit a Pull Request. 1. Fork the repository 2. Create a feature branch (`git checkout -b feature/amazing-feature`) 3. Commit changes (`git commit -m 'Add amazing feature'`) 4. Push to branch (`git push origin feature/amazing-feature`) 5. Open a Pull Request