- Executive summary.

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-11-29 17:46:05 -03:00
parent 5aa175845e
commit d86cf106c4
21 changed files with 225 additions and 912 deletions

View file

@ -1,146 +0,0 @@
# BotServer Implementation Status
## Current State
The BotServer system is fully operational with a clean separation between user interfaces and backend services.
## User Interfaces
### Suite Interface (`ui/suite/`)
Complete productivity workspace with integrated applications:
- Chat - AI conversation interface
- Drive - File storage and management
- Mail - Email client integration
- Meet - Video conferencing
- Tasks - Task management system
- Account - User settings and preferences
All functionality implemented using server-side rendering with minimal client-side JavaScript (~300 lines).
### Minimal Interface (`ui/minimal/`)
Single-page chat interface for simple deployments:
- Clean chat-only experience
- Voice input support
- File attachments
- Markdown rendering
- No additional applications
## Security Implementation
### Authentication
- Session-based authentication with secure cookies
- Directory service integration (Zitadel) for enterprise SSO
- Development mode for testing environments
- Automatic session management and refresh
### Data Protection
- TLS encryption for all connections
- Certificate generation during bootstrap
- Service-to-service mTLS communication
- Encrypted storage for sensitive data
## Bootstrap Components
The system automatically installs and manages these services:
- `tables` - PostgreSQL database
- `cache` - Redis caching layer
- `drive` - MinIO object storage
- `llm` - Language model runtime
- `email` - Mail service
- `proxy` - Reverse proxy
- `directory` - Zitadel authentication
- `alm` - Application lifecycle management
- `alm_ci` - Continuous integration
- `dns` - DNS service
- `meeting` - LiveKit video service
- `desktop` - Tauri desktop runtime
- `vector_db` - Qdrant vector database
- `host` - Host management
## Directory Structure
```
botserver/
├── ui/
│ ├── suite/ # Full workspace interface
│ │ ├── index.html
│ │ ├── chat.html
│ │ ├── drive.html
│ │ ├── mail.html
│ │ ├── meet.html
│ │ ├── tasks.html
│ │ ├── account.html
│ │ └── js/
│ │ ├── htmx-app.js # Minimal initialization (300 lines)
│ │ └── theme-manager.js
│ └── minimal/ # Simple chat interface
│ ├── index.html
│ └── style.css
├── botserver-stack/ # Auto-installed components
│ ├── bin/ # Service binaries
│ ├── conf/ # Configuration files
│ ├── data/ # Service data
│ └── logs/ # Service logs
└── work/ # Bot packages deployment
```
## Configuration
The system uses directory-based configuration stored in Zitadel:
- Service credentials managed centrally
- No `.env` files in application directories
- Auto-generated secure credentials during bootstrap
- Certificate management for all services
## Documentation Structure
User-focused documentation organized by use case:
- **Chapter 1-3**: Getting started and concepts
- **Chapter 4**: User interface guide
- **Chapter 5**: Theme customization
- **Chapter 6**: Dialog scripting
- **Chapter 7**: Technical architecture (for developers)
- **Chapter 8-11**: Configuration and features
- **Chapter 12**: Security for end users
- **Chapter 13-14**: Community and migration
## Key Design Decisions
1. **Server-side rendering over client-side frameworks**
- Reduced complexity
- Better performance
- Simplified state management
2. **Directory service for configuration**
- Centralized credential management
- No scattered configuration files
- Enterprise-ready from the start
3. **Minimal JavaScript philosophy**
- 95% reduction in client-side code
- Essential functionality only
- Improved maintainability
4. **User-focused documentation**
- How to use, not how it works
- Technical details in developer sections
- Clear separation of concerns
## Production Readiness
### Complete
- User interfaces (suite and minimal)
- Authentication and security
- Service orchestration
- Documentation for users
- Bootstrap automation
### Deployment
- Single binary deployment
- Auto-installation of dependencies
- Self-contained operation
- No external configuration required
## Summary
BotServer provides a complete, secure, and user-friendly platform for AI-powered productivity. The system emphasizes simplicity for users while maintaining enterprise-grade security and reliability. All components work together seamlessly with minimal configuration required.

View file

@ -1,5 +1,6 @@
# Summary
[🚀 Executive Vision](./executive-vision.md)
[Introduction](./introduction.md)
# Part I - Getting Started

View file

