import os import redis import hashlib import itertools import logging import subprocess from flask import Flask, request, jsonify from flask_cors import CORS # Import pour activer CORS # Configuration du logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) app = Flask(__name__) CORS(app) # Activation de CORS pour toutes les routes # Configuration de Redis redis_host = os.getenv("REDIS_HOST", "redis") # "redis" correspond au service Redis dans Docker redis_port = int(os.getenv("REDIS_PORT", 6379)) redis_client = redis.StrictRedis(host=redis_host, port=redis_port, db=0, decode_responses=True) # Clé pour le compteur de requêtes reçues REQUEST_RECEIVED_KEY = "request_received_count" # Initialisation du compteur si inexistant if not redis_client.exists(REQUEST_RECEIVED_KEY): redis_client.set(REQUEST_RECEIVED_KEY, 0) @app.before_request def count_requests(): """ Middleware exécuté avant chaque requête pour incrémenter le compteur global de requêtes reçues. """ redis_client.incr(REQUEST_RECEIVED_KEY) logger.info(f"📩 Nouvelle requête reçue ! Nombre total : {redis_client.get(REQUEST_RECEIVED_KEY)}") @app.route("/health", methods=["GET"]) def health(): """ Vérifie si l'application fonctionne correctement. """ logger.info("✅ Vérification du statut de l'application (health check)") return jsonify({"status": "ok"}), 200 @app.route("/bruteforce", methods=["POST"]) def bruteforce(): """ Endpoint pour bruteforcer un hash MD5. """ data = request.json if not data or "hash" not in data: logger.warning("⚠️ Requête invalide reçue sur /bruteforce") return jsonify({ "status": "fail", "data": None, "errors": {"message": "Invalid payload. Please provide a valid hash."} }), 400 target_hash = data["hash"] logger.info(f"🔍 Bruteforce demandé pour le hash : {target_hash}") # Vérifier si le hash existe déjà dans Redis if redis_client.exists(target_hash): original = redis_client.get(target_hash) logger.info(f"✅ Hash trouvé en cache : {original}") return jsonify({ "status": "success", "data": {"hash": target_hash, "original": original}, "errors": None }), 200 # Logique de brute-force charset = "abcdefghijklmnopqrstuvwxyz0123456789" for length in range(1, 8): for guess in itertools.product(charset, repeat=length): guess_str = ''.join(guess) if hashlib.md5(guess_str.encode()).hexdigest() == target_hash: redis_client.set(target_hash, guess_str) logger.info(f"✅ Hash {target_hash} trouvé : {guess_str}") return jsonify({ "status": "success", "data": {"hash": target_hash, "original": guess_str}, "errors": None }), 200 logger.warning(f"❌ Aucun résultat trouvé pour le hash : {target_hash}") return jsonify({ "status": "fail", "data": None, "errors": {"message": "No match found."} }), 404 @app.route("/resolved", methods=["GET"]) def get_resolved_hashes(): """ Endpoint pour récupérer tous les hash résolus. """ keys = redis_client.keys() resolved_hashes = {key: redis_client.get(key) for key in keys if key != REQUEST_RECEIVED_KEY} logger.info(f"📜 Liste des hash résolus récupérée ({len(resolved_hashes)} entrées)") return jsonify({ "status": "success", "data": resolved_hashes, "errors": None }), 200 @app.route("/resolved/", methods=["GET"]) def get_resolved_hash(hash_value): """ Endpoint pour récupérer un hash spécifique. """ if redis_client.exists(hash_value): original = redis_client.get(hash_value) logger.info(f"🔎 Recherche du hash {hash_value} : {original}") return jsonify({ "status": "success", "data": {"hash": hash_value, "original": original}, "errors": None }), 200 else: logger.warning(f"⚠️ Aucune entrée trouvée pour le hash : {hash_value}") return jsonify({ "status": "fail", "data": None, "errors": {"message": f"No resolved entry found for hash: {hash_value}"} }), 404 @app.route("/request_count", methods=["GET"]) def get_request_count(): """ Endpoint pour récupérer le nombre total de requêtes reçues. """ count = redis_client.get(REQUEST_RECEIVED_KEY) logger.info(f"📊 Nombre total de requêtes reçues : {count}") return jsonify({ "status": "success", "data": {"request_received_count": int(count) if count else 0}, "errors": None }), 200 @app.route("/clear_cache", methods=["DELETE"]) def clear_cache(): """ Endpoint pour effacer toutes les entrées stockées dans Redis (sauf le compteur de requêtes). """ keys = redis_client.keys() for key in keys: if key != REQUEST_RECEIVED_KEY: redis_client.delete(key) logger.info("🗑️ Cache nettoyé, toutes les entrées supprimées sauf le compteur de requêtes.") return jsonify({"status": "success", "message": "Cache cleared."}), 200 @app.route("/replicas", methods=["GET"]) def get_replicas(): """ Endpoint pour récupérer le nombre actuel de réplicas du backend dans Docker Swarm. """ SERVICE_NAME = "md5_stack_backend" try: result = subprocess.run(["docker", "service", "ls"], capture_output=True, text=True) for line in result.stdout.split("\n"): if SERVICE_NAME in line: replicas = line.split()[3].split("/")[0] # Extraction du nombre de réplicas actuels logger.info(f"🔢 Nombre de réplicas actuels : {replicas}") return jsonify({"status": "success", "data": {"replicas": int(replicas)}, "errors": None}), 200 except Exception as e: logger.error(f"❌ Erreur récupération réplicas : {e}") return jsonify({"status": "fail", "data": None, "errors": {"message": str(e)}}), 500 return jsonify({"status": "fail", "data": None, "errors": {"message": "Service not found"}}), 404 @app.route("/cpu_usage", methods=["GET"]) def get_cpu_usage(): """ Endpoint pour récupérer l'utilisation CPU actuelle du service backend dans Docker Swarm. """ SERVICE_NAME = "md5_stack_backend" try: result = subprocess.run(["docker", "stats", "--no-stream", "--format", "{{.Name}} {{.CPUPerc}}"], capture_output=True, text=True) for line in result.stdout.split("\n"): if SERVICE_NAME in line: cpu_usage = line.split()[1].replace("%", "") # Extraction de l'utilisation CPU logger.info(f"⚡ Utilisation CPU actuelle : {cpu_usage}%") return jsonify({"status": "success", "data": {"cpu_usage": float(cpu_usage)}, "errors": None}), 200 except Exception as e: logger.error(f"❌ Erreur récupération CPU : {e}") return jsonify({"status": "fail", "data": None, "errors": {"message": str(e)}}), 500 if __name__ == "__main__": app.run(host="0.0.0.0", port=5000)