Files
redlight/README.md
Michelle e43e7f5fc5
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m7s
Build & Push Docker Image / build (release) Successful in 6m14s
fix: update license information to GNU GPL v3 in README, package.json, and package-lock.json
fix: Add valkey to compose in case system is too old for DragonflyDB
2026-03-13 12:11:32 +01:00

21 KiB

🔴 Redlight

⚠️ Warning: This project is entirely vibe coded and meant to be a fun/hobby project. Use at your own risk!

A modern, self-hosted BigBlueButton frontend with 25+ themes, federation, calendar, CalDAV, OAuth/OIDC, and powerful room management.

Node.js React License BigBlueButton

Features

Core Features

  • 🎥 Video Conferencing - Integrated BigBlueButton support for professional video meetings
  • 🎨 25+ Themes - Dracula, Nord, Catppuccin, Rosé Pine, Gruvbox, Tokyo Night, Solarized, Everforest, Ayu, Kanagawa, Moonlight, Cyberpunk, Cotton Candy, and more
  • 📝 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
  • 📊 Learning Analytics - Collect and view per-room participant engagement data (talk time, messages, reactions) via BBB callbacks, secured with HMAC tokens
  • 📅 Calendar - Built-in calendar with event creation, sharing, customizable reminders, and room linking
  • 📆 CalDAV Server - Full CalDAV support for syncing calendars with Thunderbird, Apple Calendar, GNOME Calendar, DAVx⁵ (Android), and other standard clients
  • 🌍 Multi-Language Support - German (Deutsch) and English built-in, easily extensible
  • 🔔 In-App Notifications - Real-time notifications for room shares, federation invites, and calendar reminders
  • ✉️ Email Verification - Optional SMTP-based email verification for user registration
  • 🔑 OAuth / OIDC - Login via OpenID Connect providers (Keycloak, Authentik, etc.) with PKCE
  • 👤 User Profiles - Customizable display names, avatars, themes, and language preferences
  • 📱 Responsive Design - Works seamlessly on mobile, tablet, and desktop
  • 🌐 Federation - Invite users from remote Redlight instances via Ed25519-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
  • ✉️ Invite-Only Registration - Generate invite tokens for controlled user signup

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
  • 📊 Learning Analytics - Toggle per-room to collect participant engagement data after each meeting
  • 📑 Presentation Upload - Upload PDF, PPTX, ODP, DOC, DOCX as default slides
  • 🤝 Room Sharing - Share rooms with other registered users

Security

  • 🛡️ Comprehensive Rate Limiting - Login, register, profile, avatar, guest-join, OAuth, and federation endpoints
  • 🔒 Input Validation - Email format, field length limits, ID format checks, 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
  • 🔏 HMAC-Secured Callbacks - Learning analytics callback URLs signed with HMAC-SHA256

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 25+ customizable themes Limited theming
Learning Analytics Per-room engagement data Not supported
Calendar / CalDAV Built-in calendar + CalDAV sync Not supported
OAuth / OIDC OpenID Connect (PKCE) Supported
Federation Cross-instance invites Not supported
Notifications In-app + calendar reminders Not supported
Language Support Multi-language ready Multi-language ready
UI Framework React + Tailwind (Modern) Rails-based (Traditional)
User Preferences Theme, language, avatar, display name 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
Presentation Upload Supported Supported
API RESTful JSON API RESTful API
Setup Complexity Simple (5 min) Moderate (10-15 min)
Customization Easy (Tailwind CSS) Requires Ruby/Rails

🚀 Quick Start

Prerequisites

  • Docker & Docker Compose
  • BigBlueButton server (with API access)
  • SMTP server (optional, for email verification)

Installation

  1. Clone the repository

    git clone https://git.scrunkly.cat/Michelle/redlight
    cd redlight
    
  2. Configure environment

    cp .env.example .env
    

    Edit .env with your settings:

    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://redlight:redlight@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
    
    # Optional: OAuth / OIDC login
    # OAUTH_ISSUER=https://auth.your-domain.com/realms/your-realm
    # OAUTH_CLIENT_ID=redlight
    # OAUTH_CLIENT_SECRET=your-client-secret
    
  3. Start the application

    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

    npm install
    
  2. Start development server

    npm run dev
    
  3. Build for production

    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
  • CalDAV: xml2js-based WebDAV/CalDAV server
  • Auth: JWT + OAuth/OIDC (PKCE)
  • Build: Vite

📁 Project Structure