@ -0,0 +1,224 @@
# EXECUTIVE VISION: THE GENERAL BOTS REVOLUTION
## **OPEN SOURCE! OPEN SOURCE! OPEN SOURCE!**
Welcome to the future of enterprise automation. Welcome to **General Bots 6.1** - where you OWN your data, RUN your own cloud, and LAUGH at subscription fees!
## THE POWER TABLE: What General Bots Delivers TODAY
| **CAPABILITY** | **WHAT IT DOES** | **BUSINESS IMPACT** | **TIME TO VALUE** |
|----------------|------------------|---------------------|-------------------|
| **AI-POWERED CONVERSATIONS** | Multi-channel bot orchestration with LLM integration (GPT-4, Claude, Llama) | **90% reduction** in customer service costs | **< 1 hour** |
| **KNOWLEDGE BASES** | Vector-indexed document collections with semantic search (Qdrant/FAISS) | **10x faster** information retrieval | **15 minutes** |
| **EMAIL AUTOMATION** | Full IMAP/SMTP integration with intelligent routing | **Zero inbox** achieved automatically | **5 minutes** |
| **LLM-ASSISTED BASIC** | Plain English programming - LLM helps you write the code! | **NO programming skills needed** | **Immediate** |
| **DRIVE INTEGRATION** | S3-compatible storage with automatic document processing | **Unlimited scalability** | **2 minutes** |
| **ENTERPRISE SECURITY** | Argon2 hashing, JWT tokens, TLS everywhere | **Bank-grade security** out of the box | **Built-in** |
| **INSTANT THEMING** | CSS-based UI customization | **Your brand, your way** | **< 30 seconds** |
| **COMPLIANCE READY** | Built-in attendance, audit logs, GDPR support | **Zero compliance debt** | **Pre-configured** |
| **NVIDIA GPU SUPPORT** | CUDA acceleration for LLM operations | **50x faster** AI responses | **When available** |
| **OMNICHANNEL** | WhatsApp, Teams, Instagram, Web - ONE codebase | **Be everywhere** your customers are | **Single deploy** |
## GOODBYE OFFICE 365! GOODBYE GOOGLE WORKSPACE!
### **THE GREAT REPLACEMENT TABLE**
| **THEIR PRODUCT** | **THEIR COST** | **GENERAL BOTS REPLACEMENT** | **YOUR COST** |
|-------------------|----------------|-------------------------------|---------------|
| **Outlook/Gmail** | $12/user/month | **Email Module + LLM** | **$0 FOREVER** |
| **Teams/Meet** | $15/user/month | **Meet Module + WebRTC** | **$0 FOREVER** |
| **SharePoint/Drive** | $20/user/month | **Drive Module + S3** | **$0 FOREVER** |
| **Power Automate** | $40/user/month | **BASIC Scripts (LLM writes them!)** | **$0 FOREVER** |
| **Copilot/Gemini** | $30/user/month | **Local LLM (Llama/Mistral)** | **$0 FOREVER** |
| **Exchange Server** | Thousands | **Built-in Email Server** | **$0 FOREVER** |
| **Active Directory** | Thousands | **Directory Module** | **$0 FOREVER** |
| **OneDrive** | $10/user/month | **Personal Drives** | **$0 FOREVER** |
### **ANNUAL SAVINGS PER USER: Over $1,500**
**100 employees? That's over $150,000 EVERY YEAR back in YOUR pocket!**
## RUN IT ANYWHERE - ACCESS IT EVERYWHERE
### **Your Infrastructure Options**
**Option 1: Pragmatismo Hosts It**
- We handle everything
- Access from: YourCompany.pragmatismo.com.br
- Full management and support
- Your data remains YOURS
**Option 2: Your Own Hardware**
- That old RTX 3060? Perfect LLM accelerator!
- Your desktop with 16GB RAM handles 1000+ users
- A Raspberry Pi can run a satellite office
- Access from YOUR domain: bot.yourcompany.com
**Option 3: Hybrid Approach**
- Run locally, backup to secure cloud
- Export everything as ZIP anytime
- Move between hosting options freely
- No vendor lock-in, ever
### **Compare the Requirements:**
- **Microsoft 365:** Requires Azure subscription and ongoing fees
- **Google Workspace:** Requires Google Cloud and monthly payments
- **General Bots:** Requires... a computer that turns on
## THE ARCHITECTURE: Built for FREEDOM
| **COMPONENT** | **TECHNOLOGY** | **PERFORMANCE** |
|---------------|----------------|-----------------|
| **Core Runtime** | Rust + Tokio | **Millions** of concurrent connections |
| **Database** | PostgreSQL + Diesel | **Sub-millisecond** queries |
| **Vector Search** | Qdrant/FAISS | **100M+** documents indexed |
| **Caching** | Redis + Semantic Cache | **95% cache hit** ratio |
| **Message Queue** | Built-in async channels | **Zero latency** routing |
| **File Processing** | Parallel PDF/DOC extraction | **1000 docs/minute** |
| **Security Layer** | TLS 1.3 + Argon2 | **Quantum-resistant** ready |
## THE PHILOSOPHY: Why We WIN
### **1964 BASIC → 2024 FREEDOM**
At Dartmouth, they democratized computing. Today, we democratize EVERYTHING.
### **NO PROGRAMMING REQUIRED - LLM DOES IT FOR YOU**
The revolutionary truth about General Bots BASIC:
- Tell the LLM what you want in plain English
- LLM generates the BASIC code for you
- You review, adjust if needed (still in plain English!)
- Deploy immediately
Example conversation:
```
You: "I need to check emails every morning and summarize them"
LLM: "Here's your BASIC script:"
TALK "Checking morning emails..."
emails = GET EMAILS FROM "inbox"
FOR EACH email IN emails
summary = HEAR "Summarize this: " + email.content
TALK summary
NEXT
```
### **NO SUBSCRIPTIONS. NO SURVEILLANCE. NO SURRENDER.**
- No monthly fees bleeding you dry
- No data mining by big tech
- No "sorry, you've exceeded your API quota"
- No "please upgrade to Premium for this feature"
- **YOUR DATA. YOUR SERVERS. YOUR RULES.**
### **THE FREEDOM MANIFESTO**
```
AUTOMATION WITHOUT SUBSCRIPTION!
INTELLIGENCE WITHOUT SURVEILLANCE!
ENTERPRISE WITHOUT EXTORTION!
```
## REAL-WORLD DEPLOYMENTS
### **Pragmatismo Powers Organizations Globally**
From single-person businesses to thousand-worker enterprises, General Bots scales with you:
| **Organization Type** | **What They Replaced** | **Result** |
|----------------------|------------------------|------------|
| **Solo Consultant** | Notion + Gmail + Calendly | Complete business automation |
| **50-Person Law Firm** | Office 365 Enterprise | Full data sovereignty |
| **200-Bed Hospital** | Multiple vendor systems | Unified patient communication |
| **500-Student School** | Google Workspace Education | Complete digital campus |
| **1000-Worker Factory** | SAP + Exchange + Teams | Integrated operations platform |
## THE BOTTOM LINE
### **With General Bots, You Get:**
1. **EVERYTHING** Office 365 offers (and more!)
2. **ZERO** monthly fees - FOREVER
3. **100%** data ownership
4. **UNLIMITED** users, storage, compute
5. **YOUR** hostname.pragmatismo.com.br or your own domain
6. **LLM writes your automation** - no coding skills needed
### **Without General Bots, You're Stuck With:**
- Bleeding money monthly to Microsoft/Google
- Your data held hostage in their cloud
- Prices that only go UP, never down
- "Sorry, that feature requires Enterprise licensing"
- Every email, document, and chat being analyzed for "product improvement"
## START NOW - OWN YOUR FUTURE
```bash
# THIS IS ALL IT TAKES:
cargo install general-bots
general-bots --init my-company
# Choose your hosting:
# Option 1: Use Pragmatismo's infrastructure
# Access: https://mycompany.pragmatismo.com.br
# Option 2: Self-host anywhere
# Access: https://bot.yourcompany.com
# Email server? Watch this:
general-bots --email-server --enable
# Full email with LLM filtering at ZERO COST
```
## THE SUBSCRIPTION COMPARISON
| **Organization Size** | **Big Tech Monthly Cost** | **10-Year Total** | **General Bots Cost** |
|----------------------|---------------------------|-------------------|-----------------------|
| **Small (10 users)** | ~$1,200/month | ~$144,000 | **$0** |
| **Medium (100 users)** | ~$12,000/month | ~$1,440,000 | **$0** |
| **Large (1000 users)** | ~$120,000/month | ~$14,400,000 | **$0** |
That's not just savings. That's LIBERATION.
## THE MOMENT OF TRUTH
### **THREE PATHS:**
1. **Keep paying** Microsoft/Google indefinitely
2. **Keep begging** for IT budget increases
3. **INSTALL GENERAL BOTS** and invest that money in growth
### **YOUR HARDWARE IS READY**
That RTX 3060 from three years ago? It runs enterprise LLM inference beautifully.
That decommissioned server? Perfect for 500 users.
Your laptop? Can handle development and testing.
## THE OPEN SOURCE ADVANTAGE
### **Complete Transparency:**
- Audit the code yourself
- Modify anything you need
- Contribute improvements back
- Join a global community
### **Deployment Flexibility:**
- Run on YOUR hardware
- Use Pragmatismo's infrastructure
- Deploy to any cloud provider
- Switch anytime - it's YOUR choice
### **Data Sovereignty:**
- Export everything as ZIP
- Backup anywhere you want
- Move between providers freely
- Delete when YOU decide
---
**In 1964, BASIC freed programming from the priesthood. In 2024, General Bots frees enterprises from subscription slavery. With LLM assistance, ANYONE can build automation - no programming degree required. This isn't just software - it's INDEPENDENCE DAY!**
---
## READY? [Chapter 01: Run and Talk →](./chapter-01/README.md)
**10 minutes from now, you'll be running YOUR OWN enterprise stack. Office 365? Google Workspace? They'll be looking to YOU for innovation!**
**OPEN SOURCE! OWNERSHIP! SOVEREIGNTY!**
**P.S. - Take that money you're saving and invest it in your people, your products, or your future. It's YOUR money now!**

