A secure, high-performance chat system built with Rust, featuring real-time messaging, end-to-end encryption support, and TCP, WebSocket, and REST API interfaces.
- Real-time messaging via persistent TCP or WebSocket connections with server-pushed events
- REST API for authentication, CRUD operations, and queries
- WebSocket support for browser-compatible real-time connections through HTTP proxies
- Terminal-based client with modern TUI interface (supports both TCP and WebSocket)
- Room-based chat with invitations and membership management
- Direct messaging between users
- Role-based access control (Admin, Moderator, User)
- Native TLS/HTTPS support for HTTP API (rustls)
- End-to-end encryption support (AES-256-GCM with X25519 key exchange)
- Argon2id password hashing for secure credential storage
- JWT authentication with session management
- Rate limiting and input validation
- Protocol-first design - TCP and HTTP protocols fully documented for any client
- Clean architecture - Domain-driven design with trait-based abstractions
- Async throughout - Built on Tokio for high performance
- SQLite storage - With migration support and connection pooling
- Cross-platform - Linux, macOS, Windows (see Platform Support)
- Comprehensive tests - 800+ unit and integration tests with CI/CD
- Rust 1.88+ (rustup.rs)
# Clone the repository
git clone https://github.com/berrym/lair-chat.git
cd lair-chat
# Start the server (TCP on 8080, HTTP on 8082)
cargo run --package lair-chat-serverThe server exposes three protocols:
- HTTP API (
http://localhost:8082) - Authentication, room management, message history - TCP (
localhost:8080) - Real-time messaging and presence (with E2E encryption option) - WebSocket (
ws://localhost:8082/ws) - Real-time messaging through HTTP (browser-compatible)
For HTTPS, see Transport Security.
# In another terminal (default: TCP transport)
cargo run --package lair-chat-client
# Use WebSocket transport (works through HTTP proxies)
cargo run --package lair-chat-client -- --websocket
# Or with custom HTTP URL (for HTTPS)
cargo run --package lair-chat-client -- --http-url https://localhost:8082 --insecureThe TUI client authenticates via HTTP and connects to TCP (default) or WebSocket (--websocket) for real-time messaging.
Environment variables:
LAIR_TCP_PORT=8080 # TCP server port (real-time messaging)
LAIR_HTTP_PORT=8082 # HTTP server port (auth, CRUD, queries)
LAIR_DATABASE_URL=sqlite:lair-chat.db # Database path
LAIR_JWT_SECRET=secret # JWT signing secret (auto-generated if not set)
RUST_LOG=info # Log level (error, warn, info, debug, trace)
# TLS/HTTPS (optional)
LAIR_TLS_ENABLED=true # Enable HTTPS (default: false)
LAIR_TLS_CERT_PATH=/path/to/cert.pem # Certificate file
LAIR_TLS_KEY_PATH=/path/to/key.pem # Private key fileLair Chat uses a protocol responsibility split (see ADR-013):
- HTTP: Authentication, CRUD operations, queries (stateless, standard tooling)
- TCP: Real-time messaging, presence, events (persistent connections, low latency)
┌─────────────────────────────────────────────────────────────────────────────┐
│ LAIR CHAT SERVER │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ PROTOCOL ADAPTERS │ │
│ │ │ │
│ │ ┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐│ │
│ │ │ HTTP :8082 │ │ WebSocket :8082 │ │ TCP :8080 ││ │
│ │ │ ───────────────── │ │ ───────────────── │ │ ───────────────── ││ │
│ │ │ - Auth (login) │ │ - Real-time msgs │ │ - Real-time msgs ││ │
│ │ │ - Room CRUD │ │ - Events (push) │ │ - E2E encryption ││ │
│ │ │ - Message history │ │ - Pre-auth token │ │ - Events (push) ││ │
│ │ │ - User queries │ │ - Browser-compat │ │ - Presence ││ │
│ │ │ - Invitations │ │ │ │ - Typing ││ │
│ │ └─────────┬─────────┘ └─────────┬─────────┘ └─────────┬─────────┘│ │
│ │ │ │ │ │ │
│ └─────────────┼──────────────────────┼──────────────────────┼──────────┘ │
│ │ │ │ │
│ └──────────────────────┼──────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ CORE ENGINE │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Auth │ │ Messaging │ │ Room │ │ Session │ │ │
│ │ │ Service │ │ Service │ │ Service │ │ Manager │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────────────┐│ │
│ │ │ Event Dispatcher ││ │
│ │ │ (broadcasts to connected clients) ││ │
│ │ └─────────────────────────────────────────────────────────────────┘│ │
│ └───────────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ STORAGE LAYER │ │
│ │ (SQLite) │ │
│ │ Users · Rooms · Messages · Sessions · Invitations · Memberships │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌────────┐ ┌──────────┐ ┌────────┐
│ Client │ │ HTTP │ │ TCP │
└───┬────┘ └────┬─────┘ └───┬────┘
│ │ │
│── POST /auth/login ─────────▶│ │
│◀── JWT Token + User ─────────│ │
│ │ │
│── GET /rooms ───────────────▶│ │
│◀── Room List ────────────────│ │
│ │ │
│─────────────────── TCP Connect ────────────────────────────▶│
│◀────────────────── ServerHello ─────────────────────────────│
│─────────────────── ClientHello ────────────────────────────▶│
│─────────────────── Authenticate(jwt) ──────────────────────▶│
│◀────────────────── AuthenticateResponse ────────────────────│
│ │ │
│◀═══════════════════ Real-time Events ══════════════════════▶│
lair-chat/
├── Cargo.toml # Workspace root
├── crates/
│ ├── lair-chat-server/ # Server implementation
│ │ └── src/
│ │ ├── main.rs # Unified binary entry point
│ │ ├── domain/ # Pure domain types (User, Room, Message, etc.)
│ │ ├── core/ # Business logic services
│ │ ├── storage/ # SQLite repository implementations
│ │ ├── adapters/ # Protocol adapters
│ │ │ ├── tcp/ # TCP real-time protocol (with E2E encryption)
│ │ │ ├── http/ # REST API (handlers, middleware)
│ │ │ └── ws/ # WebSocket real-time protocol
│ │ ├── crypto/ # AES-256-GCM encryption, X25519 key exchange
│ │ └── config/ # Configuration management
│ │
│ └── lair-chat-client/ # TUI client
│ └── src/
│ ├── main.rs # Client entry point
│ ├── app.rs # Application state
│ ├── protocol/ # TCP and WebSocket protocol implementations
│ └── components/ # TUI screens (login, chat, rooms)
│
└── docs/
├── architecture/ # Architecture documentation
│ ├── OVERVIEW.md # System design overview
│ ├── DECISIONS.md # Architecture Decision Records (ADRs)
│ ├── DOMAIN_MODEL.md # Entity definitions
│ ├── COMMANDS.md # All operations
│ └── EVENTS.md # Real-time events
└── protocols/ # Protocol specifications
├── TCP.md # TCP wire protocol (real-time, E2E encryption)
├── HTTP.md # REST API specification
└── WEBSOCKET.md # WebSocket protocol (browser-compatible)
Lair Chat is designed to be protocol-first. You can implement clients in any language using the documented protocols:
- HTTP API - RESTful JSON API for auth, CRUD, queries
- TCP Protocol - Length-prefixed JSON for real-time messaging (with E2E encryption)
- WebSocket Protocol - Plain JSON over WebSocket for browser-compatible real-time messaging
# Health check
curl http://localhost:8082/health
# Register a new user
curl -X POST http://localhost:8082/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"alice","email":"alice@example.com","password":"Secret123!"}'
# Login and get JWT token
curl -X POST http://localhost:8082/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"identifier":"alice","password":"Secret123!"}'
# Response: {"user":{...},"session":{...},"token":"eyJ..."}
# List rooms (with JWT token)
curl http://localhost:8082/api/v1/rooms \
-H "Authorization: Bearer eyJ..."
# Create a room
curl -X POST http://localhost:8082/api/v1/rooms \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJ..." \
-d '{"name":"General","description":"General chat room"}'
# Get message history
curl "http://localhost:8082/api/v1/messages?target_type=room&target_id=ROOM_ID" \
-H "Authorization: Bearer eyJ..."After authenticating via HTTP, connect to TCP for real-time messaging:
// 1. Connect to TCP port 8080, receive ServerHello
// 2. Send ClientHello
{"type":"client_hello","version":"1.1","client_name":"My Client"}
// 3. Authenticate with JWT from HTTP login
{"type":"authenticate","request_id":"1","token":"eyJ..."}
// 4. Send messages in real-time
{"type":"send_message","request_id":"2","target":{"type":"room","room_id":"..."},"content":"Hello!"}
// 5. Receive real-time events (pushed by server)
{"type":"message_received","message":{...}}
{"type":"user_online","user_id":"...","username":"bob"}See docs/protocols/TCP.md for the complete wire protocol specification.
# Run all tests (800+ tests)
cargo test --workspace
# Run server tests only
cargo test --package lair-chat-server
# Run with logging
RUST_LOG=debug cargo test --workspace
# Run specific test
cargo test --package lair-chat-server test_send_message# Format code
cargo fmt --all
# Run clippy
cargo clippy --workspace
# Build release
cargo build --release --workspace
# Run with debug logging
RUST_LOG=debug cargo run --package lair-chat-serverContributions are welcome! Please see CONTRIBUTING.md for guidelines.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Production Deployment - Deployment guide, platform support, security
- Manual Testing Guide - Verify TLS, encryption, and client functionality
- Architecture Overview - High-level system design
- Architecture Decisions - ADRs explaining why choices were made
- Domain Model - Entity definitions and relationships
- TCP Protocol - Real-time wire protocol with E2E encryption
- WebSocket Protocol - Browser-compatible real-time protocol
- HTTP API - REST API specification
MIT License - see LICENSE for details.
Built with Rust