## Projet Docker Swarm – Bruteforce MD5 ![coverage](https://www-apps.univ-lehavre.fr/forge/gm213204/killemd5/badges/master/coverage.svg?job=build-and-test) Ce dépôt contient une petite infrastructure Docker Swarm capable de bruteforcer des hash MD5 de manière scalable, ainsi qu’une application web pour piloter et monitorer le cluster. --- ### Sous-projets - **backend** : API Node.js/Express pour gérer les jobs de bruteforce, l’état du cluster, et le scaling des workers. - **worker** : service de bruteforce MD5 (conteneurs réplicables dans le Swarm). - **frontend** : application React permettant d’envoyer des hash, choisir les modes *gentil/normal/agressif* et visualiser l’état du cluster. - **infra** : configuration Docker Swarm (stack) et scripts éventuels. - **proxy** : service Node.js qui expose un WebSocket compatible avec le tester de l’enseignant et le traduit en appels HTTP vers le backend. - **CI** : workflows d’intégration continue (fichier `.gitlab-ci.yml`). --- ### Architecture #### Vue d’ensemble des services (stack Swarm) Tous les services tournent sur le réseau overlay `md5_net`. Le backend et le frontend exposent des ports sur l’hôte. > *Note: Veuillez installer l'extention vsCODE: Markdown Preview: Mermaid Support pour visualiser les diagrammes.* ```mermaid flowchart LR subgraph md5_net [Réseau md5_net] Frontend[frontend] Backend[api_backend] Redis[redis] Worker[hash_worker] Proxy[hash_proxy] Checker[hash_checker] end User[Utilisateur] -->|":5173"| Frontend Frontend -->|"HTTP :8080"| Backend Backend --> Redis Backend -->|"Docker API"| Worker Worker --> Redis Checker -->|"WebSocket :3000"| Proxy Proxy -->|"HTTP :8080"| Backend ``` - **Flux utilisateur (UI)** : le frontend envoie des hash au backend (`POST /hash/manual`), qui les met en file dans Redis. Les workers consomment la file, bruteforcent et écrivent les résultats dans Redis ; le backend lit l’état et les résultats (`GET /hash/:id`). Le scaler (dans le backend) ajuste le nombre de réplicas du service `hash_worker` en fonction de la charge. - **Flux tester** : le conteneur `hash_checker` (image enseignante) se connecte en WebSocket au `hash_proxy`. Il envoie `search MD5_HASH BEGIN END`. Le proxy appelle `POST /tester/search` puis poll `GET /tester/job/:id`, et renvoie `found` ou `notfound` au checker. #### Flux de traitement d’un job (utilisateur ou tester) ```mermaid sequenceDiagram participant Client as Client (frontend ou proxy) participant Backend as api_backend participant Redis as redis participant Worker as hash_worker Client->>Backend: POST /hash/manual ou POST /tester/search Backend->>Redis: LPUSH jobs:pending, HSET jobs:status Backend-->>Client: 202 { id } Worker->>Redis: BRPOP jobs:pending Worker->>Redis: SADD jobs:in_progress Worker->>Worker: bruteforce (optionnellement entre begin/end) Worker->>Redis: HSET jobs:results, jobs:status Worker->>Redis: SREM jobs:in_progress loop Polling Client->>Backend: GET /hash/:id ou GET /tester/job/:id Backend->>Redis: HGET jobs:results ou jobs:status Backend-->>Client: résultat ou statut end ``` #### Rôle du proxy (intégration tester) Le proxy adapte le protocole WebSocket du tester à l’API HTTP du backend. ```mermaid flowchart LR subgraph Tester [Tester enseignant] Checker[hash_checker] end subgraph NotreStack [Notre stack] Proxy[hash_proxy] Backend[api_backend] end Checker -->|"search HASH BEGIN END"| Proxy Proxy -->|"POST /tester/search"| Backend Proxy -->|"GET /tester/job/:id"| Backend Backend -->|"found / notfound"| Proxy Proxy -->|"found HASH PLAINTEXT"| Checker ``` --- ### Prérequis - Docker et Docker Swarm initialisé (`docker swarm init`). - Node.js (pour le développement local du backend et du frontend). --- ### Auto-scaling Un **scaler** tourne dans le processus du backend. Il lit périodiquement la file Redis (`jobs:pending`) et le nombre de workers, puis ajuste le nombre de réplicas du service worker Swarm entre un min et un max configurables. Les seuils sont basés sur la charge (jobs par worker) : scale up si (jobs en attente / workers) dépasse un seuil, scale down si ça tombe en dessous d’un seuil plus bas (et qu’aucun job n’est en cours). Variables d’environnement (optionnelles, sur le service `api_backend`) : | Variable | Défaut | Description | |----------|--------|-------------| | `SCALER_ENABLED` | `true` | Mettre à `false` pour désactiver le scaler (ex. dev local sans Swarm). | | `SCALER_INTERVAL_MS` | `10000` | Période entre deux évaluations (ms). | | `SCALER_MIN_REPLICAS` | `1` | Nombre minimum de workers. | | `SCALER_MAX_REPLICAS` | `10` | Nombre maximum de workers. | | `SCALER_SCALE_UP_WHEN_JOBS_PER_WORKER_ABOVE` | `4` | Scale up si (jobs en attente / workers) ≥ cette valeur. | | `SCALER_SCALE_DOWN_WHEN_JOBS_PER_WORKER_BELOW` | `1` | Scale down si (jobs en attente / workers) ≤ cette valeur (et aucun job en cours). | --- ### Déploiement via Docker Swarm (stack) 1. Construire les images localement (ou via la CI) : - `docker build -t md5-swarm-backend:latest ./backend` - `docker build -t md5-swarm-worker:latest ./worker` - `docker build -t md5-swarm-frontend:latest ./frontend` 2. Initialiser Swarm si besoin : - `docker swarm init` 3. Déployer la stack : - `cd infra` - `docker stack deploy -c stack.yml md5-swarm` 4. Accéder à l’application : - Backend : `http://localhost:8080` - Frontend (proxy Nginx dans le conteneur) : `http://localhost:5173` La stack crée un service Redis, un backend qui gère la file de jobs dans Redis, un worker scalable pour le bruteforce, et un frontend pour piloter le tout. --- ### Intégration avec le tester de l’enseignant Le dépôt peut être testé automatiquement via l’image Docker `servuc/hash_extractor` fournie par l’enseignant : - **Proxy WebSocket** (`hash_proxy`) : - Service Node.js (dossier `proxy/`) qui expose l’interface WebSocket attendue par `hash_extractor`. - Il reçoit des commandes `search MD5_HASH BEGIN END`, les traduit en appels HTTP vers le backend et renvoie `found MD5_HASH PLAINTEXT` ou `notfound MD5_HASH ""` selon le résultat. - **Endpoints dédiés `/tester`** dans le backend : - `POST /tester/search` : accepte `{ hash, begin, end }`, crée un job de bruteforce borné et renvoie `{ id }`. - `GET /tester/job/:id` : renvoie un état normalisé du job, par exemple `{ status: "done", found: true, plaintext: "pina" }`. - **Worker range-aware** : - Le worker lit éventuellement `begin` et `end` dans le job et ne considère que les candidats compris dans cet intervalle (selon l’ordre de génération des chaînes). Dans `infra/stack.yml`, deux services supplémentaires sont définis : - `hash_proxy` : connecté au backend sur le réseau `md5_net`. - `hash_checker` : conteneur `servuc/hash_extractor:1.0.0` lancé en mode `c`, configuré avec `MASTER_WS=ws://hash_proxy:3000` pour piloter automatiquement le cluster. Pour lancer un test de bout en bout localement : - `cd infra && docker stack deploy -c stack.yml md5-swarm` - Surveiller les logs des services `hash_proxy`, `hash_checker`, `api_backend` et `hash_worker` avec `docker service logs -f ...` pour voir le scénario se dérouler. --- ### Tests & couverture - **Tests backend** : - `cd backend` - `npm test` - Les tests utilisent le runner intégré de Node.js (`node --test`) avec la collecte de couverture activée. - **CI GitLab** : - Le job `build-and-test` dans `.gitlab-ci.yml` exécute les tests backend, le build frontend et extrait le pourcentage de couverture à partir du rapport de Node. - Le badge en haut de ce README reflète la couverture de la branche par défaut. --- ### Licence Ce projet est distribué sous licence MIT. Voir le fichier `LICENSE.txt` pour plus de détails. --- ### À faire / améliorations possibles - Durcir la configuration de sécurité (CORS plus restrictif, `helmet`, etc.). - Ajouter davantage de tests (notamment sur le frontend). - Documenter en détail les endpoints de l’API et les scénarios d’utilisation côté UI.