Files
WebNationsGlory_ServeurBuil…/ANALYSIS.md

27 KiB

📊 Analyse Complète : NationsGlory Web Admin Panel + Serveur Minecraft

📋 Table des Matières

  1. Architecture Générale
  2. Application Web
  3. Serveur Minecraft
  4. Intégration
  5. Points de Sécurité
  6. Recommandations

Architecture Générale

Stack Technique

┌─────────────────────────────────────────────────────────┐
│  Frontend (SPA Vanilla JS)                              │
│  - index.html, app.js, style.css                       │
│  - API_URL: http://<hostname>:4001/api                 │
└────────────────────┬────────────────────────────────────┘
                     │ HTTP REST
┌────────────────────▼────────────────────────────────────┐
│  Backend (Express.js + Node.js 18)                      │
│  - server.js (port 4001, listens on 0.0.0.0)           │
│  - 7 routes: auth, server, rcon, logs, players,        │
│    whitelist, backup                                    │
└────────────────────┬────────────────────────────────────┘
                     │ RCON (port 25575)
┌────────────────────▼────────────────────────────────────┐
│  Minecraft Server (mcpc.jar / Forge)                    │
│  - Version: 1.6.4 (MCPC+)                               │
│  - Mods: 60+ mods (Nations UI, FlansMod, etc)          │
│  - Port: 25565 (server), 25575 (RCON)                  │
└─────────────────────────────────────────────────────────┘

Déploiement:
┌─────────────────────────────────────────────────────────┐
│  Docker Compose (machine distante: 192.168.1.252)       │
│  - Container webnationsglory-admin                      │
│  - Volume mount: /mc-server → serveur Minecraft         │
│  - Restart: unless-stopped                             │
│  - Port mapping: 4001:4001                             │
└─────────────────────────────────────────────────────────┘

Taille & Ressources

  • Serveur Minecraft: 143 MB (world + config + mods)
  • Web App: ~200 KB (frontend + backend source)
  • Docker Image: ~200 MB (Node.js 18-alpine + modules)

Application Web

Backend Architecture

1. Serveur Principal (backend/src/server.js)

// Configuration
const PORT = 4001;
const SERVER_DIR = '/mc-server' (Docker) ou local path
const SESSION_SECRET = process.env.SESSION_SECRET

// Middlewares
- express.json() / urlencoded
- CORS (origin: true, credentials: true)
- express-session (24h max age, httpOnly)

// Routes
/api/auth      → Authentification + enregistrement
/api/server    → Configuration serveur (server.properties)
/api/rcon      → Exécution commandes serveur
/api/logs      → Historique logs
/api/players   → Liste joueurs + statut OP
/api/whitelist → Gestion whitelist
/api/backup    → Gestion backups

Points clés:

  • Frontend path auto-detection (Docker vs local)
  • CORS enabled avec credentials
  • Session 24h max
  • ⚠️ Session secret en dur ("your-secret-key-change-in-prod")
  • ⚠️ HTTPS désactivé (secure: false)

2. Routes d'Authentification (backend/src/routes/auth.js)

Endpoints:

POST /register   → Créer compte admin (vérifie que MC username est OP)
POST /login      → Connexion
POST /logout     → Déconnexion
GET  /check      → Vérifier session active
POST /change-password → Changer mot de passe

Mécanisme:

// Enregistrement
1. Vérifier que c'est le premier compte (users.json vide)
2. Lire ops.txt OU ops.json depuis serveur
3. Vérifier que mcUsername est dans la liste OPs
4. Hash password avec bcryptjs (10 rounds)
5. Sauvegarder dans users.json

// Connexion
1. Trouver utilisateur par username
2. Comparer password avec hash bcrypt
3. Créer session req.session.user
4. Session persiste dans memory (⚠️ perd les sessions au redémarrage!)

Fichiers utilisés:

  • backend/data/users.json → Stockage utilisateurs + passwords hashés
  • ~/NationsGlory_ServeurBuild_Red/ops.txt → Admins serveur
  • ~/NationsGlory_ServeurBuild_Red/ops.json → Alternative format OPs

Risques de sécurité:

  • ⚠️ Sessions en mémoire uniquement (pas persistentes)
  • ⚠️ users.json stocké en local/Docker (pas de base de données)
  • ⚠️ Pas de rate limiting sur login
  • ⚠️ Pas de 2FA