redlight/
├── server/                 # Node.js/Express backend
│   ├── config/            # Database, Redis, mailer, BBB, federation, OAuth & notification config
│   ├── i18n/              # Server-side translations (email templates)
│   ├── jobs/              # Background jobs (federation sync, calendar reminders)
│   ├── middleware/        # JWT authentication, logging & token blacklisting
│   ├── routes/            # API endpoints (auth, rooms, recordings, admin, branding,
│   │                      #   federation, calendar, caldav, notifications, oauth, analytics)
│   └── index.js           # Server entry point
├── src/                   # React frontend
│   ├── components/        # Reusable components (RecordingList, AnalyticsList, etc.)
│   ├── contexts/          # React context (Auth, Language, Theme, Branding, Notification)
│   ├── i18n/              # Translations (DE, EN)
│   ├── pages/             # Page components
│   ├── services/          # API client
│   ├── themes/            # 25+ theme definitions
│   └── main.jsx           # Frontend entry point
├── public/                # Static assets
├── uploads/               # User avatars, branding & presentations (runtime)
├── keys/                  # Federation Ed25519 key pair (auto-generated)
├── 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
  • OAuth / OIDC - OpenID Connect with PKCE (S256) and cryptographic state tokens
  • 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, OAuth, and federation endpoints
  • Input Validation - Email regex, field length limits, ID format checks, 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
  • HMAC-Secured Callbacks - Learning analytics callback URLs signed with HMAC-SHA256 derived from BBB_SECRET
  • Admin Isolation - Role-based access control with strict admin checks
  • Network Isolation - Docker Compose uses an internal backend network for DB and cache

📦 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 (incl. learning analytics toggle)
  • 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/status - 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
  • DELETE /api/rooms/:uid/presentation - Remove presentation

Recordings

  • GET /api/recordings/room/:uid - List room recordings
  • PUT /api/recordings/:recordID/publish - Publish/unpublish recording
  • DELETE /api/recordings/:recordID - Delete recording

Learning Analytics

  • POST /api/analytics/callback/:uid?token=... - BBB callback (HMAC-secured)
  • GET /api/analytics/room/:uid - Get analytics for a room
  • DELETE /api/analytics/:id - Delete analytics entry

Calendar

  • GET /api/calendar - List calendar events
  • POST /api/calendar - Create event
  • PUT /api/calendar/:uid - Update event
  • DELETE /api/calendar/:uid - Delete event
  • GET /api/calendar/caldav-tokens - List CalDAV tokens
  • POST /api/calendar/caldav-tokens - Create CalDAV token
  • DELETE /api/calendar/caldav-tokens/:id - Delete CalDAV token

Notifications

  • GET /api/notifications - List notifications
  • PUT /api/notifications/:id/read - Mark as read
  • POST /api/notifications/read-all - Mark all as read
  • DELETE /api/notifications/:id - Delete notification

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

OAuth

  • GET /api/oauth/url - Get OAuth authorization URL
  • GET /api/oauth/callback - OAuth callback (PKCE exchange)

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

CalDAV

  • PROPFIND /caldav/ - CalDAV discovery
  • REPORT /caldav/:user/calendar/ - Calendar query
  • GET/PUT/DELETE /caldav/:user/calendar/:uid.ics - Event CRUD

🌍 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 25+ themes:

  • ☀️ Light / 🌙 Dark (default)
  • 🐱 Catppuccin Mocha / Latte
  • 🧛 Dracula
  • ❄️ Nord
  • 🌊 Tokyo Night
  • 💜 One Dark
  • 🐙 GitHub Dark
  • 🌹 Rosé Pine / Rosé Pine Dawn
  • 🍂 Gruvbox Dark / Gruvbox Light
  • ☀️ Solarized Dark / Solarized Light
  • 🌲 Everforest Dark / Everforest Light
  • 🌊 Kanagawa
  • 🌙 Moonlight
  • 🎮 Cyberpunk
  • 🌸 Ayu Dark
  • 🔴 Red Modular Light
  • 🍬 Cotton Candy Light
  • 🐱 scrunkly.cat Dark

Themes are fully customizable by editing src/themes/index.js.


🐳 Docker Deployment

docker compose up -d

Services:

  • redlight - Node.js application (port 3001)
  • postgres - PostgreSQL 17 database
  • dragonfly - DragonflyDB (Redis-compatible) for JWT blacklisting

The compose.yml uses isolated networks: frontend (public) and backend (internal, no external access). Data is persisted via named volumes (pgdata, uploads, dragonflydata). Federation keys are mounted from ./keys.

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)
OAUTH_ISSUER No - OIDC issuer URL (enables OAuth login)
OAUTH_CLIENT_ID No - OIDC client ID
OAUTH_CLIENT_SECRET No - OIDC client secret
ADMIN_EMAIL No admin@example.com Default admin email (first start only)
ADMIN_PASSWORD No admin123 Default admin password (first start only)

Production Deployment

Behind a reverse proxy (nginx example):

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 Ed25519 key pair is generated automatically and stored in keys/federation_key.pem.
  3. In Docker, mount ./keys:/app/keys (already configured in compose.yml).
  4. 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 Ed25519 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:

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 GNU GPL v3 (or later) - see 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