diff --git a/.env.example b/.env.example index 479a0b7..a5b4153 100644 --- a/.env.example +++ b/.env.example @@ -18,9 +18,12 @@ SMTP_FROM=noreply@jinkendo.de # App APP_URL=https://shinkan.jinkendo.de +# Kommasepariert (ohne Leerzeichen um die Kommas ist am sichersten). Für Dev mehrere Origins nötig (HTTPS + LAN). ALLOWED_ORIGINS=https://shinkan.jinkendo.de ENVIRONMENT=production +# Nur docker-compose.dev-env.yml (optional): DEV_APP_URL, DEV_ALLOWED_ORIGINS + # Media Storage MEDIA_DIR=/app/media diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 63c88ec..ad2ae3d 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -19,4 +19,5 @@ jobs: docker compose -f docker-compose.dev-env.yml up -d sleep 5 curl -sf http://localhost:8098/api/version && echo "✓ DEV API healthy" + curl -sf http://localhost:3098/api/version && echo "✓ DEV über Frontend-Nginx (wie Browser) healthy" echo "=== Shinkan DEV Deploy complete ===" diff --git a/backend/main.py b/backend/main.py index 0949bab..2a9d6ae 100644 --- a/backend/main.py +++ b/backend/main.py @@ -11,6 +11,9 @@ from fastapi.responses import JSONResponse from fastapi.staticfiles import StaticFiles import os +from slowapi import _rate_limit_exceeded_handler +from slowapi.errors import RateLimitExceeded + from version import APP_VERSION, BUILD_DATE, DB_SCHEMA_VERSION, MODULE_VERSIONS # Run database migrations on startup @@ -22,6 +25,8 @@ except Exception as e: print(f"⚠ Warning: Migration error: {e}") print(" Continuing startup - migrations may need manual intervention") +from routers.auth import limiter as auth_rate_limiter + # Initialize FastAPI app app = FastAPI( title="Shinkan Jinkendo API", @@ -29,8 +34,13 @@ app = FastAPI( version=APP_VERSION ) -# CORS Configuration -ALLOWED_ORIGINS = os.getenv("ALLOWED_ORIGINS", "http://localhost:3098").split(",") +# SlowAPI: Rate Limits auf /api/auth/* (Decorator in routers/auth.py) +app.state.limiter = auth_rate_limiter +app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) + +# CORS — kommaseparierte Liste (z. B. https://dev.shinkan… und http://192.168.x.x:3098) +_cors_raw = os.getenv("ALLOWED_ORIGINS", "http://localhost:3098") +ALLOWED_ORIGINS = [o.strip() for o in _cors_raw.split(",") if o.strip()] app.add_middleware( CORSMiddleware, diff --git a/docker-compose.dev-env.yml b/docker-compose.dev-env.yml index 534ca02..b0236cd 100644 --- a/docker-compose.dev-env.yml +++ b/docker-compose.dev-env.yml @@ -34,8 +34,10 @@ services: SMTP_USER: ${SMTP_USER} SMTP_PASS: ${SMTP_PASS} SMTP_FROM: ${SMTP_FROM} - APP_URL: http://192.168.2.49:3098 - ALLOWED_ORIGINS: http://192.168.2.49:3098 + # Öffentliche Dev-URL (E-Mail-Links); lokaler Zugriff per IP bleibt über ALLOWED_ORIGINS möglich + APP_URL: "${DEV_APP_URL:-https://dev.shinkan.jinkendo.de}" + # Login/Register vom Browser: HTTPS-Subdomain und optional LAN-IP (Compose überschreibbar per .env) + ALLOWED_ORIGINS: "${DEV_ALLOWED_ORIGINS:-https://dev.shinkan.jinkendo.de,http://192.168.2.49:3098}" ENVIRONMENT: development MEDIAWIKI_API_URL: https://karatetrainer.net/api.php MEDIAWIKI_USER: Jinkendo @@ -58,11 +60,14 @@ services: build: context: ./frontend dockerfile: Dockerfile + # Leer = relative /api/*-URLs → gleicher Host wie die SPA (vermeidet Mixed Content HTTPS→HTTP) args: - VITE_API_URL: http://192.168.2.49:8098 + VITE_API_URL: "" container_name: dev-shinkan-ui ports: - "3098:80" + depends_on: + - backend restart: unless-stopped networks: - dev-shinkan-network diff --git a/docker-compose.yml b/docker-compose.yml index c0ac97c..859a61f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -52,7 +52,7 @@ services: context: ./frontend dockerfile: Dockerfile args: - VITE_API_URL: https://shinkan.jinkendo.de + VITE_API_URL: "" container_name: shinkan-ui ports: - "3003:80"