diff --git a/docker/.env.example b/docker/.env.example
deleted file mode 100644
index 389dfacb..00000000
--- a/docker/.env.example
+++ /dev/null
@@ -1,26 +0,0 @@
-DB_HOST=postgres
-DB_PORT=5432
-DB_USER=postgres
-DB_PASSWORD=Ia3JWjw3Y0HzlEXH6QH3pqEu09Fap5C420
-DB_NAME=gestion_db
-DB_SSLMODE=disable
-SESSION_SECRET=GwDgqYn7Tn4x6Hs9ZjUD6HP8B7pQWK
-USER_JWT_SECRET=69F5ujM1YZ6JBh3pXczc3j0JzBuAvU
-ADMIN_JWT_SECRET=RwPxdzSzAR7HcrufA6kEXHFdIiEX87
-REDIS_HOST=redis
-REDIS_PORT=6379
-REDIS_PASSWORD=m3hQyr4BgF0Paer1H4a5iUnzXqjUji
-TOMTOM_API_KEY=MERY8I7LMeYVSLKO5WuV73W9rKJpBLoB
-TOMTOM_API_KEY_1=6F7HHk8GT6WGlZ22W4gfAbRiQk5lJoGV
-TELEGRAM_BOT_TOKEN=7419967935:AAEeNIzlK6DqcQTL8q63zQ-Ted5W5VOd-LI
-TELEGRAM_BOT_USERNAME=rezsssnfdsjfdsfbot
-TELEGRAM_WEBHOOK_SECRET=vGB8n5H2fJTUx6jy6iYgYlqLz1mfSv9htF
-TELEGRAM_WEBHOOK_URL=https://uber-demo.club/webhook/telegram
-BACKEND_LINK_SECRET=QxAEEGUGRMtWbNvC2REo27haN78Rl5c5EQ
-LBTELEGRAM_URL=http://lbtelegram:8081
-LBTELEGRAM_BOT1_USERNAME=GetRezStealer_bot
-LBTELEGRAM_BOT2_USERNAME=rezDJDFJSFUltraFast_bot
-BACKEND_LINK_SECRET=change_me_internal_secret
-API_PORT=8080
-FRONTEND_PORT=5173
-GIN_MODE=release
diff --git a/docker/.env.lbtelegram b/docker/.env.lbtelegram
deleted file mode 100644
index c6af6483..00000000
--- a/docker/.env.lbtelegram
+++ /dev/null
@@ -1,30 +0,0 @@
-# Gateway
-PORT=8081
-ENV=production
-BOT_COUNT=2
-
-# Bots Telegram
-BOT1_TOKEN=8336841145:AAHPfHdgqLctEC_Zet5mT8D7ZXiwp8BQ1io
-BOT1_USERNAME=GetRezStealer_bot
-BOT1_WEBHOOK_SECRET=cVxqtea9s078ozDSlX57MWe6bjoLAK3ra7Zq
-
-BOT2_TOKEN=8325503969:AAGffm9Q-oYr5ySf8cR4Wr-e2CA2p_xOrbg
-BOT2_USERNAME=rezDJDFJSFUltraFast_bot
-BOT2_WEBHOOK_SECRET=591aVEu1kj3YUVCNWAOU2xGdFNCVWqElzXGi
-
-# URL publique de la gateway (pour setWebhook Telegram)
-GATEWAY_URL=https://demo-uber.club
-
-# JWT
-JWT_SECRET=IxGF36s14J0ZNeQCF2Of0APc4kpNd5PlsJ
-JWT_TTL_SECONDS=300
-
-# Load balancer: roundrobin | leastconn | failover
-LB_STRATEGY=failover
-
-# Health check interval en secondes
-HEALTH_CHECK_INTERVAL=30
-
-# URL interne du backend pour valider les tokens de liaison
-BACKEND_LINK_URL=http://backend:8080/api/internal/telegram/link
-BACKEND_LINK_SECRET=QxAEEGUGRMtWbNvC2REo27haN78Rl5c5EQ
diff --git a/docker/backend/Dockerfile b/docker/backend/Dockerfile
deleted file mode 100644
index 6464ae4f..00000000
--- a/docker/backend/Dockerfile
+++ /dev/null
@@ -1,76 +0,0 @@
-FROM golang:1.24-alpine AS builder
-WORKDIR /app
-
-# Installer les dépendances système
-RUN apk add --no-cache git ca-certificates tzdata gcc musl-dev
-
-# Copier go mod files
-COPY backend/gestion/go.mod backend/gestion/go.sum ./
-
-# Configurer Go et télécharger les dépendances
-ENV GOPROXY=https://proxy.golang.org,direct
-ENV GOSUMDB=sum.golang.org
-ENV CGO_ENABLED=0
-
-# Télécharger les dépendances
-RUN go mod download
-
-# Copier tout le code source
-COPY backend/gestion/ .
-
-# Build le binaire
-RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
- -ldflags="-w -s -X main.Version=1.0.0 -X main.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
- -o /app/server .
-
-# =========================================================
-# Stage 2: Runtime
-# =========================================================
-FROM alpine:latest AS runtime
-
-# Installer les dépendances runtime
-RUN apk --no-cache add ca-certificates tzdata wget
-
-# Créer l'utilisateur avec UID/GID fixes
-RUN addgroup -g 101 app && adduser -u 101 -S app -G app
-
-
-WORKDIR /app
-
-# Copier le binaire et les fichiers nécessaires
-COPY --from=builder /app/server .
-COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
-
-# Copier l'entrypoint
-COPY docker/backend/entrypoint.sh .
-RUN chmod +x entrypoint.sh
-
-RUN mkdir -p /app/uploads/images /app/uploads/videos && \
- chown -R app:app /app
-
-# Passer à l'utilisateur non-root
-USER app
-
-EXPOSE 8080
-
-ENTRYPOINT ["./entrypoint.sh"]
-
-# =========================================================
-# Stage 3: WAF (Nginx + ModSecurity)
-# =========================================================
-FROM owasp/modsecurity-crs:nginx-alpine AS waf
-
-# Toutes les opérations privilégiées en root
-USER root
-
-RUN mkdir -p /var/log/modsec /etc/nginx/certs && \
- chown -R nginx:nginx /var/log/modsec /etc/nginx/certs /usr/share/nginx/html
-
-COPY docker/backend/nginx.conf /etc/nginx/conf.d/app.conf
-COPY docker/backend/custom-rules.conf /etc/nginx/modsec/custom-rules.conf
-RUN echo "Include /etc/nginx/modsec/custom-rules.conf" > /etc/nginx/modsec/custom-includes.conf && \
- rm -f /etc/nginx/templates/conf.d/default.conf.template || true
-
-USER nginx
-EXPOSE 80 443
-CMD ["nginx", "-g", "daemon off;"]
diff --git a/docker/backend/custom-rules.conf b/docker/backend/custom-rules.conf
deleted file mode 100644
index c2aaeb37..00000000
--- a/docker/backend/custom-rules.conf
+++ /dev/null
@@ -1,77 +0,0 @@
-# Exclure le corps des requêtes/réponses de l'audit log pour garder les lignes < 6KB (limite Wazuh)
-SecAuditLogParts ABIFHZ
-
-SecRuleRemoveById 932235
-SecRuleRemoveById 911100
-
-SecRule REQUEST_URI "@streq /api/v2/admin/protected/products" \
- "id:399002,phase:2,nolog,pass,\
- ctl:ruleRemoveById=920120,\
- ctl:ruleRemoveById=920121"
-
-SecRule REQUEST_URI "@beginsWith /uploads/" \
- "id:1000,\
- phase:1,\
- pass,\
- nolog,\
- ctl:ruleEngine=Off"
-
-SecRule IP:BANNED "@eq 1" \
- "id:100000,phase:1,deny,status:403,log,\
- msg:'IP is banned'"
-
-SecRule IP:REPUTATION_SCORE "@ge 100" \
- "id:100099,phase:1,deny,status:403,log,\
- msg:'Critical reputation score',\
- setvar:'ip.blocked=1',expirevar:'ip.blocked=86400'"
-
-SecRule TX:SQL_INJECTION_SCORE "@ge 5" \
- "id:100001,phase:2,deny,status:403,log,\
- msg:'SQL Injection detected',\
- setvar:'ip.banned=1',expirevar:'ip.banned=172800'"
-
-SecRule TX:XSS_SCORE "@ge 5" \
- "id:100010,phase:2,deny,status:403,log,\
- msg:'XSS detected',\
- setvar:'ip.banned=1',expirevar:'ip.banned=172800'"
-
-SecRule TX:RCE_SCORE "@ge 5" \
- "id:100020,phase:2,deny,status:403,log,\
- msg:'RCE detected',\
- setvar:'ip.banned=1',expirevar:'ip.banned=259200'"
-
-SecRule TX:LFI_SCORE "@ge 5" \
- "id:100030,phase:2,deny,status:403,log,\
- msg:'LFI detected',\
- setvar:'ip.banned=1',expirevar:'ip.banned=172800'"
-
-SecRule TX:INBOUND_ANOMALY_SCORE "@ge 20" \
- "id:100060,phase:2,deny,status:403,log,\
- msg:'Critical anomaly score',\
- setvar:'ip.banned=1',expirevar:'ip.banned=172800'"
-
-SecRule REQUEST_URI "@streq /api/v1/panier/remove" \
- "id:399010,phase:1,nolog,pass,\
- ctl:ruleRemoveById=911100,ctl:ruleRemoveById=920350"
-
-SecRule REQUEST_URI "@streq /api/v1/panier/clear" \
- "id:399011,phase:1,nolog,pass,\
- ctl:ruleRemoveById=911100,ctl:ruleRemoveById=920350"
-
-SecRule REQUEST_URI "@streq /api/v2/admin/protected/products" \
- "id:399001,phase:2,nolog,pass,\
- ctl:ruleRemoveById=932235"
-
-SecAction \
- "id:400161,phase:1,nolog,pass,\
- setvar:'ip.request_window_1sec=+1',\
- expirevar:'ip.request_window_1sec=1'"
-
-SecRule IP:REQUEST_WINDOW_1SEC "@gt 20" \
- "id:400160,phase:1,deny,status:429,log,\
- msg:'Too many requests'"
-
-SecRule IP:REPUTATION_SCORE "@ge 100" \
- "id:409999,phase:1,deny,status:403,log,\
- msg:'Critical reputation score',\
- setvar:'ip.blocked=1',expirevar:'ip.blocked=86400'"
diff --git a/docker/backend/entrypoint.sh b/docker/backend/entrypoint.sh
deleted file mode 100755
index 4c1b857e..00000000
--- a/docker/backend/entrypoint.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-set -e
-
-# Créer le dossier uploads s'il n'existe pas (le volume le crée en root)
-# Puis créer les sous-dossiers
-if [ ! -d "/app/uploads" ]; then
- mkdir -p /app/uploads
-fi
-
-# Créer les sous-répertoires
-mkdir -p /app/uploads/images /app/uploads/videos 2>/dev/null || true
-
-echo "✅ Répertoires uploads prêts"
-
-# Lancer l'application
-exec ./server
diff --git a/docker/backend/nginx.conf b/docker/backend/nginx.conf
deleted file mode 100644
index 557db88f..00000000
--- a/docker/backend/nginx.conf
+++ /dev/null
@@ -1,215 +0,0 @@
-# =========================================================
-# Request ID correlation
-# =========================================================
-map $http_x_request_id $req_id {
- default $http_x_request_id;
- "" $request_id;
-}
-
-# =========================================================
-# HTTP → HTTPS redirect
-# =========================================================
-server {
- listen 80;
- listen [::]:80;
- server_name _;
-
- return 301 https://$host$request_uri;
-}
-
-# =========================================================
-# HTTPS — Hardened
-# =========================================================
-server {
- listen 443 ssl;
- listen [::]:443 ssl;
- http2 on;
- server_name _;
-
- server_tokens off;
-
- # ---------------------------------------------------
- # TLS
- # ---------------------------------------------------
- ssl_certificate /etc/nginx/certs/fullchain.pem;
- ssl_certificate_key /etc/nginx/certs/privkey.pem;
-
- ssl_protocols TLSv1.2 TLSv1.3;
- ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256;
- ssl_prefer_server_ciphers off;
-
- ssl_session_cache shared:SSL:10m;
- ssl_session_timeout 1d;
- ssl_session_tickets off;
-
- ssl_stapling on;
- ssl_stapling_verify on;
- ssl_trusted_certificate /etc/nginx/certs/fullchain.pem;
- resolver 127.0.0.11 valid=10s ipv6=off;
- resolver_timeout 5s;
-
- # ---------------------------------------------------
- # En-têtes de sécurité
- # ---------------------------------------------------
- add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
- add_header X-Frame-Options "SAMEORIGIN" always;
- add_header X-Content-Type-Options "nosniff" always;
- add_header X-XSS-Protection "0" always;
- add_header Referrer-Policy "strict-origin-when-cross-origin" always;
- add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=()" always;
- add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; connect-src 'self' https:; frame-ancestors 'self';" always;
-
- # ---------------------------------------------------
- # Limites et timeouts
- # ---------------------------------------------------
- client_max_body_size 100M;
- client_body_buffer_size 128k;
- client_header_buffer_size 1k;
- large_client_header_buffers 4 8k;
-
- client_body_timeout 30s;
- client_header_timeout 30s;
- send_timeout 30s;
- keepalive_timeout 65s;
-
- # ---------------------------------------------------
- # Gzip (statique uniquement — évite BREACH sur l'API)
- # ---------------------------------------------------
- gzip on;
- gzip_vary on;
- gzip_proxied any;
- gzip_comp_level 5;
- gzip_min_length 1000;
- gzip_types text/plain text/css text/javascript application/javascript application/json image/svg+xml;
-
- # ---------------------------------------------------
- # ModSecurity WAF
- # ---------------------------------------------------
- modsecurity on;
- modsecurity_rules_file /etc/nginx/modsec/custom-rules.conf;
-
- # ---------------------------------------------------
- # API backend Go
- # ---------------------------------------------------
- location /api/ {
- limit_except GET POST PUT PATCH DELETE OPTIONS { deny all; }
-
- if ($request_method = 'OPTIONS') {
- add_header 'Access-Control-Allow-Origin' "$http_origin" always;
- add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE, OPTIONS' always;
- add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-Request-ID' always;
- add_header 'Access-Control-Allow-Credentials' 'true' always;
- add_header 'Access-Control-Max-Age' 86400 always;
- add_header 'Content-Length' 0;
- add_header 'Content-Type' 'text/plain charset=UTF-8';
- return 204;
- }
-
- set $upstream_backend http://backend:8080;
- proxy_pass $upstream_backend;
- proxy_http_version 1.1;
- proxy_set_header Connection "";
- 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;
- proxy_set_header X-Request-ID $req_id;
- proxy_hide_header X-Powered-By;
-
- proxy_connect_timeout 60s;
- proxy_send_timeout 300s;
- proxy_read_timeout 300s;
-
- proxy_buffer_size 128k;
- proxy_buffers 4 256k;
- proxy_busy_buffers_size 256k;
- }
-
- # ---------------------------------------------------
- # Webhook Telegram principal → backend Go
- # ---------------------------------------------------
- location = /webhook/telegram {
- limit_except POST { deny all; }
-
- set $upstream_backend http://backend:8080;
- proxy_pass $upstream_backend;
- proxy_http_version 1.1;
- proxy_set_header Connection "";
- 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;
- }
-
- # ---------------------------------------------------
- # Webhooks LBTelegram (/webhook/bot1, /webhook/bot2…)
- # ---------------------------------------------------
- location /webhook/ {
- limit_except POST { deny all; }
-
- set $upstream_lbtelegram http://lbtelegram:8081;
- proxy_pass $upstream_lbtelegram;
- proxy_http_version 1.1;
- proxy_set_header Connection "";
- 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;
- }
-
- # ---------------------------------------------------
- # Fichiers uploadés (images / vidéos)
- # ---------------------------------------------------
- location /uploads/ {
- alias /usr/share/nginx/html/uploads/;
- expires 7d;
- add_header Cache-Control "public, no-transform" always;
- add_header X-Content-Type-Options "nosniff" always;
-
- location ~* \.(php|pl|py|cgi|sh|rb|exe)$ {
- deny all;
- }
- }
-
- # ---------------------------------------------------
- # Frontend React SPA
- # ---------------------------------------------------
- location / {
- set $upstream_frontend http://frontend:80;
- proxy_pass $upstream_frontend;
- proxy_http_version 1.1;
- proxy_set_header Connection "";
- 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;
- }
-
- # ---------------------------------------------------
- # Blocage fichiers sensibles
- # ---------------------------------------------------
- location ~ /\. {
- deny all;
- access_log off;
- log_not_found off;
- }
-
- location ~* \.(env|git|sql|bak|log|conf|ini|sh)$ {
- deny all;
- access_log off;
- log_not_found off;
- }
-
- location ~* (package\.json|package-lock\.json|yarn\.lock|Dockerfile|docker-compose)$ {
- deny all;
- access_log off;
- log_not_found off;
- }
-
- # Bloquer scans WordPress / PHP courants
- location ~* (wp-admin|wp-login|wp-content|xmlrpc|\.php)$ {
- deny all;
- access_log off;
- log_not_found off;
- }
-}
diff --git a/docker/docker-compose-pre-prod.yml b/docker/docker-compose-pre-prod.yml
deleted file mode 100644
index 0a4c84d8..00000000
--- a/docker/docker-compose-pre-prod.yml
+++ /dev/null
@@ -1,212 +0,0 @@
-services:
- # =========================================================
- # Backend Go
- # =========================================================
- backend:
- image: xor1234/backend-mln:pre-prod
- container_name: gestion-backend
- restart: unless-stopped
- environment:
- - DB_HOST=${DB_HOST:-postgres}
- - DB_PORT=${DB_PORT:-5432}
- - DB_USER=${DB_USER:-postgres}
- - DB_PASSWORD=${DB_PASSWORD}
- - DB_NAME=${DB_NAME:-gestion_db}
- - DB_SSLMODE=${DB_SSLMODE:-disable}
- - SESSION_SECRET=${SESSION_SECRET}
- - USER_JWT_SECRET=${USER_JWT_SECRET}
- - USER_JWT_SECRET_OLD=${USER_JWT_SECRET_OLD}
- - ADMIN_JWT_SECRET=${ADMIN_JWT_SECRET}
- - ADMIN_JWT_SECRET_OLD=${ADMIN_JWT_SECRET_OLD}
- - REDIS_HOST=${REDIS_HOST:-redis}
- - REDIS_PORT=${REDIS_PORT:-6379}
- - REDIS_PASSWORD=${REDIS_PASSWORD}
- - TOMTOM_API_KEY=${TOMTOM_API_KEY}
- - TOMTOM_API_KEY_1=${TOMTOM_API_KEY_1}
- - TOMTOM_API_KEY_2=${TOMTOM_API_KEY_2}
- - TOMTOM_API_KEY_3=${TOMTOM_API_KEY_3}
- - API_PORT=${API_PORT:-8080}
- - NOWPAYMENTS_IPN_SECRET=${NOWPAYMENTS_IPN_SECRET}
- - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
- - TELEGRAM_BOT_USERNAME=${TELEGRAM_BOT_USERNAME}
- - TELEGRAM_WEBHOOK_SECRET=${TELEGRAM_WEBHOOK_SECRET}
- - TELEGRAM_WEBHOOK_URL=${TELEGRAM_WEBHOOK_URL}
- - LBTELEGRAM_URL=http://lbtelegram:8081
- - LBTELEGRAM_BOT1_USERNAME=${LBTELEGRAM_BOT1_USERNAME:-GetRezStealer_bot}
- - LBTELEGRAM_BOT2_USERNAME=${LBTELEGRAM_BOT2_USERNAME:-rezDJDFJSFUltraFast_bot}
- - BACKEND_LINK_SECRET=${BACKEND_LINK_SECRET:-change_me_internal_secret}
- volumes:
- - backend_uploads:/app/uploads
- networks:
- - gestion-network
- depends_on:
- postgres:
- condition: service_healthy
- redis:
- condition: service_healthy
-
- # =========================================================
- # Frontend Web (React/Vite — servi en HTTP interne)
- # =========================================================
- frontend:
- image: xor1234/frontend-mln:pre-prod
- container_name: gestion-frontend
- restart: unless-stopped
- networks:
- - gestion-network
- depends_on:
- - backend
-
- waf:
- image: xor1234/backend-mln:waf-pre-prod
- container_name: gestion-waf
- restart: unless-stopped
- environment:
- - DISABLE_MODSEC_ENV_SUBST=true
- - PARANOIA=2
- - ANOMALY_INBOUND=5
- - ANOMALY_OUTBOUND=4
- - MODSEC_AUDIT_LOG=/var/log/modsec/modsec_audit.log
- ports:
- - "80:80"
- - "443:443"
- volumes:
- - backend_uploads:/usr/share/nginx/html/uploads:ro
- - ./certs:/etc/nginx/certs:ro
- - ./backend/nginx.conf:/etc/nginx/conf.d/app.conf:ro
- - ./backend/custom-rules.conf:/etc/nginx/modsec/custom-rules.conf:ro
- - /var/log/waf/nginx:/var/log/nginx
- - /var/log/waf/modsec:/var/log/modsec
- networks:
- - gestion-network
- depends_on:
- - backend
- - frontend
-
- # =========================================================
- # PostgreSQL
- # =========================================================
- postgres:
- image: postgres:16-alpine
- container_name: gestion-postgres
- restart: unless-stopped
- environment:
- - POSTGRES_USER=${DB_USER:-postgres}
- - POSTGRES_PASSWORD=${DB_PASSWORD}
- - POSTGRES_DB=${DB_NAME:-gestion_db}
- - PGDATA=/var/lib/postgresql/data/pgdata
- volumes:
- - postgres_data:/var/lib/postgresql/data
- networks:
- - gestion-network
- healthcheck:
- test:
- [
- "CMD-SHELL",
- "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-gestion_db}",
- ]
- interval: 10s
- timeout: 5s
- retries: 5
- start_period: 10s
-
- # =========================================================
- # Redis
- # =========================================================
- redis:
- image: redis:7-alpine
- container_name: gestion-redis
- restart: unless-stopped
- command: >
- redis-server
- --requirepass ${REDIS_PASSWORD}
- --appendonly yes
- --appendfsync everysec
- --maxmemory 256mb
- --maxmemory-policy allkeys-lru
- volumes:
- - redis_data:/data
- networks:
- - gestion-network
- healthcheck:
- test:
- [
- "CMD",
- "redis-cli",
- "--no-auth-warning",
- "-a",
- "${REDIS_PASSWORD}",
- "ping",
- ]
- interval: 10s
- timeout: 3s
- retries: 5
- start_period: 10s
-
- # =========================================================
- # LBTelegram — Gateway Telegram load balancer
- # =========================================================
- lbtelegram:
- image: xor1234/load-balancer-tlg:latest
- container_name: gestion-lbtelegram
- restart: unless-stopped
- env_file: ./.env.lbtelegram
- environment:
- - REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379/0
- - DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@postgres:5432/${DB_NAME}?sslmode=disable
- networks:
- - gestion-network
- depends_on:
- postgres:
- condition: service_healthy
- redis:
- condition: service_healthy
- backend:
- condition: service_started
-
- clamav:
- deploy:
- resources:
- limits:
- memory: 1g
- cpus: 0.5
- image: clamav/clamav:latest
- container_name: gestion-clamav
- restart: unless-stopped
- volumes:
- - backend_uploads:/app/uploads:ro
- - clamav_data:/var/lib/clamav
- networks:
- - gestion-network
- healthcheck:
- test: ["CMD", "clamdcheck.sh"]
- interval: 60s
- timeout: 10s
- retries: 3
- start_period: 120s
-
- dozzle-agent:
- image: amir20/dozzle:latest
- command: agent
- volumes:
- - /var/run/docker.sock:/var/run/docker.sock:ro
- ports:
- - "7007:7007"
- restart: unless-stopped
-
-networks:
- gestion-network:
- driver: bridge
- internal: false
- driver_opts:
- com.docker.network.bridge.name: gestion-br0
-
-volumes:
- postgres_data:
- driver: local
- redis_data:
- driver: local
- backend_uploads:
- driver: local
- clamav_data:
- driver: local
diff --git a/docker/docker-compose-prod.yml b/docker/docker-compose-prod.yml
deleted file mode 100644
index d62c40bd..00000000
--- a/docker/docker-compose-prod.yml
+++ /dev/null
@@ -1,212 +0,0 @@
-services:
- # =========================================================
- # Backend Go
- # =========================================================
- backend:
- image: xor1234/backend-mln:latest
- container_name: gestion-backend
- restart: unless-stopped
- environment:
- - DB_HOST=${DB_HOST:-postgres}
- - DB_PORT=${DB_PORT:-5432}
- - DB_USER=${DB_USER:-postgres}
- - DB_PASSWORD=${DB_PASSWORD}
- - DB_NAME=${DB_NAME:-gestion_db}
- - DB_SSLMODE=${DB_SSLMODE:-disable}
- - SESSION_SECRET=${SESSION_SECRET}
- - USER_JWT_SECRET=${USER_JWT_SECRET}
- - USER_JWT_SECRET_OLD=${USER_JWT_SECRET_OLD}
- - ADMIN_JWT_SECRET=${ADMIN_JWT_SECRET}
- - ADMIN_JWT_SECRET_OLD=${ADMIN_JWT_SECRET_OLD}
- - REDIS_HOST=${REDIS_HOST:-redis}
- - REDIS_PORT=${REDIS_PORT:-6379}
- - REDIS_PASSWORD=${REDIS_PASSWORD}
- - TOMTOM_API_KEY=${TOMTOM_API_KEY}
- - TOMTOM_API_KEY_1=${TOMTOM_API_KEY_1}
- - TOMTOM_API_KEY_2=${TOMTOM_API_KEY_2}
- - TOMTOM_API_KEY_3=${TOMTOM_API_KEY_3}
- - API_PORT=${API_PORT:-8080}
- - NOWPAYMENTS_IPN_SECRET=${NOWPAYMENTS_IPN_SECRET}
- - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
- - TELEGRAM_BOT_USERNAME=${TELEGRAM_BOT_USERNAME}
- - TELEGRAM_WEBHOOK_SECRET=${TELEGRAM_WEBHOOK_SECRET}
- - TELEGRAM_WEBHOOK_URL=${TELEGRAM_WEBHOOK_URL}
- - LBTELEGRAM_URL=http://lbtelegram:8081
- - LBTELEGRAM_BOT1_USERNAME=${LBTELEGRAM_BOT1_USERNAME:-GetRezStealer_bot}
- - LBTELEGRAM_BOT2_USERNAME=${LBTELEGRAM_BOT2_USERNAME:-rezDJDFJSFUltraFast_bot}
- - BACKEND_LINK_SECRET=${BACKEND_LINK_SECRET:-change_me_internal_secret}
- volumes:
- - backend_uploads:/app/uploads
- networks:
- - gestion-network
- depends_on:
- postgres:
- condition: service_healthy
- redis:
- condition: service_healthy
-
- # =========================================================
- # Frontend Web (React/Vite — servi en HTTP interne)
- # =========================================================
- frontend:
- image: xor1234/frontend-mln:latest
- container_name: gestion-frontend
- restart: unless-stopped
- networks:
- - gestion-network
- depends_on:
- - backend
-
- waf:
- image: xor1234/backend-mln:waf
- container_name: gestion-waf
- restart: unless-stopped
- environment:
- - DISABLE_MODSEC_ENV_SUBST=true
- - PARANOIA=2
- - ANOMALY_INBOUND=5
- - ANOMALY_OUTBOUND=4
- - MODSEC_AUDIT_LOG=/var/log/modsec/modsec_audit.log
- ports:
- - "80:80"
- - "443:443"
- volumes:
- - backend_uploads:/usr/share/nginx/html/uploads:ro
- - ./certs:/etc/nginx/certs:ro
- - ./backend/nginx.conf:/etc/nginx/conf.d/app.conf:ro
- - ./backend/custom-rules.conf:/etc/nginx/modsec/custom-rules.conf:ro
- - /var/log/waf/nginx:/var/log/nginx
- - /var/log/waf/modsec:/var/log/modsec
- networks:
- - gestion-network
- depends_on:
- - backend
- - frontend
-
- # =========================================================
- # PostgreSQL
- # =========================================================
- postgres:
- image: postgres:16-alpine
- container_name: gestion-postgres
- restart: unless-stopped
- environment:
- - POSTGRES_USER=${DB_USER:-postgres}
- - POSTGRES_PASSWORD=${DB_PASSWORD}
- - POSTGRES_DB=${DB_NAME:-gestion_db}
- - PGDATA=/var/lib/postgresql/data/pgdata
- volumes:
- - postgres_data:/var/lib/postgresql/data
- networks:
- - gestion-network
- healthcheck:
- test:
- [
- "CMD-SHELL",
- "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-gestion_db}",
- ]
- interval: 10s
- timeout: 5s
- retries: 5
- start_period: 10s
-
- # =========================================================
- # Redis
- # =========================================================
- redis:
- image: redis:7-alpine
- container_name: gestion-redis
- restart: unless-stopped
- command: >
- redis-server
- --requirepass ${REDIS_PASSWORD}
- --appendonly yes
- --appendfsync everysec
- --maxmemory 256mb
- --maxmemory-policy allkeys-lru
- volumes:
- - redis_data:/data
- networks:
- - gestion-network
- healthcheck:
- test:
- [
- "CMD",
- "redis-cli",
- "--no-auth-warning",
- "-a",
- "${REDIS_PASSWORD}",
- "ping",
- ]
- interval: 10s
- timeout: 3s
- retries: 5
- start_period: 10s
-
- # =========================================================
- # LBTelegram — Gateway Telegram load balancer
- # =========================================================
- lbtelegram:
- image: xor1234/load-balancer-tlg:latest
- container_name: gestion-lbtelegram
- restart: unless-stopped
- env_file: ./.env.lbtelegram
- environment:
- - REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379/0
- - DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@postgres:5432/${DB_NAME}?sslmode=disable
- networks:
- - gestion-network
- depends_on:
- postgres:
- condition: service_healthy
- redis:
- condition: service_healthy
- backend:
- condition: service_started
-
- clamav:
- deploy:
- resources:
- limits:
- memory: 1g
- cpus: 0.5
- image: clamav/clamav:latest
- container_name: gestion-clamav
- restart: unless-stopped
- volumes:
- - backend_uploads:/app/uploads:ro
- - clamav_data:/var/lib/clamav
- networks:
- - gestion-network
- healthcheck:
- test: ["CMD", "clamdcheck.sh"]
- interval: 60s
- timeout: 10s
- retries: 3
- start_period: 120s
-
- dozzle-agent:
- image: amir20/dozzle:latest
- command: agent
- volumes:
- - /var/run/docker.sock:/var/run/docker.sock:ro
- ports:
- - "7007:7007"
- restart: unless-stopped
-
-networks:
- gestion-network:
- driver: bridge
- internal: false
- driver_opts:
- com.docker.network.bridge.name: gestion-br0
-
-volumes:
- postgres_data:
- driver: local
- redis_data:
- driver: local
- backend_uploads:
- driver: local
- clamav_data:
- driver: local
diff --git a/docker/frontend/Dockerfile b/docker/frontend/Dockerfile
deleted file mode 100644
index 8594b8ff..00000000
--- a/docker/frontend/Dockerfile
+++ /dev/null
@@ -1,34 +0,0 @@
-# =========================================================
-# Stage 1: Build React/Vite
-# =========================================================
-FROM node:22-alpine AS builder
-
-WORKDIR /app
-
-COPY frontend-prep/package.json frontend-prep/package-lock.json* ./
-RUN npm ci --ignore-scripts
-
-COPY frontend-prep/ .
-RUN npm run build
-
-# =========================================================
-# Stage 2: Nginx HTTP (TLS terminé par le WAF)
-# =========================================================
-FROM nginx:alpine AS runtime
-
-COPY docker/frontend/nginx.conf /etc/nginx/conf.d/default.conf
-
-COPY --from=builder /app/dist /usr/share/nginx/html
-
-RUN chown -R nginx:nginx /usr/share/nginx/html && \
- mkdir -p /var/cache/nginx && \
- chown -R nginx:nginx /var/cache/nginx && \
- chown -R nginx:nginx /var/log/nginx && \
- touch /var/run/nginx.pid && \
- chown nginx:nginx /var/run/nginx.pid
-
-USER nginx
-
-EXPOSE 80
-
-CMD ["nginx", "-g", "daemon off;"]
diff --git a/docker/frontend/nginx.conf b/docker/frontend/nginx.conf
deleted file mode 100644
index 6d95b8c4..00000000
--- a/docker/frontend/nginx.conf
+++ /dev/null
@@ -1,16 +0,0 @@
-server {
- listen 80;
- server_name _;
-
- root /usr/share/nginx/html;
- index index.html;
-
- location / {
- try_files $uri $uri/ /index.html;
- }
-
- location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
- expires 1y;
- add_header Cache-Control "public, immutable";
- }
-}
diff --git a/docker/test-rules.sh b/docker/test-rules.sh
deleted file mode 100755
index 3f0fd0c9..00000000
--- a/docker/test-rules.sh
+++ /dev/null
@@ -1,610 +0,0 @@
-#!/bin/bash
-
-# =============================================================================
-# Script de Test - ModSecurity Rules (XSS, SQL Injection, RCE, LFI, RFI)
-# =============================================================================
-# Description: Teste les règles WAF pour XSS, SQL, RCE, LFI et RFI
-# Usage: ./test-rules.sh
-# =============================================================================
-
-# Couleurs pour l'affichage
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-YELLOW='\033[1;33m'
-BLUE='\033[0;34m'
-PURPLE='\033[0;35m'
-CYAN='\033[0;36m'
-NC='\033[0m' # No Color
-BOLD='\033[1m'
-
-# Configuration
-API_BASE_URL="http://172.20.167.237"
-
-# Credentials Client
-CLIENT_USERNAME="salut"
-CLIENT_PASSWORD="salut1234_"
-CLIENT_TOKEN=""
-
-# Credentials Admin
-ADMIN_USERNAME="admin_1768505094"
-ADMIN_PASSWORD="AdminPass123!"
-ADMIN_TOKEN=""
-
-TOTAL_TESTS=0
-PASSED_TESTS=0
-FAILED_TESTS=0
-LOG_FILE="modsec_test_$(date +%Y%m%d_%H%M%S).log"
-
-# =============================================================================
-# Fonctions Utilitaires
-# =============================================================================
-
-print_header() {
- echo -e "\n${BOLD}${CYAN}========================================${NC}"
- echo -e "${BOLD}${CYAN}$1${NC}"
- echo -e "${BOLD}${CYAN}========================================${NC}\n"
-}
-
-print_section() {
- echo -e "\n${BOLD}${BLUE}>>> $1${NC}\n"
-}
-
-print_test() {
- echo -e "${YELLOW}[TEST] $1${NC}"
-}
-
-print_success() {
- ((PASSED_TESTS++))
- ((TOTAL_TESTS++))
- echo -e "${GREEN}✓ PASS${NC} - $1" | tee -a "$LOG_FILE"
-}
-
-print_fail() {
- ((FAILED_TESTS++))
- ((TOTAL_TESTS++))
- echo -e "${RED}✗ FAIL${NC} - $1" | tee -a "$LOG_FILE"
-}
-
-print_info() {
- echo -e "${CYAN}ℹ INFO${NC} - $1"
-}
-
-print_warning() {
- echo -e "${YELLOW}⚠ WARNING${NC} - $1"
-}
-
-print_response() {
- echo -e "${PURPLE}📄 Response:${NC} $1"
-}
-
-# Fonction pour effectuer une requête HTTP avec token client
-http_test_client() {
- local method=$1
- local endpoint=$2
- local data=$3
- local expected_code=$4
- local description=$5
- local extra_headers=$6
-
- print_test "$description"
-
- if [ -z "$data" ]; then
- response=$(curl -s -w "\n%{http_code}" -X "$method" \
- -H "Authorization: Bearer $CLIENT_TOKEN" \
- -H "Content-Type: application/json" \
- $extra_headers \
- "${API_BASE_URL}${endpoint}" 2>&1)
- else
- response=$(curl -s -w "\n%{http_code}" -X "$method" \
- -H "Authorization: Bearer $CLIENT_TOKEN" \
- -H "Content-Type: application/json" \
- $extra_headers \
- -d "$data" \
- "${API_BASE_URL}${endpoint}" 2>&1)
- fi
-
- http_code=$(echo "$response" | tail -n1)
- body=$(echo "$response" | sed '$d')
-
- if [ "$http_code" -eq "$expected_code" ]; then
- print_success "$description (HTTP $http_code)"
- else
- print_fail "$description - Expected: $expected_code, Got: $http_code"
- print_response "$body"
- echo "$description - Expected: $expected_code, Got: $http_code" >> "$LOG_FILE"
- echo "Response: $body" >> "$LOG_FILE"
- fi
-
- sleep 0.5
-}
-
-# Fonction pour effectuer une requête HTTP avec token admin
-http_test_admin() {
- local method=$1
- local endpoint=$2
- local data=$3
- local expected_code=$4
- local description=$5
- local extra_headers=$6
-
- print_test "$description"
-
- if [ -z "$data" ]; then
- response=$(curl -s -w "\n%{http_code}" -X "$method" \
- -H "Authorization: Bearer $ADMIN_TOKEN" \
- -H "Content-Type: application/json" \
- $extra_headers \
- "${API_BASE_URL}${endpoint}" 2>&1)
- else
- response=$(curl -s -w "\n%{http_code}" -X "$method" \
- -H "Authorization: Bearer $ADMIN_TOKEN" \
- -H "Content-Type: application/json" \
- $extra_headers \
- -d "$data" \
- "${API_BASE_URL}${endpoint}" 2>&1)
- fi
-
- http_code=$(echo "$response" | tail -n1)
- body=$(echo "$response" | sed '$d')
-
- if [ "$http_code" -eq "$expected_code" ]; then
- print_success "$description (HTTP $http_code)"
- echo "$body"
- else
- print_fail "$description - Expected: $expected_code, Got: $http_code"
- print_response "$body"
- echo "$description - Expected: $expected_code, Got: $http_code" >> "$LOG_FILE"
- echo "Response: $body" >> "$LOG_FILE"
- fi
-
- sleep 0.5
-}
-
-# Fonction pour effectuer une requête HTTP sans authentification
-http_test_no_auth() {
- local method=$1
- local endpoint=$2
- local data=$3
- local expected_code=$4
- local description=$5
-
- print_test "$description"
-
- if [ -z "$data" ]; then
- response=$(curl -s -w "\n%{http_code}" -X "$method" \
- -H "Content-Type: application/json" \
- "${API_BASE_URL}${endpoint}" 2>&1)
- else
- response=$(curl -s -w "\n%{http_code}" -X "$method" \
- -H "Content-Type: application/json" \
- -d "$data" \
- "${API_BASE_URL}${endpoint}" 2>&1)
- fi
-
- http_code=$(echo "$response" | tail -n1)
- body=$(echo "$response" | sed '$d')
-
- if [ "$http_code" -eq "$expected_code" ]; then
- print_success "$description (HTTP $http_code)"
- else
- print_fail "$description - Expected: $expected_code, Got: $http_code"
- print_response "$body"
- echo "$description - Expected: $expected_code, Got: $http_code" >> "$LOG_FILE"
- echo "Response: $body" >> "$LOG_FILE"
- fi
-
- sleep 0.5
-}
-
-# =============================================================================
-# Authentification
-# =============================================================================
-
-authenticate() {
- print_header "AUTHENTIFICATION"
-
- # ==================== CLIENT LOGIN ====================
- print_section "1. Login Client"
- response=$(curl -s -w "\n%{http_code}" -X POST \
- -H "Content-Type: application/json" \
- -d "{\"username\":\"$CLIENT_USERNAME\",\"password\":\"$CLIENT_PASSWORD\"}" \
- "${API_BASE_URL}/api/v1/auth/login")
-
- http_code=$(echo "$response" | tail -n1)
- body=$(echo "$response" | sed '$d')
-
- if [ "$http_code" -eq 200 ]; then
- CLIENT_TOKEN=$(echo "$body" | grep -o '"access_token":"[^"]*' | cut -d'"' -f4)
- if [ -n "$CLIENT_TOKEN" ]; then
- print_success "Login Client réussi - Token obtenu"
- print_info "Token Client: ${CLIENT_TOKEN:0:50}..."
- else
- print_fail "Login Client réussi mais token non trouvé"
- print_response "$body"
- exit 1
- fi
- else
- print_fail "Échec du login Client (HTTP $http_code)"
- print_response "$body"
- exit 1
- fi
-
- # ==================== ADMIN LOGIN ====================
- print_section "2. Login Admin"
- response=$(curl -s -w "\n%{http_code}" -X POST \
- -H "Content-Type: application/json" \
- -d "{\"username\":\"$ADMIN_USERNAME\",\"password\":\"$ADMIN_PASSWORD\"}" \
- "${API_BASE_URL}/api/v2/admin/auth/login")
-
- http_code=$(echo "$response" | tail -n1)
- body=$(echo "$response" | sed '$d')
-
- if [ "$http_code" -eq 200 ]; then
- ADMIN_TOKEN=$(echo "$body" | grep -o '"access_token":"[^"]*' | cut -d'"' -f4)
- if [ -n "$ADMIN_TOKEN" ]; then
- print_success "Login Admin réussi - Token obtenu"
- print_info "Token Admin: ${ADMIN_TOKEN:0:50}..."
- else
- print_fail "Login Admin réussi mais token non trouvé"
- print_response "$body"
- exit 1
- fi
- else
- print_fail "Échec du login Admin (HTTP $http_code)"
- print_response "$body"
- exit 1
- fi
-}
-
-# =============================================================================
-# Tests SQL Injection
-# =============================================================================
-
-test_sql_injection() {
- print_header "TESTS SQL INJECTION"
-
- print_section "1. SQL Injection - Login"
-
- # Test 1: SQL Injection classique dans login client
- http_test_no_auth "POST" "/api/v1/auth/login" \
- '{"username":"admin'\'' OR '\''1'\''='\''1","password":"test"}' \
- 403 "SQLi - Login Client OR 1=1"
-
- # Test 2: SQL Injection dans login admin
- http_test_no_auth "POST" "/api/v2/admin/auth/login" \
- '{"username":"admin'\'' OR '\''1'\''='\''1","password":"test"}' \
- 403 "SQLi - Login Admin OR 1=1"
-
- # Test 3: SQL Injection avec UNION
- http_test_no_auth "POST" "/api/v1/auth/login" \
- '{"username":"admin'\'' UNION SELECT * FROM users--","password":"test"}' \
- 403 "SQLi - UNION SELECT"
-
- # Test 4: SQL Injection avec DROP TABLE
- http_test_no_auth "POST" "/api/v1/auth/login" \
- '{"username":"admin'\''; DROP TABLE users;--","password":"test"}' \
- 403 "SQLi - DROP TABLE"
-
- # Test 5: SQL Injection avec commentaire
- http_test_no_auth "POST" "/api/v1/auth/login" \
- '{"username":"admin'\''--","password":"test"}' \
- 403 "SQLi - Commentaire SQL --"
-
- print_section "2. SQL Injection - Panier"
-
- # Test 6: SQL Injection dans name_product
- http_test_client "POST" "/api/v1/panier/add" \
- '{"name_product":"Pizza'\'' OR 1=1--","category":"pizza","quantity":1}' \
- 403 "SQLi - Panier name_product"
-
- # Test 7: SQL Injection dans category
- http_test_client "POST" "/api/v1/panier/add" \
- '{"name_product":"Pizza","category":"pizza'\'' OR '\''1'\''='\''1","quantity":1}' \
- 403 "SQLi - Panier category"
-
- print_section "3. SQL Injection - Admin"
-
- # Test 8: SQL Injection dans username pénalité
- http_test_admin "POST" "/api/v2/admin/protected/penalty" \
- "{\"username\":\"admin' OR '1'='1\",\"amount\":50.0,\"reason\":\"Test\"}" \
- 403 "SQLi - Username pénalité"
-
- # Test 9: SQL Injection dans paramètres commandes
- http_test_admin "GET" "/api/v2/admin/protected/orders?status=pending' OR '1'='1" \
- "" \
- 403 "SQLi - Paramètres commandes"
-
- # Test 10: SQL Injection dans ID commande
- http_test_admin "POST" "/api/v2/admin/protected/orders/1' OR '1'='1/auto-assign" \
- "" \
- 403 "SQLi - ID commande"
-
- # Test 11: SQL Injection dans username livreur
- http_test_admin "GET" "/api/v2/admin/protected/delivery-persons/john' OR '1'='1/location" \
- "" \
- 403 "SQLi - Username livreur"
-
- print_section "4. SQL Injection - Commandes Client"
-
- # Test 12: SQL Injection dans adresse checkout
- http_test_client "POST" "/api/v1/checkout" \
- '{"delivery_address":"1'\'' OR '\''1'\''='\''1"}' \
- 403 "SQLi - Adresse checkout"
-
- # Test 13: SQL Injection nom produit admin
- http_test_admin "POST" "/api/v2/admin/protected/products" \
- '{"nom":"Pizza'\'' OR '\''1'\''='\''1","category":"pizza","stock":10,"prix":12.99}' \
- 403 "SQLi - Nom produit admin"
-
- print_section "5. SQL Injection - Variantes avancées"
-
- # Test 14: SQL Injection avec AND
- http_test_no_auth "POST" "/api/v1/auth/login" \
- '{"username":"admin'\'' AND '\''1'\''='\''1","password":"test"}' \
- 403 "SQLi - AND condition"
-
- # Test 15: SQL Injection avec encodage hex
- http_test_no_auth "POST" "/api/v1/auth/login" \
- '{"username":"admin'\'' OR 0x31=0x31--","password":"test"}' \
- 403 "SQLi - Encodage hex"
-
- # Test 16: SQL Injection avec SLEEP (Time-based)
- http_test_no_auth "POST" "/api/v1/auth/login" \
- '{"username":"admin'\'' AND SLEEP(5)--","password":"test"}' \
- 403 "SQLi - Time-based SLEEP"
-
- # Test 17: SQL Injection avec BENCHMARK
- http_test_no_auth "POST" "/api/v1/auth/login" \
- '{"username":"admin'\'' AND BENCHMARK(10000000,SHA1('\''test'\''))--","password":"test"}' \
- 403 "SQLi - BENCHMARK"
-
- # Test 18: SQL Injection avec sous-requête
- http_test_no_auth "POST" "/api/v1/auth/login" \
- '{"username":"admin'\'' AND (SELECT COUNT(*) FROM users)>0--","password":"test"}' \
- 403 "SQLi - Sous-requête"
-}
-
-# =============================================================================
-# Tests XSS (Cross-Site Scripting)
-# =============================================================================
-
-test_xss() {
- print_header "TESTS XSS (CROSS-SITE SCRIPTING)"
-
- print_section "1. XSS - Login"
-
- # Test 1: XSS basique avec script tag
- http_test_no_auth "POST" "/api/v1/auth/login" \
- '{"username":"","password":"test"}' \
- 403 "XSS - Script tag basique"
-
- # Test 2: XSS avec event handler
- http_test_no_auth "POST" "/api/v1/auth/login" \
- '{"username":"
","password":"test"}' \
- 403 "XSS - Event handler onerror"
-
- # Test 3: XSS avec SVG
- http_test_no_auth "POST" "/api/v1/auth/login" \
- '{"username":"