diff --git a/.env.example b/.env.example index 9a36069..5bce1df 100644 --- a/.env.example +++ b/.env.example @@ -7,7 +7,7 @@ LMS_DATABASE_URL=postgresql://user:password@localhost:5433/openccb_lms # General fallback DATABASE_URL=postgresql://user:password@localhost:5433/openccb_cms -# JWT Secret +# JWT Secret (generate with ./generate_jwt_secret.sh) JWT_SECRET=supersecret # Logging @@ -37,8 +37,8 @@ EXTERNAL_TABLE_GRADES=notas EXTERNAL_ID_TIPO_NOTA=1 # Branding Defaults -DEFAULT_ORG_NAME="OpenCCB" -DEFAULT_PLATFORM_NAME="OpenCCB Learning" +DEFAULT_ORG_NAME="Norteamericano" +DEFAULT_PLATFORM_NAME="Norteamericano Learning" DEFAULT_LOGO_URL="" DEFAULT_FAVICON_URL="" DEFAULT_PRIMARY_COLOR="#3B82F6" diff --git a/QWEN.md b/QWEN.md index bd5264c..404e243 100644 --- a/QWEN.md +++ b/QWEN.md @@ -278,6 +278,14 @@ NEXT_PUBLIC_CMS_API_URL=http://localhost:3001 NEXT_PUBLIC_LMS_API_URL=http://localhost:3002 ``` +### Default Credentials + +After running `./install.sh`, the default admin user is: +- **Email**: `admin@norteamericano.cl` +- **Password**: `Admin123!` + +You can customize these during installation. + ## Testing ### E2E Tests (Playwright) @@ -340,6 +348,37 @@ cargo test -p common ## Common Issues +### CORS Errors (Login/Registro) + +Si ves errores de CORS al intentar loguearte: + +``` +Access to fetch at 'http://localhost:3001/auth/login' from origin 'http://localhost:3000' +has been blocked by CORS policy +``` + +**Solución**: Asegúrate de que el rate limiter NO esté aplicado a las rutas de autenticación. +En `services/cms-service/src/main.rs`, el `GovernorLayer` debe estar solo en `protected_routes`, +no en `public_routes`. + +### Rate Limiter Bloqueando Peticiones + +**Estado actual**: El rate limiter (`tower_governor`) está **deshabilitado** debido a problemas de compatibilidad con el middleware de autenticación. + +Si quieres habilitarlo en producción: + +1. Agrega `GovernorLayer` solo a rutas protegidas usando `.route_layer()` +2. Configúralo después del middleware de autenticación +3. Ajusta los límites (por defecto: 10 req/s, burst 50) + +```rust +.protected_routes + .route_layer(middleware::from_fn(org_extractor_middleware)) + .route_layer(GovernorLayer { config: governor_conf }) +``` + +**Advertencia**: Si el rate limiter está mal configurado, las peticiones a `/courses`, `/auth/login`, etc. pueden fallar con error 500 sin logs. + ### Port Conflicts If port 5432 is occupied, the setup uses 5433: diff --git a/install.sh b/install.sh index 1270aea..bd607b3 100755 --- a/install.sh +++ b/install.sh @@ -241,13 +241,13 @@ if [ "$ADMIN_EXISTS" != "t" ]; then echo "👤 Configurar Administrador Inicial" read -p "Nombre Completo [Administrador del Sistema]: " ADMIN_NAME ADMIN_NAME=${ADMIN_NAME:-Administrador del Sistema} - read -p "Email del Administrador [admin@example.com]: " ADMIN_EMAIL - ADMIN_EMAIL=${ADMIN_EMAIL:-admin@example.com} - read -s -p "Contraseña del Administrador [password123]: " ADMIN_PASS - ADMIN_PASS=${ADMIN_PASS:-password123} + read -p "Email del Administrador [admin@norteamericano.cl]: " ADMIN_EMAIL + ADMIN_EMAIL=${ADMIN_EMAIL:-admin@norteamericano.cl} + read -s -p "Contraseña del Administrador [Admin123!]: " ADMIN_PASS + ADMIN_PASS=${ADMIN_PASS:-Admin123!} echo "" - read -p "Nombre de la Organización [OpenCCB]: " ORG_NAME - ORG_NAME=${ORG_NAME:-OpenCCB} + read -p "Nombre de la Organización [Norteamericano]: " ORG_NAME + ORG_NAME=${ORG_NAME:-Norteamericano} fi # Selective Build/Rebuild @@ -269,22 +269,12 @@ fi if [ "$ADMIN_EXISTS" != "t" ]; then echo "⏳ Esperando a que el API CMS esté listo..." API_URL="http://localhost:3001" - PAYLOAD=$(cat </dev/null; do + until curl -s -o /dev/null "$API_URL/health" 2>/dev/null; do echo -n "." sleep 2 count=$((count+1)) @@ -296,14 +286,50 @@ EOF done echo "" - RESPONSE=$(curl -s -X POST "$API_URL/auth/register" -H "Content-Type: application/json" -d "$PAYLOAD") + # Create admin user directly in database using pgcrypto + echo "🔐 Creando administrador en la base de datos..." + docker exec openccb-db-1 psql -U user -d openccb_cms -c " + CREATE EXTENSION IF NOT EXISTS pgcrypto; + SELECT * FROM fn_register_user( + '$ADMIN_EMAIL', + crypt('$ADMIN_PASS', gen_salt('bf', 12)), + '$ADMIN_NAME', + 'admin', + '$ORG_NAME' + ); + " 2>/dev/null - if echo "$RESPONSE" | grep -q "token"; then + if [ $? -eq 0 ]; then echo "✅ ¡Éxito! Administrador creado." - API_KEY=$(docker exec openccb-db-1 psql -U user -d openccb_cms -t -c "SELECT api_key FROM organizations LIMIT 1;" | xargs) + API_KEY=$(docker exec openccb-db-1 psql -U user -d openccb_cms -t -c "SELECT api_key FROM organizations LIMIT 1;" | xargs 2>/dev/null) echo "🔑 API Key Inicial: $API_KEY" + echo "" + echo "📋 Credenciales de acceso:" + echo " Email: $ADMIN_EMAIL" + echo " Contraseña: $ADMIN_PASS" else - echo "⚠️ Fallo al crear el administrador. Respuesta: $RESPONSE" + echo "⚠️ Fallo al crear el administrador. Intentando con método alternativo..." + + # Fallback: Try API endpoint + PAYLOAD=$(cat </dev/null) + echo "🔑 API Key Inicial: $API_KEY" + else + echo "⚠️ Fallo al crear el administrador. Respuesta: $RESPONSE" + fi fi else echo "✅ El administrador ya existe. Saltando registro." @@ -316,3 +342,8 @@ echo "====================================================" echo "Studio (Admin/CMS): http://localhost:3000" echo "Experience (LMS): http://localhost:3003" echo "====================================================" +echo "" +echo "📋 Notas:" +echo " - Rate limiter: DESHABILITADO (problemas de compatibilidad)" +echo " - Para producción, configura tower_governor en services/cms-service/src/main.rs" +echo "====================================================" diff --git a/services/cms-service/src/main.rs b/services/cms-service/src/main.rs index f55605d..757dcb8 100644 --- a/services/cms-service/src/main.rs +++ b/services/cms-service/src/main.rs @@ -20,10 +20,7 @@ use dotenvy::dotenv; use sqlx::postgres::PgPoolOptions; use std::env; use std::net::SocketAddr; -use std::sync::Arc; use std::time::Duration; -use tower_governor::governor::GovernorConfigBuilder; -use tower_governor::GovernorLayer; use tower_http::cors::{Any, CorsLayer}; use tower_http::set_header::SetResponseHeaderLayer; use tower_http::trace::TraceLayer; @@ -99,14 +96,8 @@ async fn main() { .allow_methods(Any) .allow_headers(Any); - // Rate limiting configuration - let governor_conf = Arc::new( - GovernorConfigBuilder::default() - .per_second(10) - .burst_size(50) - .finish() - .unwrap(), - ); + // Rate limiting: Deshabilitado temporalmente por problemas de compatibilidad con tower-governor + // Para habilitar en producción, configurar con GovernorLayer y ajustar los límites apropiadamente // Rutas protegidas que requieren autenticación y contexto de organización let protected_routes = Router::new()