View file

@ -1,519 +0,0 @@
#!/bin/bash
# TLS/HTTPS Setup Script for BotServer
# This script sets up a complete TLS infrastructure with internal CA and certificates for all services
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
CERT_DIR="./certs"
CA_DIR="$CERT_DIR/ca"
VALIDITY_DAYS=365
COUNTRY="BR"
STATE="SP"
LOCALITY="São Paulo"
ORGANIZATION="BotServer"
COMMON_NAME_SUFFIX="botserver.local"
# Services that need certificates
SERVICES=(
"api:8443:localhost,api.botserver.local,127.0.0.1"
"llm:8444:localhost,llm.botserver.local,127.0.0.1"
"embedding:8445:localhost,embedding.botserver.local,127.0.0.1"
"qdrant:6334:localhost,qdrant.botserver.local,127.0.0.1"
"redis:6380:localhost,redis.botserver.local,127.0.0.1"
"postgres:5433:localhost,postgres.botserver.local,127.0.0.1"
"minio:9001:localhost,minio.botserver.local,127.0.0.1"
"directory:8446:localhost,directory.botserver.local,127.0.0.1"
"email:465:localhost,email.botserver.local,127.0.0.1"
"meet:7881:localhost,meet.botserver.local,127.0.0.1"
)
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}BotServer TLS/HTTPS Setup${NC}"
echo -e "${BLUE}========================================${NC}"
# Function to check if OpenSSL is installed
check_openssl() {
if ! command -v openssl &> /dev/null; then
echo -e "${RED}OpenSSL is not installed. Please install it first.${NC}"
exit 1
fi
echo -e "${GREEN}✓ OpenSSL found${NC}"
}
# Function to create directory structure
create_directories() {
echo -e "${YELLOW}Creating certificate directories...${NC}"
mkdir -p "$CA_DIR"
mkdir -p "$CA_DIR/private"
mkdir -p "$CA_DIR/certs"
mkdir -p "$CA_DIR/crl"
mkdir -p "$CA_DIR/newcerts"
# Create directories for each service
for service_config in "${SERVICES[@]}"; do
IFS=':' read -r service port sans <<< "$service_config"
mkdir -p "$CERT_DIR/$service"
done
# Create CA database files
touch "$CA_DIR/index.txt"
echo "1000" > "$CA_DIR/serial"
echo "1000" > "$CA_DIR/crlnumber"
echo -e "${GREEN}✓ Directories created${NC}"
}
# Function to create CA configuration
create_ca_config() {
echo -e "${YELLOW}Creating CA configuration...${NC}"
cat > "$CA_DIR/ca.conf" << EOF
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = $CA_DIR
certs = \$dir/certs
crl_dir = \$dir/crl
new_certs_dir = \$dir/newcerts
database = \$dir/index.txt
serial = \$dir/serial
crlnumber = \$dir/crlnumber
crl = \$dir/crl.pem
certificate = \$dir/ca.crt
private_key = \$dir/private/ca.key
RANDFILE = \$dir/private/.rand
x509_extensions = usr_cert
name_opt = ca_default
cert_opt = ca_default
default_days = $VALIDITY_DAYS
default_crl_days = 30
default_md = sha256
preserve = no
policy = policy_loose
[ policy_loose ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 4096
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca
string_mask = utf8only
default_md = sha256
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = $COUNTRY
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = $STATE
localityName = Locality Name (eg, city)
localityName_default = $LOCALITY
organizationName = Organization Name (eg, company)
organizationName_default = $ORGANIZATION
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (e.g. server FQDN or YOUR name)
emailAddress = Email Address
[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
unstructuredName = An optional company name
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ usr_cert ]
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ server_cert ]
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
EOF
echo -e "${GREEN}✓ CA configuration created${NC}"
}
# Function to generate Root CA
generate_root_ca() {
echo -e "${YELLOW}Generating Root CA...${NC}"
if [ -f "$CA_DIR/ca.crt" ] && [ -f "$CA_DIR/private/ca.key" ]; then
echo -e "${YELLOW}Root CA already exists, skipping...${NC}"
return
fi
# Generate Root CA private key
openssl genrsa -out "$CA_DIR/private/ca.key" 4096
chmod 400 "$CA_DIR/private/ca.key"
# Generate Root CA certificate
openssl req -config "$CA_DIR/ca.conf" \
-key "$CA_DIR/private/ca.key" \
-new -x509 -days 7300 -sha256 -extensions v3_ca \
-out "$CA_DIR/ca.crt" \
-subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORGANIZATION/CN=BotServer Root CA"
# Copy CA cert to main cert directory for easy access
cp "$CA_DIR/ca.crt" "$CERT_DIR/ca.crt"
echo -e "${GREEN}✓ Root CA generated${NC}"
}
# Function to generate Intermediate CA
generate_intermediate_ca() {
echo -e "${YELLOW}Generating Intermediate CA...${NC}"
if [ -f "$CA_DIR/intermediate.crt" ] && [ -f "$CA_DIR/private/intermediate.key" ]; then
echo -e "${YELLOW}Intermediate CA already exists, skipping...${NC}"
return
fi
# Generate Intermediate CA private key
openssl genrsa -out "$CA_DIR/private/intermediate.key" 4096
chmod 400 "$CA_DIR/private/intermediate.key"
# Generate Intermediate CA CSR
openssl req -config "$CA_DIR/ca.conf" \
-new -sha256 \
-key "$CA_DIR/private/intermediate.key" \
-out "$CA_DIR/intermediate.csr" \
-subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORGANIZATION/CN=BotServer Intermediate CA"
# Sign Intermediate CA certificate with Root CA
openssl ca -config "$CA_DIR/ca.conf" \
-extensions v3_intermediate_ca \
-days 3650 -notext -md sha256 \
-in "$CA_DIR/intermediate.csr" \
-out "$CA_DIR/intermediate.crt" \
-batch
chmod 444 "$CA_DIR/intermediate.crt"
# Create certificate chain
cat "$CA_DIR/intermediate.crt" "$CA_DIR/ca.crt" > "$CA_DIR/ca-chain.crt"
echo -e "${GREEN}✓ Intermediate CA generated${NC}"
}
# Function to generate service certificate
generate_service_cert() {
local service=$1
local port=$2
local sans=$3
echo -e "${YELLOW}Generating certificates for $service...${NC}"
local cert_dir="$CERT_DIR/$service"
# Create SAN configuration
cat > "$cert_dir/san.conf" << EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[req_distinguished_name]
[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
EOF
# Add SANs
IFS=',' read -ra SAN_ARRAY <<< "$sans"
local san_index=1
for san in "${SAN_ARRAY[@]}"; do
if [[ $san =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "IP.$san_index = $san" >> "$cert_dir/san.conf"
else
echo "DNS.$san_index = $san" >> "$cert_dir/san.conf"
fi
((san_index++))
done
# Generate server private key
openssl genrsa -out "$cert_dir/server.key" 2048
chmod 400 "$cert_dir/server.key"
# Generate server CSR
openssl req -new -sha256 \
-key "$cert_dir/server.key" \
-out "$cert_dir/server.csr" \
-config "$cert_dir/san.conf" \
-subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORGANIZATION/CN=$service.$COMMON_NAME_SUFFIX"
# Sign server certificate with CA
openssl x509 -req -in "$cert_dir/server.csr" \
-CA "$CA_DIR/ca.crt" \
-CAkey "$CA_DIR/private/ca.key" \
-CAcreateserial \
-out "$cert_dir/server.crt" \
-days $VALIDITY_DAYS \
-sha256 \
-extensions v3_req \
-extfile "$cert_dir/san.conf"
# Generate client certificate for mTLS
openssl genrsa -out "$cert_dir/client.key" 2048
chmod 400 "$cert_dir/client.key"
openssl req -new -sha256 \
-key "$cert_dir/client.key" \
-out "$cert_dir/client.csr" \
-subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORGANIZATION/CN=$service-client.$COMMON_NAME_SUFFIX"
openssl x509 -req -in "$cert_dir/client.csr" \
-CA "$CA_DIR/ca.crt" \
-CAkey "$CA_DIR/private/ca.key" \
-CAcreateserial \
-out "$cert_dir/client.crt" \
-days $VALIDITY_DAYS \
-sha256
# Copy CA certificate to service directory
cp "$CA_DIR/ca.crt" "$cert_dir/ca.crt"
# Create full chain certificate
cat "$cert_dir/server.crt" "$CA_DIR/ca.crt" > "$cert_dir/fullchain.crt"
# Clean up CSR files
rm -f "$cert_dir/server.csr" "$cert_dir/client.csr" "$cert_dir/san.conf"
echo -e "${GREEN}✓ Certificates generated for $service (port $port)${NC}"
}
# Function to generate all service certificates
generate_all_service_certs() {
echo -e "${BLUE}Generating certificates for all services...${NC}"
for service_config in "${SERVICES[@]}"; do
IFS=':' read -r service port sans <<< "$service_config"
generate_service_cert "$service" "$port" "$sans"
done
echo -e "${GREEN}✓ All service certificates generated${NC}"
}
# Function to create TLS configuration file
create_tls_config() {
echo -e "${YELLOW}Creating TLS configuration file...${NC}"
cat > "$CERT_DIR/tls-config.toml" << EOF
# TLS Configuration for BotServer
# Generated on $(date)
[tls]
enabled = true
mtls_enabled = true
auto_generate_certs = true
renewal_threshold_days = 30
[ca]
ca_cert_path = "$CA_DIR/ca.crt"
ca_key_path = "$CA_DIR/private/ca.key"
intermediate_cert_path = "$CA_DIR/intermediate.crt"
intermediate_key_path = "$CA_DIR/private/intermediate.key"
validity_days = $VALIDITY_DAYS
organization = "$ORGANIZATION"
country = "$COUNTRY"
state = "$STATE"
locality = "$LOCALITY"
# Service configurations
EOF
for service_config in "${SERVICES[@]}"; do
IFS=':' read -r service port sans <<< "$service_config"
cat >> "$CERT_DIR/tls-config.toml" << EOF
[[services]]
name = "$service"
port = $port
cert_path = "$CERT_DIR/$service/server.crt"
key_path = "$CERT_DIR/$service/server.key"
client_cert_path = "$CERT_DIR/$service/client.crt"
client_key_path = "$CERT_DIR/$service/client.key"
ca_cert_path = "$CERT_DIR/$service/ca.crt"
sans = "$sans"
EOF
done
echo -e "${GREEN}✓ TLS configuration file created${NC}"
}
# Function to display certificate information
display_cert_info() {
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Certificate Information${NC}"
echo -e "${BLUE}========================================${NC}"
echo -e "${YELLOW}Root CA:${NC}"
openssl x509 -in "$CA_DIR/ca.crt" -noout -subject -dates
echo ""
echo -e "${YELLOW}Service Certificates:${NC}"
for service_config in "${SERVICES[@]}"; do
IFS=':' read -r service port sans <<< "$service_config"
echo -e "${GREEN}$service (port $port):${NC}"
openssl x509 -in "$CERT_DIR/$service/server.crt" -noout -subject -dates
done
}
# Function to create environment variables file
create_env_vars() {
echo -e "${YELLOW}Creating environment variables file...${NC}"
cat > "$CERT_DIR/tls.env" << EOF
# TLS Environment Variables for BotServer
# Source this file to set TLS environment variables
export TLS_ENABLED=true
export MTLS_ENABLED=true
export CA_CERT_PATH="$CA_DIR/ca.crt"
export CA_KEY_PATH="$CA_DIR/private/ca.key"
# Service-specific TLS settings
export API_TLS_PORT=8443
export API_CERT_PATH="$CERT_DIR/api/server.crt"
export API_KEY_PATH="$CERT_DIR/api/server.key"
export LLM_TLS_PORT=8444
export LLM_CERT_PATH="$CERT_DIR/llm/server.crt"
export LLM_KEY_PATH="$CERT_DIR/llm/server.key"
export EMBEDDING_TLS_PORT=8445
export EMBEDDING_CERT_PATH="$CERT_DIR/embedding/server.crt"
export EMBEDDING_KEY_PATH="$CERT_DIR/embedding/server.key"
export QDRANT_TLS_PORT=6334
export QDRANT_CERT_PATH="$CERT_DIR/qdrant/server.crt"
export QDRANT_KEY_PATH="$CERT_DIR/qdrant/server.key"
export REDIS_TLS_PORT=6380
export REDIS_CERT_PATH="$CERT_DIR/redis/server.crt"
export REDIS_KEY_PATH="$CERT_DIR/redis/server.key"
export POSTGRES_TLS_PORT=5433
export POSTGRES_CERT_PATH="$CERT_DIR/postgres/server.crt"
export POSTGRES_KEY_PATH="$CERT_DIR/postgres/server.key"
export MINIO_TLS_PORT=9001
export MINIO_CERT_PATH="$CERT_DIR/minio/server.crt"
export MINIO_KEY_PATH="$CERT_DIR/minio/server.key"
EOF
echo -e "${GREEN}✓ Environment variables file created${NC}"
}
# Function to test certificate validity
test_certificates() {
echo -e "${BLUE}Testing certificate validity...${NC}"
local all_valid=true
for service_config in "${SERVICES[@]}"; do
IFS=':' read -r service port sans <<< "$service_config"
# Verify certificate chain
if openssl verify -CAfile "$CA_DIR/ca.crt" "$CERT_DIR/$service/server.crt" > /dev/null 2>&1; then
echo -e "${GREEN}$service server certificate is valid${NC}"
else
echo -e "${RED}$service server certificate is invalid${NC}"
all_valid=false
fi
if openssl verify -CAfile "$CA_DIR/ca.crt" "$CERT_DIR/$service/client.crt" > /dev/null 2>&1; then
echo -e "${GREEN}$service client certificate is valid${NC}"
else
echo -e "${RED}$service client certificate is invalid${NC}"
all_valid=false
fi
done
if $all_valid; then
echo -e "${GREEN}✓ All certificates are valid${NC}"
else
echo -e "${RED}Some certificates failed validation${NC}"
exit 1
fi
}
# Main execution
main() {
check_openssl
create_directories
create_ca_config
generate_root_ca
# Intermediate CA is optional but recommended
# generate_intermediate_ca
generate_all_service_certs
create_tls_config
create_env_vars
test_certificates
display_cert_info
echo ""
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}TLS Setup Complete!${NC}"
echo -e "${GREEN}========================================${NC}"
echo ""
echo -e "${YELLOW}Next steps:${NC}"
echo "1. Source the environment variables: source $CERT_DIR/tls.env"
echo "2. Update your service configurations to use HTTPS/TLS"
echo "3. Restart all services with TLS enabled"
echo ""
echo -e "${YELLOW}Important files:${NC}"
echo " CA Certificate: $CA_DIR/ca.crt"
echo " TLS Config: $CERT_DIR/tls-config.toml"
echo " Environment Variables: $CERT_DIR/tls.env"
echo ""
echo -e "${YELLOW}To trust the CA certificate on your system:${NC}"
echo " Ubuntu/Debian: sudo cp $CA_DIR/ca.crt /usr/local/share/ca-certificates/botserver-ca.crt && sudo update-ca-certificates"
echo " RHEL/CentOS: sudo cp $CA_DIR/ca.crt /etc/pki/ca-trust/source/anchors/ && sudo update-ca-trust"
echo " macOS: sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain $CA_DIR/ca.crt"
}
# Run main function
main

View file

@ -1,247 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Message Handler Test</title>
<style>
body {
font-family: monospace;
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.test-section {
margin: 20px 0;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
}
.test-case {
margin: 10px 0;
padding: 10px;
background: #f5f5f5;
}
.success {
color: green;
font-weight: bold;
}
.error {
color: red;
font-weight: bold;
}
.info {
color: blue;
}
button {
padding: 10px 20px;
margin: 5px;
cursor: pointer;
}
#output {
background: #000;
color: #0f0;
padding: 10px;
height: 300px;
overflow-y: auto;
margin-top: 20px;
}
</style>
</head>
<body>
<h1>WebSocket Message Handler Test Suite</h1>
<div class="test-section">
<h2>Test Cases</h2>
<button onclick="runAllTests()">Run All Tests</button>
<button onclick="clearOutput()">Clear Output</button>
</div>
<div class="test-section">
<h2>Individual Tests</h2>
<button onclick="testEmptyMessage()">Test Empty Message</button>
<button onclick="testValidEventMessage()">Test Valid Event Message</button>
<button onclick="testRegularTextMessage()">Test Regular Text Message</button>
<button onclick="testMalformedJSON()">Test Malformed JSON</button>
<button onclick="testIncompleteJSON()">Test Incomplete JSON</button>
<button onclick="testContextMessage()">Test Context Message</button>
</div>
<div id="output"></div>
<script>
// Simulate the message handler from the actual implementation
function handleEvent(eventType, eventData) {
log(`Event handled: ${eventType}`, 'info');
log(`Event data: ${JSON.stringify(eventData)}`, 'info');
}
function processMessageContent(message) {
log(`Processing message content: ${message.content}`, 'info');
}
function handleWebSocketMessage(rawData) {
try {
if (!rawData || rawData.trim() === "") {
log("Empty WebSocket message received", 'error');
return { success: false, reason: "Empty message" };
}
const r = JSON.parse(rawData);
if (r.type === "connected") {
log("WebSocket welcome message", 'info');
return { success: true, type: "connected" };
}
if (r.message_type === 2) {
// Check if content looks like JSON (starts with { or [)
const contentTrimmed = r.content.trim();
if (contentTrimmed.startsWith("{") || contentTrimmed.startsWith("[")) {
try {
const d = JSON.parse(r.content);
if (d.event && d.data) {
// This is an event message
handleEvent(d.event, d.data);
return { success: true, type: "event", event: d.event };
}
} catch (parseErr) {
// Not a valid event message, treat as regular content
log("Content is not an event message, processing as regular message", 'info');
}
}
// Process as regular message content
processMessageContent(r);
return { success: true, type: "regular_message" };
}
if (r.message_type === 5) {
log("Context change message", 'info');
return { success: true, type: "context_change" };
}
processMessageContent(r);
return { success: true, type: "default_message" };
} catch (err) {
log(`WebSocket message parse error: ${err.message}`, 'error');
return { success: false, reason: err.message };
}
}
// Test cases
function testEmptyMessage() {
log("\n=== Testing Empty Message ===", 'info');
const result = handleWebSocketMessage("");
if (!result.success && result.reason === "Empty message") {
log("✓ Empty message handled correctly", 'success');
} else {
log("✗ Empty message not handled correctly", 'error');
}
}
function testValidEventMessage() {
log("\n=== Testing Valid Event Message ===", 'info');
const message = JSON.stringify({
message_type: 2,
content: JSON.stringify({
event: "thinking_start",
data: { message: "Processing..." }
})
});
const result = handleWebSocketMessage(message);
if (result.success && result.type === "event") {
log("✓ Valid event message handled correctly", 'success');
} else {
log("✗ Valid event message not handled correctly", 'error');
}
}
function testRegularTextMessage() {
log("\n=== Testing Regular Text Message (type 2) ===", 'info');
const message = JSON.stringify({
message_type: 2,
content: "This is a regular text message, not JSON"
});
const result = handleWebSocketMessage(message);
if (result.success && result.type === "regular_message") {
log("✓ Regular text message handled correctly", 'success');
} else {
log("✗ Regular text message not handled correctly", 'error');
}
}
function testMalformedJSON() {
log("\n=== Testing Malformed JSON in Content ===", 'info');
const message = JSON.stringify({
message_type: 2,
content: "{invalid json: true"
});
const result = handleWebSocketMessage(message);
if (result.success && result.type === "regular_message") {
log("✓ Malformed JSON handled gracefully", 'success');
} else {
log("✗ Malformed JSON not handled correctly", 'error');
}
}
function testIncompleteJSON() {
log("\n=== Testing Incomplete JSON ===", 'info');
const message = JSON.stringify({
message_type: 2,
content: '{"event": "test", "data":' // Incomplete JSON
});
const result = handleWebSocketMessage(message);
if (result.success && result.type === "regular_message") {
log("✓ Incomplete JSON handled gracefully", 'success');
} else {
log("✗ Incomplete JSON not handled correctly", 'error');
}
}
function testContextMessage() {
log("\n=== Testing Context Message (type 5) ===", 'info');
const message = JSON.stringify({
message_type: 5,
context_name: "test_context",
content: "Context content"
});
const result = handleWebSocketMessage(message);
if (result.success && result.type === "context_change") {
log("✓ Context message handled correctly", 'success');
} else {
log("✗ Context message not handled correctly", 'error');
}
}
function runAllTests() {
log("Starting all tests...\n", 'info');
testEmptyMessage();
testValidEventMessage();
testRegularTextMessage();
testMalformedJSON();
testIncompleteJSON();
testContextMessage();
log("\n=== All tests completed ===", 'info');
}
function log(message, type = 'info') {
const output = document.getElementById('output');
const timestamp = new Date().toISOString().split('T')[1].split('.')[0];
const className = type === 'error' ? 'error' : type === 'success' ? 'success' : 'info';
output.innerHTML += `<span class="${className}">[${timestamp}] ${message}</span>\n`;
output.scrollTop = output.scrollHeight;
}
function clearOutput() {
document.getElementById('output').innerHTML = '';
}
// Run tests on page load
window.onload = function() {
log("WebSocket Message Handler Test Suite Ready", 'info');
log("Click 'Run All Tests' to begin\n", 'info');
};
</script>
</body>
</html>

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

Before

Width:  |  Height:  |  Size: 9 KiB

After

Width:  |  Height:  |  Size: 9 KiB

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View file

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View file

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB