diff --git a/chat-service/src/controllers/ChatWebSocketController.cpp b/chat-service/src/controllers/ChatWebSocketController.cpp index dbea6ca..069251c 100644 --- a/chat-service/src/controllers/ChatWebSocketController.cpp +++ b/chat-service/src/controllers/ChatWebSocketController.cpp @@ -98,7 +98,7 @@ void ChatWebSocketController::handleNewConnection(const HttpRequestPtr& req, // Bots must send { type: "auth", apiKey: "..." } message after connecting // This prevents API keys from being logged in server access logs { - // Check for token in query params or headers + // Check for token in query params, headers, or httpOnly cookie auto token = req->getParameter("token"); LOG_DEBUG << "Token from query param: " << (token.empty() ? "(empty)" : "present"); @@ -110,6 +110,12 @@ void ChatWebSocketController::handleNewConnection(const HttpRequestPtr& req, } } + // Check httpOnly auth_token cookie (browser sends this with WebSocket upgrade request) + if (token.empty()) { + token = req->getCookie("auth_token"); + LOG_DEBUG << "Token from auth_token cookie: " << (token.empty() ? "(empty)" : "present"); + } + if (!token.empty()) { LOG_INFO << "Attempting to verify JWT token"; auto& authService = services::AuthService::getInstance(); diff --git a/openresty/nginx.conf b/openresty/nginx.conf index f8a2367..cbc2285 100644 --- a/openresty/nginx.conf +++ b/openresty/nginx.conf @@ -377,8 +377,58 @@ http { add_header Cache-Control "no-store, no-cache" always; } - # Public realm endpoints (with viewer token authentication for stream-key) - location ~ ^/api/realms/(by-name/[^/]+|live|[0-9]+/stats|[0-9]+/stream-key)$ { + # Public site settings endpoint + location = /api/settings/site { + # CORS headers + add_header Access-Control-Allow-Origin $cors_origin always; + add_header Access-Control-Allow-Methods "GET, OPTIONS" always; + add_header Access-Control-Allow-Headers "Content-Type" always; + add_header Access-Control-Allow-Credentials "true" always; + + if ($request_method = 'OPTIONS') { + add_header Content-Length 0; + add_header Content-Type text/plain; + return 204; + } + + proxy_pass http://backend; + 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; + + # Cache site settings + expires 30s; + add_header Cache-Control "public, max-age=30" always; + } + + # Public honk sound endpoint + location = /api/honk/active { + # CORS headers + add_header Access-Control-Allow-Origin $cors_origin always; + add_header Access-Control-Allow-Methods "GET, OPTIONS" always; + add_header Access-Control-Allow-Headers "Content-Type" always; + add_header Access-Control-Allow-Credentials "true" always; + + if ($request_method = 'OPTIONS') { + add_header Content-Length 0; + add_header Content-Type text/plain; + return 204; + } + + proxy_pass http://backend; + 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; + + # Short cache + expires 10s; + add_header Cache-Control "public, max-age=10" always; + } + + # Public realm endpoints - includes single realm by ID (with viewer token authentication for stream-key) + location ~ ^/api/realms/(by-name/[^/]+|live|[0-9]+|[0-9]+/stats|[0-9]+/stream-key)$ { # CORS headers add_header Access-Control-Allow-Origin $cors_origin always; add_header Access-Control-Allow-Methods "GET, OPTIONS" always; @@ -471,6 +521,7 @@ http { 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; + proxy_set_header Cookie $http_cookie; # WebSocket timeouts proxy_read_timeout 3600s; @@ -493,6 +544,7 @@ http { 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; + proxy_set_header Cookie $http_cookie; # WebSocket timeouts proxy_read_timeout 3600s; @@ -516,6 +568,7 @@ http { 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; + proxy_set_header Cookie $http_cookie; # WebSocket timeouts proxy_read_timeout 3600s; diff --git a/terraform/modules/app_server/cloud-init.yaml.tpl b/terraform/modules/app_server/cloud-init.yaml.tpl index 1e8dcb7..f191e4d 100644 --- a/terraform/modules/app_server/cloud-init.yaml.tpl +++ b/terraform/modules/app_server/cloud-init.yaml.tpl @@ -164,7 +164,6 @@ write_files: # Message of the day - path: /etc/motd content: | - +---------------------------------------------------------------+ | REALMS APP SERVER | | | @@ -176,12 +175,40 @@ write_files: | | | Commands: | | cd /opt/realms && docker compose logs -f | - | cd /opt/realms && docker compose pull && up -d | + | cd /opt/realms && docker compose pull && docker compose up -d | | +---------------------------------------------------------------+ - permissions: '0644' + # Environment file generator script (separate file to avoid YAML parsing issues) + - path: /usr/local/bin/generate-env.sh + content: | + #!/bin/bash + set -e + ENV_FILE="/opt/realms/.env" + if [ -f "$ENV_FILE" ]; then + echo ".env already exists, skipping generation" + exit 0 + fi + echo "Generating .env with secure random secrets..." + DB_PASS=$(openssl rand -base64 32 | tr -d '/+=' | head -c 32) + JWT_SEC=$(openssl rand -base64 48 | tr -d '/+=' | head -c 48) + REDIS_PASS=$(openssl rand -base64 32 | tr -d '/+=' | head -c 32) + OME_TOKEN=$(openssl rand -hex 32) + NAKAMA_KEY=$(openssl rand -hex 16) + NAKAMA_PASS=$(openssl rand -base64 16 | tr -d '/+=' | head -c 16) + { + echo "DB_PASSWORD=$DB_PASS" + echo "JWT_SECRET=$JWT_SEC" + echo "REDIS_PASSWORD=$REDIS_PASS" + echo "OME_API_TOKEN=$OME_TOKEN" + echo "NAKAMA_SERVER_KEY=$NAKAMA_KEY" + echo "NAKAMA_CONSOLE_PASSWORD=$NAKAMA_PASS" + } > "$ENV_FILE" + chmod 600 "$ENV_FILE" + echo ".env generated with secure random secrets" + permissions: '0755' + runcmd: # Ensure .ssh directory exists - mkdir -p /root/.ssh && chmod 700 /root/.ssh @@ -226,70 +253,8 @@ runcmd: - mkdir -p /opt/realms - mkdir -p /opt/realms/uploads - # Generate .env with secure random secrets (only if it doesn't exist) - - | - ENV_FILE="/opt/realms/.env" - if [ ! -f "$ENV_FILE" ]; then - echo "Generating .env with secure random secrets..." - cat > "$ENV_FILE" << 'ENVEOF' -# ============================================================================= -# Realms Production Environment - Auto-generated on first deploy -# ============================================================================= - -# Database -DB_PASSWORD=$(openssl rand -base64 32 | tr -d '/+=' | head -c 32) - -# JWT Secret for authentication -JWT_SECRET=$(openssl rand -base64 48 | tr -d '/+=' | head -c 48) - -# Redis -REDIS_PASSWORD=$(openssl rand -base64 32 | tr -d '/+=' | head -c 32) - -# OvenMediaEngine API Token -OME_API_TOKEN=$(openssl rand -hex 32) - -# Nakama Game Server -NAKAMA_SERVER_KEY=$(openssl rand -hex 16) -NAKAMA_CONSOLE_PASSWORD=$(openssl rand -base64 16 | tr -d '/+=' | head -c 16) -ENVEOF - - # Generate actual random values by evaluating the file - # Read template and generate real values - DB_PASS=$(openssl rand -base64 32 | tr -d '/+=' | head -c 32) - JWT_SEC=$(openssl rand -base64 48 | tr -d '/+=' | head -c 48) - REDIS_PASS=$(openssl rand -base64 32 | tr -d '/+=' | head -c 32) - OME_TOKEN=$(openssl rand -hex 32) - NAKAMA_KEY=$(openssl rand -hex 16) - NAKAMA_PASS=$(openssl rand -base64 16 | tr -d '/+=' | head -c 16) - - cat > "$ENV_FILE" << ENVEOF -# ============================================================================= -# Realms Production Environment - Auto-generated on first deploy -# Generated: $(date -Iseconds) -# ============================================================================= - -# Database -DB_PASSWORD=$DB_PASS - -# JWT Secret for authentication -JWT_SECRET=$JWT_SEC - -# Redis -REDIS_PASSWORD=$REDIS_PASS - -# OvenMediaEngine API Token -OME_API_TOKEN=$OME_TOKEN - -# Nakama Game Server -NAKAMA_SERVER_KEY=$NAKAMA_KEY -NAKAMA_CONSOLE_PASSWORD=$NAKAMA_PASS -ENVEOF - - chmod 600 "$ENV_FILE" - echo ".env generated with secure random secrets" - else - echo ".env already exists, skipping generation" - fi + # Generate .env with secure random secrets (script defined in write_files) + - /usr/local/bin/generate-env.sh # Enable unattended upgrades - systemctl enable unattended-upgrades