Newer
Older

Massiles Ghernaout
a validé
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.
Massiles Ghernaout
a validé
- **backend** : API Node.js/Express pour gérer les jobs de bruteforce, le **cache des hash** (Redis), 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.
Massiles Ghernaout
a validé
- **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`).
Massiles Ghernaout
a validé
### 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
```
Massiles Ghernaout
a validé
**Flux utilisateur (UI)** :
* Le frontend envoie des hash au backend (`POST /hash/manual`).
* Le backend vérifie d’abord le **cache des hash** (`jobs:cache`) ; en cas de hit, il crée un job « synthétique » et renvoie immédiatement `202 { id }` sans mettre en file. Sinon, le job est mis en file Redis.
* Les workers consomment la file, bruteforcent, écrivent les résultats et mettent à jour le cache
* Le frontend récupère la liste des jobs via `GET /cluster/jobs`.
* Le scaler ajuste le nombre de réplicas du service `hash_worker` en fonction de la charge.
**Flux tester** :
* Le conteneur `hash_checker` se connecte en WebSocket au `hash_proxy`.
* Il envoie `search MD5_HASH BEGIN END`.
* Le proxy appelle `POST /tester/search`.
* Le backend applique le même middleware de cache, mais n’utilise le cache que si le résultat en cache est **trouvé** (`found: true`), afin de garantir la cohérence des plages `begin`/`end`. Sinon, le job est mis en file.
* Le proxy poll `GET /tester/job/:id` et renvoie `found` ou `notfound` au checker.
Massiles Ghernaout
a validé
#### 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
Massiles Ghernaout
a validé
Backend->>Redis: HGET jobs:cache (middleware cache)
alt Cache hit (selon règles frontend/tester)
Backend->>Redis: HSET jobs:results, jobs:status, jobs:meta, LPUSH jobs:recent
Backend-->>Client: 202 { id }
else Pas de cache
Backend->>Redis: LPUSH jobs:pending, HSET jobs:status, jobs:meta, LPUSH jobs:recent
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, jobs:cache
Worker->>Redis: SREM jobs:in_progress
end
Massiles Ghernaout
a validé
loop Polling
Massiles Ghernaout
a validé
Client->>Backend: GET /cluster/jobs ou GET /tester/job/:id
Backend->>Redis: HGET jobs:meta, jobs:status, jobs:results
Backend-->>Client: liste jobs ou résultat
Massiles Ghernaout
a validé
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
```
Massiles Ghernaout
a validé
#### Cache des hash
Pour éviter de re-bruteforcer un même hash déjà traité, un **cache** est géré dans Redis.
- **Clé Redis** : `jobs:cache` (hash Redis : clé = hash MD5, valeur = JSON `{ found, plaintext, elapsedMs }`).
- **Lecture (backend)** : un middleware Express `cacheHashOrNext` est appliqué à `POST /hash/manual` et `POST /tester/search`. Avant toute mise en file, il vérifie si le hash est présent dans `jobs:cache`. En cas de hit :
- **Frontend** : tout résultat en cache (trouvé ou non) est réutilisé ; le backend crée un job « synthétique » (résultat, statut, métadonnées, liste des jobs récents) et renvoie `202 { id }` sans toucher à la file.
- **Tester** : le cache n’est utilisé que si le résultat en cache a `found === true`, afin de ne pas renvoyer « non trouvé » pour une plage `begin`/`end` différente.
- **Écriture (worker)** : après chaque bruteforce réussi, le worker écrit dans `jobs:cache` le résultat (trouvé ou non) associé au hash, pour les soumissions futures.
Le worker ne consulte pas le cache : toute décision de cache est prise côté backend à la soumission.
Massiles Ghernaout
a validé
---
### Prérequis
- Docker et Docker Swarm initialisé (`docker swarm init`).
- Node.js (pour le développement local du backend et du frontend).
Massiles Ghernaout
a validé
### Auto-scaling
Massiles Ghernaout
a validé
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).
Massiles Ghernaout
a validé
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. |
Massiles Ghernaout
a validé
| `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). |
Massiles Ghernaout
a validé
---
### 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.