3. Routes Serveur (backend/src/routes/server.js)

Endpoints:

GET  /           → Lire server.properties
POST /update     → Modifier une propriété
GET  /jvm-args   → Lire arguments JVM
POST /restart    → Redémarrer le serveur
POST /stop       → Arrêter le serveur
POST /backup     → Créer backup

Implémentation:

  • Parse server.properties ligne par ligne
  • Supporte modification de propriétés individuelles
  • Contrôle via RCON pour restart/stop

4. Routes RCON (backend/src/routes/rcon.js)

Architecture RCON:

// Classe RconClient (backend/src/utils/rcon.js)
- Protocole: Minecraft RCON (TCP port 25575)
- Packet format: [size][id][type][payload][null]
- Type 3 = Auth, Type 2 = Command, Type 0 = Response
- Timeout: 5s (auth), 10s (command)

// Implémentation
1. Parse server.properties pour rcon.port + rcon.password
2. Créer socket TCP vers serveur
3. S'authentifier avec password
4. Envoyer commandes
5. Recevoir réponses avec stream buffer
6. Timeout après 10s

Endpoints:

POST /command          → Exécuter commande RCON
GET  /history          → Historique 200 dernières commandes
DELETE /history/:id    → Nettoyer historique

Commandes supportées:

  • say <msg> → Message serveur
  • stop → Arrêter serveur
  • restart → Redémarrer (custom)
  • list → Joueurs en ligne (parsé pour joueurs)
  • op <player> → Ajouter OP
  • whitelist add <player> → Ajouter whitelist
  • Tout ce que le serveur Minecraft supporte

Historique:

  • Stocké dans .web-admin/rcon-history.json
  • Limité à 200 dernières commandes
  • Contient: timestamp, command, response, success, error

5. Routes Joueurs (backend/src/routes/players.js)

Endpoints:

GET / → Liste tous joueurs + statut OP + dernière connexion

Implémentation:

// 1. Lire world/players/*.dat (fichiers joueurs)
// 2. Mapper UUID → Nom via usercache.json
// 3. Lire ops.txt et parser noms OPs
// 4. Ajouter champ isOp: boolean pour chaque joueur
// 5. Retourner liste avec:
{
  players: [
    { uuid, name, isOp, lastPlayed }
  ]
}

Données sources:

  • world/players/*.dat → Fichiers joueurs Minecraft
  • usercache.json → Mapping UUID ↔ Nom (si existe)
  • ops.txt → Noms des OPs (nouvelle feature)

6. Routes Whitelist (backend/src/routes/whitelist.js)

Endpoints:

GET  /              → Lire whitelist
POST /add           → Ajouter joueur
POST /remove        → Retirer joueur

Support formats:

  • whitelist.json → Format moderne [{name, uuid}]
  • whitelist.txt → Format legacy, 1 nom/ligne

Implémentation:

  • Auto-détecte format (JSON ou TXT)
  • Priorise JSON si les deux existent
  • Ajoute validation de doublons

7. Routes Logs (backend/src/routes/logs.js)

Endpoints:

GET / → Logs serveur (recent-latest.log + ancien logs.1, logs.2, etc)

Parsing:

  • Supporte format colorisé Minecraft
  • Convertit codes Minecraft (§X) en HTML
  • Retourne HTML colorisé pour UI

8. Routes Backup (backend/src/routes/backup.js)

Endpoints:

GET  /          → Lister backups existants
POST /create    → Créer nouveau backup (tar.gz)
GET  /download  → Télécharger backup
POST /restore   → Restaurer depuis backup

Implémentation:

tar --exclude='.web-admin' --exclude='*.log.lck' \
    -czf "backup-<timestamp>.tar.gz" .

Répertoire: backups/ dans SERVER_DIR


Frontend Architecture

1. Structure SPA (frontend/public/js/app.js)

// État global
let currentUser = null;
let isAuthenticated = false

// Points d'entrée
checkAuth()              // Vérifier session
showLoginPage()          // Authentification
showDashboard()          // Interface admin
switchTab(tabName)       // Navigation

// Sections disponibles (onglets)
- Dashboard             Infos serveur + joueurs en ligne
- Joueurs               Liste tous joueurs, statut OP
- Whitelist             Gérer whitelist
- Commandes RCON        Interface ligne de commande
- Logs                  Consulter logs serveur
- Serveur               Settings server.properties
- Backups               Gérer backups + restore
- Paramètres            Changement password

2. API_URL Resolution

// Avant: hardcoded localhost
const API_URL = 'http://localhost:4001/api';

// Après: Dynamic hostname detection
const API_URL = window.location.hostname === 'localhost' || 
                window.location.hostname === '127.0.0.1'
    ? 'http://localhost:4001/api'
    : `http://${window.location.hostname}:4001/api`;

Impact: Permet accès via IP (192.168.1.252) sans modification code

3. Authentification Frontend

// Login Flow
checkAuth()  
  fetch /auth/check 
    Authentifié  showDashboard()
    Non-auth  showLoginPage()  handleLogin()  fetch /auth/login

// Données transmises
POST /api/auth/login {
  username: string,
  password: string
}

// Réponse
{ authenticated: true, user: { username, mcUsername } }

4. Dashboard Principal

┌─────────────────────────────────────────────────┐
│ NationsGlory Admin Panel  🔓 admin ▼ Logout     │
├─────────────────────────────────────────────────┤
│ Tabs: [Dashboard] [Joueurs] [Whitelist] [RCON]  │
│       [Logs] [Serveur] [Backups] [Settings]     │
├─────────────────────────────────────────────────┤
│ 📊 Dashboard                                     │
│ • Joueurs connectés: 0/20 ⚪                     │
│ • Statut serveur: ON/OFF                         │
│ • Mods chargés: 60+                              │
│ • World: FLAT, seed: [value]                     │
│ • Max build height: 256                          │
├─────────────────────────────────────────────────┤
│ 👥 Joueurs en ligne                             │
│ [Rafraîchir]                                     │
│ 📋 Tous les Joueurs                             │
│ [Table avec columns: Nom, OP, UUID, LastPlayed] │
└─────────────────────────────────────────────────┘

5. Sections Clés

A. Joueurs (loadPlayersData())

  • Affiche tous les joueurs jamais connectés
  • Colonne OP: OP ou
  • Colonne UUID + dernière connexion
  • Chargement RCON list pour joueurs en ligne en temps réel

B. Whitelist (getWhitelistHTML())

  • Ajouter / Retirer joueurs
  • Support JSON et TXT formats
  • Validation doublons

C. RCON Terminal (getRconHTML())

  • Interface ligne de commande
  • Input texte + historique
  • Exécution commandes
  • Affichage résultats

D. Logs (getLogsHTML())

  • Lecture logs serveur
  • Coloration codes Minecraft
  • Scroll horizontal si long

E. Serveur Settings (getServerHTML())

  • Liste properties modifiables
  • Boutons Start/Stop/Restart
  • Actions avec confirmation

F. Backups (getBackupsHTML())

  • Lister backups
  • Créer backup
  • Télécharger
  • Restaurer depuis backup

G. Settings (getSettingsHTML())

  • Changement mot de passe
  • About version

Serveur Minecraft

Configuration Serveur

Server Properties (server.properties)

server-ip=                    # Écoute sur toutes interfaces
server-port=25565            # Port Minecraft standard
max-players=20               # Limite 20 joueurs
gamemode=1                   # Creative mode
difficulty=1                 # Normal
level-type=FLAT              # Monde plat
level-name=world             # Dossier monde
enable-rcon=true             # RCON activé
rcon.port=25575              # Port RCON
rcon.password=Landau8210     # ⚠️ Password en clair!
online-mode=false            # Offline mode (permet cracked clients)
pvp=true                      # PvP activé
allow-nether=true            # Nether autorisé
spawn-animals=true           # Génération animaux
white-list=false             # Whitelist désactivée par défaut

Structure Serveur

NationsGlory_ServeurBuild_Red/
├── world/                      # Données du monde
│   ├── players/                # Fichiers joueurs (.dat)
│   ├── stats/                  # Stats joueurs (.json)
│   ├── region/                 # Chunks du monde
│   └── level.dat              # Info niveau
├── mods/                       # 60+ mods Minecraft
│   └── [liste complète ci-dessous]
├── plugins/                    # Plugins serveur
├── config/                     # Configuration mods (60+ fichiers .cfg)
├── libraries/                  # Dépendances Java
├── customnpcs/                 # NPCs custom
├── Flan/                       # Config FlansMod
├── .web-admin/                 # Historique RCON
├── mcpc.jar                    # Serveur MCPC+
├── server.properties           # Configuration
├── ops.txt                     # Admins serveur (format texte)
├── ops.json                    # Alternative format OPs
├── whitelist.txt               # Whitelist (TXT)
├── whitelist.json              # Alternative whitelist (JSON)
├── banned-players.txt          # Bannis
├── banned-ips.txt              # IPs bannies
├── usercache.json              # Cache UUID ↔ Nom (si existe)
└── backups/                    # Sauvegardes (créées par app)

Taille: 143 MB

Mods/Plugins Identifiés

Via config/*.cfg:

  1. NationsGlory mods

    • ngcore.cfg → Nations Core
    • ngcontent.cfg → Contenu Nations
    • nationsui.cfg → Interface Nations
    • nationsgui.json
    • nationsmachine.cfg → Machines Nations
    • NGUpgrades.json
  2. Gameplay Mods

    • FlansMod.cfg → Armes, véhicules
    • WeaponMod.cfg → Armes custom
    • ICBM.cfg → Missiles
    • CustomNpcs.cfg → NPCs custom
    • GetAllTheSeeds.cfg
    • AnimalBikes.cfg
  3. Building/Tech

    • Chisel.cfg → Blocs décoratifs
    • BiblioCraft.cfg → Furniture
    • ArmorStatusHUD.cfg
    • TLSpecialArmor.cfg
  4. Farming

    • PAM mods (multiple):
      • pamtemperateplants.cfg
      • pamweeeflowers.cfg
      • pamrandomaplants.cfg
      • pamextendedglass.cfg
  5. Infrastructure

    • Galacticraft/ → Espace
    • Netherrocks → Nether
    • AquaTweaks.cfg → Eau
    • MelonSpawn.cfg
    • Autoutils.cfg
  6. Visualization

    • MapWriter.cfg → Mini-map
    • ArmorStatusHUD.cfg
  7. Framework/Admin

    • forge.cfg → Forge base
    • forgeChunkLoading.cfg
    • bspkrsCore.cfg → Libraire
    • logging.properties

Version: 1.6.4 (Minecraft 1.6.4, probablement MCPC+ pour Forge)

Architecture Serveur MCPC+

MCPC+ = Minecraft + Bukkit compatibility + Forge mods

  • Combine Minecraft serveur vanilla
  • Ajoute Forge pour mods
  • Supporte plugins Bukkit (en parallèle)
  • Version 1.6.4 (assez vieille, 2013)

Intégration

Flux de Données

Frontend (Browser)
    ↓ fetch /api/auth/login
Backend (Express)
    ├─ Vérifie users.json
    ├─ Hash password bcrypt
    ├─ Crée session
    └─ Return { authenticated: true }
    ↓ fetch /api/rcon/command
Backend RCON Client
    ├─ Parse server.properties
    ├─ Connect TCP:25575
    ├─ Auth avec rcon.password
    ├─ Send command bytes
    └─ Receive/parse response
    ↓
Minecraft Server (MCPC+)
    ├─ Process command
    ├─ Modify world/players/ ou server.properties
    └─ Send output back
    ↓
Backend Response
    └─ Return output JSON
    ↓
Frontend Display
    └─ Show result to user

Session Management

Current: Express-session in-memory

app.use(session({
  secret: SESSION_SECRET,
  resave: false,
  saveUninitialized: true,
  cookie: { 
    secure: false,      // HTTP only (not HTTPS)
    httpOnly: true,     // No JS access
    sameSite: 'lax',    // CSRF protection
    maxAge: 24 * 60 * 60 * 1000  // 24 hours
  }
}))

Problème: Sessions perdues au redémarrage Docker

  • currentUser reste authentifié tant que session active
  • Redémarrage container = logout automatique
  • Solution: Utiliser connect-mongo, redis, ou JWT

RCON Integration

Web UI → Command → Backend → RCON Client → Minecraft Server → Response

Example: /api/rcon/command POST {"command": "list"}

  1. Backend RCON Client:

    - Read: server.properties (rcon.port=25575, rcon.password=Landau8210)
    - Connect: TCP 192.168.1.252:25575
    - Authenticate: send password bytes
    - Send: "list" command
    - Parse: "There are 1/20 players online: anakine22"
    - Return: JSON response
    
  2. Frontend parses & displays


Points de Sécurité

🔴 Critiques

  1. RCON Password en Clair

    rcon.password=Landau8210  # Visible dans server.properties
    

    Risque: Accès direct au serveur Minecraft si fichier leak Fix: Lire depuis env vars, pas fichier

  2. Session en Mémoire

    // Sessions perdues au redémarrage
    // Accessible seulement au container courant (pas clustering)
    

    Risque: Forcer logout en case de crash/redémarrage Fix: Store sessions en Redis/DB

  3. HTTP seulement

    secure: false  // No HTTPS
    

    Risque: Credentials en clair sur le réseau Fix: Activer HTTPS, self-signed cert minimum

  4. users.json pas encrypté

    backend/data/users.json
    

    Contient: Passwords bcryptés (OK) + usernames (leak de données) Fix: Chiffrer fichier ou utiliser database

🟡 Modérés

  1. Pas de Rate Limiting

    Brute force possible sur endpoint /auth/login
    

    Fix: express-rate-limit middleware

  2. Pas de 2FA

    Seul username/password
    

    Fix: Ajouter TOTP si critique

  3. CORS trop permissif

    CORS({ origin: true, credentials: true })
    

    Risque: N'importe quel domaine peut faire requêtes Fix: Whitelist domains explicitement

  4. Pas de CSRF tokens

    State-changing operations (POST/DELETE) sans CSRF
    

    Fix: Ajouter csurf middleware

  5. Pas de input validation

    // POST /api/server/update
    { property, value }  // Pas de validation property names
    

    Risque: Injection server.properties arbitraire Fix: Whitelist propriétés modifiables

  6. Fichiers logs exposés

    GET /api/logs expose tous les logs du serveur
    

    Risque: Info sensitive (errors, plugins, config) Fix: Limiter logs, filtrer data sensitive

🟢 Acceptables

  1. online-mode=false

    Serveur accepte cracked clients (offline mode)
    

    Pourquoi: Peut être intentionnel pour privé réseau

  2. Debug pas activé

    debug=false  ✓
    
  3. Entity tracking config non visible


Recommandations

🚀 Priorité 1: Critique

1. Ajouter HTTPS/SSL

# docker-compose.yml
volumes:
  - ./certs:/app/certs  # Certificates auto-renew via certbot
environment:
  - NODE_ENV=production
  - HTTPS_CERT=/app/certs/cert.pem
  - HTTPS_KEY=/app/certs/key.pem

2. Session Persistence (Redis)

# Ajouter redis service
version: '3'
services:
  app:
    # ...
    depends_on:
      - redis
  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data
// backend/src/server.js
const RedisStore = require('connect-redis').default;
const { createClient } = require('redis');

const redisClient = createClient({ host: 'redis', port: 6379 });
const store = new RedisStore({ client: redisClient });

app.use(session({
  store,
  secret: process.env.SESSION_SECRET,
  // ...
}));

3. RCON Password sécurisé

# .env
RCON_PASSWORD=${RCON_PASSWORD}  # Via docker-compose.yml

# Avoid storing in server.properties
# Option: Lire depuis /run/secrets/rcon_password (Docker Secrets)

4. Rate Limiting

// backend/src/middleware/rateLimit.js
const rateLimit = require('express-rate-limit');

const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,  // 15 min
  max: 5,                     // 5 tentatives
  message: 'Trop de tentatives login'
});

app.post('/api/auth/login', loginLimiter, handleLogin);

5. Validation Input Server Properties

// backend/src/routes/server.js
const ALLOWED_PROPERTIES = [
  'max-players',
  'difficulty',
  'pvp',
  'enable-nether',
  'server-ip',
  'server-port',  // Attention: change port!
  // NOT: gamemode, level-type, level-name, rcon.password, etc
];

if (!ALLOWED_PROPERTIES.includes(property)) {
  return res.status(400).json({ error: 'Propriété non modifiable' });
}

🎯 Priorité 2: Important

6. CSRF Tokens

const csrf = require('csurf');
const csrfProtection = csrf({ cookie: false, sessionKey: 'session' });

app.post('/api/server/update', csrfProtection, handleUpdate);

7. Chiffrer users.json

const crypto = require('crypto');
const FILE_KEY = Buffer.from(process.env.FILE_ENCRYPTION_KEY, 'hex');

function encryptUsers(users) {
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv('aes-256-gcm', FILE_KEY, iv);
  const encrypted = cipher.update(JSON.stringify(users));
  // ...
}

8. Logs Filtering

// backend/src/routes/logs.js
// Filtrer:
// - Passwords
// - Database credentials
// - API keys
// - Player IPs
// - Internal errors

9. Database Migration

Remplacer:
  users.json → PostgreSQL (+ migrations)
  RCON history JSON → Database table
  
Avantages:
  - Transactions
  - Backups
  - Multi-instance
  - Better performance

10. API Documentation

Ajouter Swagger/OpenAPI
  - /api-docs
  - Documentation endpoints
  - Authentification requirements

🛠️ Priorité 3: Nice to Have

11. Monitoring & Alerting

// Backend metrics
- Uptime server
- RCON connection failures
- API response times
- Error rate

// Integration: Prometheus + Grafana
// Discord webhooks for alerts

12. Admin Audit Log

// Log all admin actions
- Login/logout timestamps
- Command executor + command
- Property changes
- File modifications

13. World Backup Restoration

// Current: Créer backup ✓
// TODO: Restore backup avec safety checks
// - Stop serveur
// - Restore world/
// - Restart serveur
// - Verify integrité

14. Multi-Admin Support

// Current: 1 seul admin (users.json = array mais UI single)
// TODO:
// - Multiple admins support
// - Role-based access (RBAC)
// - Permissions per admin

15. Players Statistics

// Ajouter analytics:
// - Playtime per player
// - Last 7 days activity
// - Top builders/killers
// - Trends

Métriques de Santé

Points Forts

  1. Architecture modulaire → 7 routes bien séparées
  2. Vanilla JS frontend → Pas de build complexity
  3. RCON protocol bien implémenté → Pas de pertes commands
  4. Session management → Auth basique ok
  5. Docker-ready → Déploiement facile
  6. Markdown docs → QUICKSTART, DEPLOYMENT, MAINTENANCE
  7. Dynamic API URL → Fonctionne IP ou localhost
  8. OP status tracking → Lecture ops.txt correcte

⚠️ Domaines d'Amélioration

  1. Sécurité → HTTPS, rate limiting, validation input
  2. Persistence → Session, database
  3. Error handling → Logs réseau, retry logic
  4. Scalability → Multi-instance support
  5. Observability → Monitoring, alerting
  6. Testing → Tests unitaires + intégration
  7. Code quality → Linting, type checking
  8. Features → 2FA, RBAC, audit log

📈 Performance

  • Frontend: Single file SPA (~61 KB)
  • Backend: 104 lines server.js, routes <250 lines each
  • Response time: <100ms API (RCON varies)
  • Memory: ~50-100 MB Node.js container
  • Concurrency: Sequential RCON (une commande à la fois)

Conclusion

Current State

L'application est fonctionnelle pour un usage LAN privé ou réseau interne.

Prêt pour production?

  • Manque HTTPS, rate limiting, CSRF
  • Sessions perdues au redémarrage
  • Pas de database
  • Input validation insuffisante

Prêt pour LAN interne?

  • Sécurité acceptable pour réseau de confiance
  • Toutes features essentielles présentes
  • Déploiement Docker simple

Priorités à Court Terme

  1. Dynamic API URL (FAIT: app.js détecte hostname)
  2. OP status tracking (FAIT: lit ops.txt, affiche /)
  3. Session persistence (Redis recommended)
  4. HTTPS + rate limiting (Pour production)
  5. Input validation (Server properties + RCON)

Prochaines Étapes Recommandées

Phase 1 (Cette semaine)
  [ ] Tester OP display après refresh navigateur
  [ ] Documenter RCON commands disponibles
  [ ] Ajouter healthcheck serveur Minecraft

Phase 2 (Semaine 2)
  [ ] Implémenter Redis pour sessions
  [ ] Ajouter HTTPS auto-signed
  [ ] Rate limiting login

Phase 3 (Semaine 3)
  [ ] Migrer users.json → Database
  [ ] Input validation complete
  [ ] CSRF tokens

Document généré: 5 février 2026 Version: 1.0 Auteur: GitHub Copilot