Add cybersecurity/Network Reputation Service/script-nrs.py
This commit is contained in:
712
cybersecurity/Network Reputation Service/script-nrs.py
Normal file
712
cybersecurity/Network Reputation Service/script-nrs.py
Normal file
@@ -0,0 +1,712 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script d'Audit Firewall - Network Reputation Service
|
||||
Auteur: Converti depuis PowerShell
|
||||
Date: 04/09/2025
|
||||
Version: 1.3 (Python)
|
||||
"""
|
||||
|
||||
import json
|
||||
import requests
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlparse
|
||||
import time
|
||||
import getpass
|
||||
from typing import List, Dict, Any, Optional, Tuple
|
||||
import math
|
||||
|
||||
# Import des bibliothèques avec gestion des erreurs
|
||||
try:
|
||||
from colorama import init, Fore, Back, Style
|
||||
init(autoreset=True)
|
||||
COLORAMA_AVAILABLE = True
|
||||
except ImportError:
|
||||
COLORAMA_AVAILABLE = False
|
||||
print("Attention: colorama n'est pas installé. Les couleurs ne seront pas disponibles.")
|
||||
print("Installez avec: pip install colorama")
|
||||
|
||||
try:
|
||||
from tqdm import tqdm
|
||||
TQDM_AVAILABLE = True
|
||||
except ImportError:
|
||||
TQDM_AVAILABLE = False
|
||||
print("Attention: tqdm n'est pas installé. Les barres de progression ne seront pas disponibles.")
|
||||
print("Installez avec: pip install tqdm")
|
||||
|
||||
# Configuration globale
|
||||
TIMEOUT_DEFAULT = 10
|
||||
GRADE_COLORS = {
|
||||
'A+': '#28a745', 'A': '#52b83a', 'B+': '#7ac92e', 'B': '#a3da23',
|
||||
'C+': '#cceb17', 'C': '#f5f90c', 'D+': '#f7d808', 'D': '#f9b604',
|
||||
'E+': '#fb9500', 'E': '#fd7300', 'F+': '#ff5100', 'F': '#dc3545'
|
||||
}
|
||||
|
||||
BLOCK_KEYWORDS = [
|
||||
"site bloqué", "access denied", "filtrage web",
|
||||
"Access Denied", "Site Blocked", "blocked", "forbidden"
|
||||
]
|
||||
|
||||
BROWSER_HEADERS = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
|
||||
"Accept-Language": "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7"
|
||||
}
|
||||
|
||||
def write_color_output(text: str, color: str = "WHITE") -> None:
|
||||
"""Affiche du texte en couleur si colorama est disponible"""
|
||||
if not COLORAMA_AVAILABLE:
|
||||
print(text)
|
||||
return
|
||||
|
||||
color_map = {
|
||||
"RED": Fore.RED,
|
||||
"GREEN": Fore.GREEN,
|
||||
"YELLOW": Fore.YELLOW,
|
||||
"BLUE": Fore.BLUE,
|
||||
"CYAN": Fore.CYAN,
|
||||
"MAGENTA": Fore.MAGENTA,
|
||||
"WHITE": Fore.WHITE,
|
||||
"GRAY": Fore.LIGHTBLACK_EX
|
||||
}
|
||||
|
||||
color_code = color_map.get(color.upper(), Fore.WHITE)
|
||||
print(f"{color_code}{text}")
|
||||
|
||||
def prerequisites() -> bool:
|
||||
"""Vérifie les prérequis du script"""
|
||||
write_color_output("\n === Vérification des prérequis ===", "CYAN")
|
||||
|
||||
# Vérification du fichier JSON
|
||||
script_dir = Path(__file__).parent
|
||||
json_file = script_dir / "file-nrs.json"
|
||||
|
||||
if not json_file.exists():
|
||||
write_color_output("ERREUR: Le fichier 'file-nrs.json' n'existe pas!", "RED")
|
||||
write_color_output("Veuillez télécharger ou créer le fichier depuis:", "YELLOW")
|
||||
write_color_output("https://gitea.tips-of-mine.com/Tips-Of-Mine/Powershell/src/branch/main/cybersecurity/Network%20Reputation%20Service/file-nrs.json", "BLUE")
|
||||
write_color_output("Le fichier doit être placé dans le même dossier que ce script.", "YELLOW")
|
||||
return False
|
||||
|
||||
write_color_output("✓ Fichier 'file-nrs.json' trouvé", "GREEN")
|
||||
|
||||
# Vérification des modules Python requis
|
||||
required_modules = {
|
||||
'requests': 'requests',
|
||||
'colorama': 'colorama',
|
||||
'tqdm': 'tqdm'
|
||||
}
|
||||
|
||||
missing_modules = []
|
||||
for module_name, pip_name in required_modules.items():
|
||||
try:
|
||||
__import__(module_name)
|
||||
write_color_output(f"✓ Module {module_name} disponible", "GREEN")
|
||||
except ImportError:
|
||||
write_color_output(f"⚠ Module {module_name} manquant", "YELLOW")
|
||||
missing_modules.append(pip_name)
|
||||
|
||||
if missing_modules:
|
||||
write_color_output(f"Modules manquants (optionnels): {', '.join(missing_modules)}", "YELLOW")
|
||||
write_color_output(f"Installez avec: pip install {' '.join(missing_modules)}", "YELLOW")
|
||||
|
||||
return True
|
||||
|
||||
def calculate_category_score(results: List[Dict]) -> float:
|
||||
"""Calcule le score d'une catégorie"""
|
||||
if not results:
|
||||
return 0.0
|
||||
|
||||
correct_results = sum(1 for result in results if result['is_correct'])
|
||||
return round((correct_results / len(results)) * 100, 2)
|
||||
|
||||
def convert_score_to_grade(score: float) -> str:
|
||||
"""Convertit un score en note"""
|
||||
if score >= 95: return 'A+'
|
||||
elif score >= 90: return 'A'
|
||||
elif score >= 85: return 'B+'
|
||||
elif score >= 80: return 'B'
|
||||
elif score >= 75: return 'C+'
|
||||
elif score >= 70: return 'C'
|
||||
elif score >= 65: return 'D+'
|
||||
elif score >= 60: return 'D'
|
||||
elif score >= 55: return 'E+'
|
||||
elif score >= 50: return 'E'
|
||||
elif score >= 45: return 'F+'
|
||||
else: return 'F'
|
||||
|
||||
def get_url_status(url: str, expected_action: str, proxy_url: Optional[str] = None,
|
||||
proxy_auth: Optional[Tuple[str, str]] = None, timeout: int = TIMEOUT_DEFAULT) -> Dict:
|
||||
"""Teste une URL et détermine si elle est bloquée ou autorisée"""
|
||||
|
||||
result = {
|
||||
'url': url,
|
||||
'expected': expected_action,
|
||||
'actual_result': 'Indéterminé',
|
||||
'test_status': 'Échec',
|
||||
'score': None,
|
||||
'status_code': '',
|
||||
'details': '',
|
||||
'response_time': ''
|
||||
}
|
||||
|
||||
# Configuration des proxies
|
||||
proxies = {}
|
||||
if proxy_url:
|
||||
proxies = {
|
||||
'http': proxy_url,
|
||||
'https': proxy_url
|
||||
}
|
||||
|
||||
# Configuration de l'authentification proxy
|
||||
auth = None
|
||||
if proxy_auth:
|
||||
auth = proxy_auth
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
try:
|
||||
response = requests.get(
|
||||
url,
|
||||
headers=BROWSER_HEADERS,
|
||||
timeout=timeout,
|
||||
proxies=proxies,
|
||||
auth=auth,
|
||||
verify=True,
|
||||
allow_redirects=True
|
||||
)
|
||||
|
||||
response_time = round(time.time() - start_time, 2)
|
||||
result['response_time'] = str(response_time)
|
||||
result['status_code'] = str(response.status_code)
|
||||
|
||||
# Vérification des mots-clés de blocage dans le contenu
|
||||
keyword_found = any(keyword.lower() in response.text.lower() for keyword in BLOCK_KEYWORDS)
|
||||
|
||||
if keyword_found:
|
||||
result['actual_result'] = "Bloqué"
|
||||
result['details'] = "Page de blocage détectée."
|
||||
else:
|
||||
result['actual_result'] = "Autorisé"
|
||||
result['details'] = "Le site a été atteint sans blocage."
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
result['actual_result'] = "Bloqué (Timeout)"
|
||||
result['details'] = f"La requête a expiré après {timeout}s, indiquant un blocage probable."
|
||||
result['response_time'] = str(timeout)
|
||||
|
||||
except requests.exceptions.ConnectionError:
|
||||
result['actual_result'] = "Erreur de Connexion"
|
||||
result['details'] = "Impossible de joindre le serveur"
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
result['actual_result'] = "Erreur Script"
|
||||
result['details'] = f"Erreur inattendue: {str(e)}"
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
result['actual_result'] = "Erreur Script"
|
||||
result['details'] = f"Erreur inattendue: {str(e)}"
|
||||
return result
|
||||
|
||||
# Détermination si le test est conforme
|
||||
is_blocked = result['actual_result'] in ['Bloqué', 'Bloqué (Timeout)']
|
||||
should_be_blocked = expected_action == 'block'
|
||||
|
||||
if (is_blocked and should_be_blocked) or (not is_blocked and not should_be_blocked):
|
||||
result['test_status'] = "Conforme"
|
||||
result['score'] = 1
|
||||
result['details'] += " (Résultat conforme à l'attendu)"
|
||||
else:
|
||||
result['test_status'] = "Non Conforme"
|
||||
result['score'] = 0
|
||||
result['details'] += f" (NON CONFORME; Attendu: {expected_action}; Obtenu: {result['actual_result']})"
|
||||
|
||||
return result
|
||||
|
||||
def check_categories(categories: Dict, proxy_url: Optional[str] = None,
|
||||
proxy_auth: Optional[Tuple[str, str]] = None, timeout: int = TIMEOUT_DEFAULT) -> List[Dict]:
|
||||
"""Teste toutes les catégories et URLs"""
|
||||
|
||||
all_results = []
|
||||
categories_data = categories.get('categorie', [])
|
||||
|
||||
write_color_output(f"\n=== Début du test de {len(categories_data)} catégories ===", "CYAN")
|
||||
|
||||
# Barre de progression principale si tqdm est disponible
|
||||
category_progress = None
|
||||
if TQDM_AVAILABLE:
|
||||
category_progress = tqdm(categories_data, desc="Catégories", unit="cat")
|
||||
|
||||
for category_idx, category in enumerate(categories_data):
|
||||
if not TQDM_AVAILABLE:
|
||||
write_color_output(f"\n=== Test de la catégorie: {category['nom']} ({category_idx + 1}/{len(categories_data)}) ===", "CYAN")
|
||||
|
||||
category_results = []
|
||||
urls = category.get('urls', [])
|
||||
|
||||
# Barre de progression pour les URLs si tqdm est disponible
|
||||
url_progress = None
|
||||
if TQDM_AVAILABLE:
|
||||
url_progress = tqdm(urls, desc=f"URLs de '{category['nom']}'", unit="url", leave=False)
|
||||
|
||||
for url_idx, url_obj in enumerate(urls):
|
||||
if not TQDM_AVAILABLE:
|
||||
write_color_output(f"Test de: {url_obj['url']} ({url_idx + 1}/{len(urls)})", "YELLOW")
|
||||
|
||||
result = get_url_status(
|
||||
url_obj['url'],
|
||||
url_obj['expected_action'],
|
||||
proxy_url,
|
||||
proxy_auth,
|
||||
timeout
|
||||
)
|
||||
|
||||
test_result = {
|
||||
'category': category['nom'],
|
||||
'category_id': category.get('id', ''),
|
||||
'url': url_obj['url'],
|
||||
'reputation': url_obj.get('reputation', ''),
|
||||
'expected_action': url_obj['expected_action'],
|
||||
'status': result['actual_result'],
|
||||
'status_code': result['status_code'],
|
||||
'response_time': result['response_time'],
|
||||
'error': result['details'],
|
||||
'score': result['score'],
|
||||
'is_correct': result['test_status'] == "Conforme"
|
||||
}
|
||||
|
||||
if not TQDM_AVAILABLE:
|
||||
status_color = "GREEN" if test_result['is_correct'] else "RED"
|
||||
write_color_output(
|
||||
f" → Résultat: {test_result['status']} | Attendu: {test_result['expected_action']} | Correct: {test_result['is_correct']}",
|
||||
status_color
|
||||
)
|
||||
|
||||
category_results.append(test_result)
|
||||
all_results.append(test_result)
|
||||
|
||||
if url_progress:
|
||||
url_progress.update(1)
|
||||
|
||||
if url_progress:
|
||||
url_progress.close()
|
||||
|
||||
category_score = calculate_category_score(category_results)
|
||||
category_grade = convert_score_to_grade(category_score)
|
||||
|
||||
if not TQDM_AVAILABLE:
|
||||
write_color_output(f"Score de la catégorie '{category['nom']}': {category_score}% (Note: {category_grade})", "MAGENTA")
|
||||
|
||||
if category_progress:
|
||||
category_progress.set_postfix({
|
||||
'Score': f"{category_score}%",
|
||||
'Grade': category_grade
|
||||
})
|
||||
category_progress.update(1)
|
||||
|
||||
if category_progress:
|
||||
category_progress.close()
|
||||
|
||||
return all_results
|
||||
|
||||
def generate_html_report(results: List[Dict], output_path: Path) -> None:
|
||||
"""Génère le rapport HTML"""
|
||||
write_color_output("Génération du rapport HTML...", "YELLOW")
|
||||
|
||||
# Calcul des scores par catégorie
|
||||
categories_dict = {}
|
||||
for result in results:
|
||||
cat_name = result['category']
|
||||
if cat_name not in categories_dict:
|
||||
categories_dict[cat_name] = []
|
||||
categories_dict[cat_name].append(result)
|
||||
|
||||
category_scores = []
|
||||
for cat_name, cat_results in categories_dict.items():
|
||||
score = calculate_category_score(cat_results)
|
||||
grade = convert_score_to_grade(score)
|
||||
|
||||
category_scores.append({
|
||||
'category': cat_name,
|
||||
'score': score,
|
||||
'grade': grade,
|
||||
'color': GRADE_COLORS[grade],
|
||||
'total_urls': len(cat_results),
|
||||
'correct_results': sum(1 for r in cat_results if r['is_correct']),
|
||||
'results': cat_results
|
||||
})
|
||||
|
||||
# Score global
|
||||
global_score = calculate_category_score(results)
|
||||
global_grade = convert_score_to_grade(global_score)
|
||||
global_color = GRADE_COLORS[global_grade]
|
||||
|
||||
# Génération du HTML
|
||||
current_time = datetime.now().strftime('%d/%m/%Y à %H:%M')
|
||||
|
||||
html_content = f"""<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Audit Firewall - Network Reputation Service</title>
|
||||
<style>
|
||||
* {{ margin: 0; padding: 0; box-sizing: border-box; }}
|
||||
body {{ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f5f5f5; color: #333; line-height: 1.6; }}
|
||||
.container {{ max-width: 1200px; margin: 0 auto; padding: 20px; }}
|
||||
h1 {{ text-align: center; color: #2c3e50; margin-bottom: 10px; font-size: 2.5em; }}
|
||||
.subtitle {{ text-align: center; color: #666; margin-bottom: 30px; font-size: 1.1em; }}
|
||||
.section {{ background: white; margin: 20px 0; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }}
|
||||
.section h2 {{ color: #2c3e50; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 2px solid #3498db; }}
|
||||
|
||||
/* Score global */
|
||||
.global-score {{ display: flex; align-items: center; justify-content: center; margin: 30px 0; }}
|
||||
.score-box {{ background-color: {global_color}; color: white; width: 150px; height: 150px; border-radius: 15px; display: flex; flex-direction: column; align-items: center; justify-content: center; box-shadow: 0 4px 15px rgba(0,0,0,0.2); margin-right: 40px; }}
|
||||
.score-grade {{ font-size: 3em; font-weight: bold; }}
|
||||
.score-percent {{ font-size: 1.5em; margin-top: 5px; }}
|
||||
.score-label {{ font-size: 1em; margin-top: 5px; opacity: 0.9; }}
|
||||
.stats {{ text-align: left; }}
|
||||
.stats div {{ margin: 8px 0; font-size: 1.2em; }}
|
||||
|
||||
/* Tableau des scores */
|
||||
table {{ width: 100%; border-collapse: collapse; margin: 20px 0; }}
|
||||
th, td {{ padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }}
|
||||
th {{ background-color: #3498db; color: white; font-weight: bold; }}
|
||||
tr:nth-child(even) {{ background-color: #f9f9f9; }}
|
||||
tr:hover {{ background-color: #e8f4fd; }}
|
||||
.grade-cell {{ font-weight: bold; color: white; text-align: center; border-radius: 5px; }}
|
||||
|
||||
/* Catégories en grille */
|
||||
.categories-grid {{ display: flex; flex-wrap: wrap; gap: 20px; margin: 20px 0; }}
|
||||
.category-item {{ flex: 1; min-width: 280px; max-width: calc(25% - 15px); background: white; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); overflow: hidden; }}
|
||||
.category-header {{ padding: 15px; cursor: pointer; transition: background-color 0.3s; }}
|
||||
.category-header:hover {{ background-color: #f8f9fa; }}
|
||||
.category-title {{ font-size: 1.2em; font-weight: bold; margin-bottom: 8px; color: #2c3e50; }}
|
||||
.category-score {{ display: inline-block; padding: 5px 15px; border-radius: 20px; color: white; font-weight: bold; font-size: 0.9em; }}
|
||||
.category-content {{ display: none; padding: 0 15px 15px; }}
|
||||
.category-content.active {{ display: block; animation: slideDown 0.3s ease; }}
|
||||
|
||||
/* Animations */
|
||||
@keyframes slideDown {{ from {{ opacity: 0; transform: translateY(-10px); }} to {{ opacity: 1; transform: translateY(0); }} }}
|
||||
|
||||
/* Tables détaillées */
|
||||
.detail-table {{ font-size: 0.9em; }}
|
||||
.detail-table th {{ font-size: 0.8em; }}
|
||||
.correct {{ background-color: #d4edda !important; color: #155724; }}
|
||||
.incorrect {{ background-color: #f8d7da !important; color: #721c24; }}
|
||||
|
||||
/* Barème */
|
||||
.grading-scale {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 10px; }}
|
||||
.grade-item {{ display: flex; align-items: center; padding: 10px; border-radius: 8px; background-color: #f8f9fa; }}
|
||||
.grade-badge {{ width: 40px; height: 40px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-weight: bold; color: white; margin-right: 15px; }}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 768px) {{
|
||||
.global-score {{ flex-direction: column; }}
|
||||
.score-box {{ margin-right: 0; margin-bottom: 20px; }}
|
||||
.category-item {{ max-width: 100%; }}
|
||||
}}
|
||||
|
||||
/* Bouton toggle */
|
||||
.toggle-btn {{ float: right; font-size: 1.2em; transition: transform 0.3s; }}
|
||||
.toggle-btn.active {{ transform: rotate(180deg); }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🛡️ Audit Firewall - Network Reputation Service</h1>
|
||||
<p class="subtitle">Rapport généré le {current_time}</p>
|
||||
|
||||
<!-- Résumé Exécutif -->
|
||||
<div class="section">
|
||||
<h2>📊 Résumé Exécutif</h2>
|
||||
<div class="global-score">
|
||||
<div class="score-box">
|
||||
<div class="score-grade">{global_grade}</div>
|
||||
<div class="score-percent">{global_score}%</div>
|
||||
<div class="score-label">Score Global</div>
|
||||
</div>
|
||||
<div class="stats">
|
||||
<div><strong>📋 Total des URLs testées :</strong> {len(results)}</div>
|
||||
<div><strong>✅ URLs correctement filtrées :</strong> {sum(1 for r in results if r['is_correct'])}</div>
|
||||
<div><strong>🎯 Taux de réussite :</strong> {round((sum(1 for r in results if r['is_correct']) / len(results)) * 100, 2)}%</div>
|
||||
<div><strong>📅 Date du test :</strong> {datetime.now().strftime('%d/%m/%Y %H:%M')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scores par Catégorie -->
|
||||
<div class="section">
|
||||
<h2>📈 Scores par Catégorie</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Catégorie</th>
|
||||
<th>Score (%)</th>
|
||||
<th>Note</th>
|
||||
<th>URLs Totales</th>
|
||||
<th>Résultats Corrects</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>"""
|
||||
|
||||
# Ajout des lignes du tableau
|
||||
for cat_score in category_scores:
|
||||
html_content += f"""
|
||||
<tr>
|
||||
<td><strong>{cat_score['category']}</strong></td>
|
||||
<td>{cat_score['score']}%</td>
|
||||
<td><span class="grade-cell" style="background-color: {cat_score['color']}; padding: 5px 10px; border-radius: 5px;">{cat_score['grade']}</span></td>
|
||||
<td>{cat_score['total_urls']}</td>
|
||||
<td>{cat_score['correct_results']}</td>
|
||||
</tr>"""
|
||||
|
||||
html_content += """
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Détail des Tests par Catégorie -->
|
||||
<div class="section">
|
||||
<h2>🔍 Détail des Tests par Catégorie</h2>
|
||||
<div class="categories-grid">"""
|
||||
|
||||
# Ajout des catégories
|
||||
for idx, cat_score in enumerate(category_scores, 1):
|
||||
html_content += f"""
|
||||
<div class="category-item">
|
||||
<div class="category-header" onclick="toggleCategory('cat-{idx}')">
|
||||
<div class="category-title">{cat_score['category']} <span class="toggle-btn" id="btn-cat-{idx}">▼</span></div>
|
||||
<span class="category-score" style="background-color: {cat_score['color']};">{cat_score['grade']} - {cat_score['score']}%</span>
|
||||
</div>
|
||||
<div class="category-content" id="cat-{idx}">
|
||||
<table class="detail-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>URL</th>
|
||||
<th>Réputation</th>
|
||||
<th>Action Attendue</th>
|
||||
<th>Statut</th>
|
||||
<th>Correct</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>"""
|
||||
|
||||
# Ajout des résultats de chaque URL
|
||||
for result in cat_score['results']:
|
||||
row_class = "correct" if result['is_correct'] else "incorrect"
|
||||
correct_text = "✅ Oui" if result['is_correct'] else "❌ Non"
|
||||
url_display = result['url'][:30] + ("..." if len(result['url']) > 30 else "")
|
||||
|
||||
html_content += f"""
|
||||
<tr class="{row_class}">
|
||||
<td title="{result['url']}">{url_display}</td>
|
||||
<td>{result['reputation']}</td>
|
||||
<td>{result['expected_action']}</td>
|
||||
<td>{result['status']}</td>
|
||||
<td>{correct_text}</td>
|
||||
</tr>"""
|
||||
|
||||
html_content += """
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>"""
|
||||
|
||||
html_content += """
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Barème de Notation -->
|
||||
<div class="section">
|
||||
<h2>📏 Barème de Notation</h2>
|
||||
<div class="grading-scale">"""
|
||||
|
||||
# Ajout du barème de notation
|
||||
grading_scale = [
|
||||
{'grade': 'A+', 'score': '95-100%', 'interpretation': 'Excellent / Parfait', 'color': '#28a745'},
|
||||
{'grade': 'A', 'score': '90-95%', 'interpretation': 'Très bon niveau de filtrage', 'color': '#52b83a'},
|
||||
{'grade': 'B+', 'score': '85-90%', 'interpretation': 'Très bon', 'color': '#7ac92e'},
|
||||
{'grade': 'B', 'score': '80-85%', 'interpretation': 'Bon, quelques ajustements nécessaires', 'color': '#a3da23'},
|
||||
{'grade': 'C+', 'score': '75-80%', 'interpretation': 'Assez bon', 'color': '#cceb17'},
|
||||
{'grade': 'C', 'score': '70-75%', 'interpretation': 'Moyen, lacunes importantes', 'color': '#f5f90c'},
|
||||
{'grade': 'D+', 'score': '65-70%', 'interpretation': 'Passable', 'color': '#f7d808'},
|
||||
{'grade': 'D', 'score': '60-65%', 'interpretation': 'Faible, filtrage inefficace', 'color': '#f9b604'},
|
||||
{'grade': 'E+', 'score': '55-60%', 'interpretation': 'Très faible', 'color': '#fb9500'},
|
||||
{'grade': 'E', 'score': '50-55%', 'interpretation': 'Insuffisant', 'color': '#fd7300'},
|
||||
{'grade': 'F+', 'score': '45-50%', 'interpretation': 'Critique', 'color': '#ff5100'},
|
||||
{'grade': 'F', 'score': '0-45%', 'interpretation': 'Très faible, action immédiate requise', 'color': '#dc3545'}
|
||||
]
|
||||
|
||||
for grade_info in grading_scale:
|
||||
html_content += f"""
|
||||
<div class="grade-item">
|
||||
<div class="grade-badge" style="background-color: {grade_info['color']};">{grade_info['grade']}</div>
|
||||
<div>
|
||||
<strong>{grade_info['score']}</strong><br>
|
||||
<span style="color: #666;">{grade_info['interpretation']}</span>
|
||||
</div>
|
||||
</div>"""
|
||||
|
||||
html_content += """
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleCategory(categoryId) {
|
||||
const content = document.getElementById(categoryId);
|
||||
const btn = document.getElementById('btn-' + categoryId);
|
||||
|
||||
if (content.classList.contains('active')) {
|
||||
content.classList.remove('active');
|
||||
btn.classList.remove('active');
|
||||
content.style.display = 'none';
|
||||
} else {
|
||||
content.classList.add('active');
|
||||
btn.classList.add('active');
|
||||
content.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
// Animation au chargement
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const items = document.querySelectorAll('.category-item');
|
||||
items.forEach((item, index) => {
|
||||
setTimeout(() => {
|
||||
item.style.opacity = '1';
|
||||
item.style.transform = 'translateY(0)';
|
||||
}, index * 100);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
# Écriture du fichier HTML
|
||||
try:
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
f.write(html_content)
|
||||
write_color_output(f"✓ Rapport généré: {output_path}", "GREEN")
|
||||
except Exception as e:
|
||||
write_color_output(f"ERREUR: Impossible de générer le rapport: {str(e)}", "RED")
|
||||
|
||||
def main():
|
||||
"""Fonction principale"""
|
||||
parser = argparse.ArgumentParser(description="Script d'Audit Firewall - Network Reputation Service")
|
||||
parser.add_argument("--proxy-url", help="URL du proxy à utiliser (ex: 'http://proxy.domaine.com:8080')")
|
||||
parser.add_argument("--proxy-auth", action="store_true", help="Utiliser l'authentification pour le proxy")
|
||||
parser.add_argument("--timeout", type=int, default=TIMEOUT_DEFAULT, help="Délai d'attente en secondes pour chaque requête")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
write_color_output("""
|
||||
╔══════════════════════════════════════════════════════════════════════════════╗
|
||||
║ AUDIT FIREWALL - NETWORK REPUTATION SERVICE ║
|
||||
║ Version 1.3 (Python) ║
|
||||
╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
""", "CYAN")
|
||||
|
||||
# Vérification des prérequis
|
||||
if not prerequisites():
|
||||
write_color_output("ERREUR: Les prérequis ne sont pas satisfaits. Arrêt du script.", "RED")
|
||||
sys.exit(1)
|
||||
|
||||
# Chargement du fichier JSON
|
||||
try:
|
||||
script_dir = Path(__file__).parent
|
||||
json_file = script_dir / "file-nrs.json"
|
||||
|
||||
with open(json_file, 'r', encoding='utf-8') as f:
|
||||
categories = json.load(f)
|
||||
|
||||
write_color_output(f"✓ Fichier JSON chargé avec {len(categories.get('categorie', []))} catégories", "GREEN")
|
||||
except Exception as e:
|
||||
write_color_output(f"ERREUR: Impossible de charger le fichier JSON: {str(e)}", "RED")
|
||||
sys.exit(1)
|
||||
|
||||
# Configuration de l'authentification proxy si nécessaire
|
||||
proxy_auth = None
|
||||
if args.proxy_auth and args.proxy_url:
|
||||
write_color_output(f"Configuration de l'authentification pour le proxy {args.proxy_url}", "YELLOW")
|
||||
username = input("Nom d'utilisateur: ")
|
||||
password = getpass.getpass("Mot de passe: ")
|
||||
proxy_auth = (username, password)
|
||||
|
||||
# Création du dossier de sortie
|
||||
current_time = datetime.now()
|
||||
report_date = current_time.strftime("%A %d %B %Y-%H %M")
|
||||
script_dir = Path(__file__).parent
|
||||
reports_dir = script_dir / "Rapports"
|
||||
output_dir = reports_dir / report_date
|
||||
|
||||
reports_dir.mkdir(exist_ok=True)
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
|
||||
write_color_output(f"\nDossier de sortie: {output_dir}", "YELLOW")
|
||||
|
||||
# Début des tests
|
||||
write_color_output("\n=== DÉBUT DES TESTS ===", "GREEN")
|
||||
start_time = time.time()
|
||||
|
||||
all_results = check_categories(
|
||||
categories,
|
||||
args.proxy_url,
|
||||
proxy_auth,
|
||||
args.timeout
|
||||
)
|
||||
|
||||
end_time = time.time()
|
||||
duration = end_time - start_time
|
||||
duration_str = f"{int(duration // 3600):02d}:{int((duration % 3600) // 60):02d}:{int(duration % 60):02d}"
|
||||
|
||||
write_color_output("\n=== RÉSULTATS FINAUX ===", "GREEN")
|
||||
write_color_output(f"\nTemps total d'exécution: {duration_str}", "YELLOW")
|
||||
write_color_output(f"Total des URLs testées: {len(all_results)}", "YELLOW")
|
||||
|
||||
# Calcul du score global
|
||||
global_score = calculate_category_score(all_results)
|
||||
global_grade = convert_score_to_grade(global_score)
|
||||
|
||||
write_color_output(f"\n\nScore global: {global_score}% - Note: {global_grade}", "MAGENTA")
|
||||
|
||||
# Génération du rapport HTML
|
||||
report_path = output_dir / "Audit_Firewall_Report.html"
|
||||
generate_html_report(all_results, report_path)
|
||||
|
||||
# Sauvegarde des résultats en JSON
|
||||
json_results_path = output_dir / "Results.json"
|
||||
try:
|
||||
with open(json_results_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(all_results, f, indent=2, ensure_ascii=False)
|
||||
write_color_output(f"✓ Résultats sauvegardés: {json_results_path}", "GREEN")
|
||||
except Exception as e:
|
||||
write_color_output(f"ERREUR: Impossible de sauvegarder les résultats: {str(e)}", "RED")
|
||||
|
||||
write_color_output("\n=== AUDIT TERMINÉ ===", "GREEN")
|
||||
write_color_output(f"\nRapport disponible à: {report_path}", "CYAN")
|
||||
|
||||
# Ouverture automatique du rapport
|
||||
try:
|
||||
open_report = input("\nVoulez-vous ouvrir le rapport maintenant? (O/N): ").strip().lower()
|
||||
if open_report in ['o', 'oui', 'y', 'yes']:
|
||||
import webbrowser
|
||||
webbrowser.open(f"file://{report_path.absolute()}")
|
||||
except KeyboardInterrupt:
|
||||
print("\nAu revoir!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
write_color_output("\n\nScript interrompu par l'utilisateur.", "YELLOW")
|
||||
sys.exit(0)
|
||||
except Exception as e:
|
||||
write_color_output(f"ERREUR FATALE: {str(e)}", "RED")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
Reference in New Issue
Block a user