Actualiser 7lna.py

This commit is contained in:
2026-03-02 08:24:46 +00:00
parent b3c8cbc837
commit 0aef5fb334

241
7lna.py
View File

@@ -3,43 +3,51 @@ from tkinter import filedialog, messagebox
import os import os
import threading import threading
import subprocess import subprocess
import urllib.request
import time
from watchdog.observers import Observer from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler from watchdog.events import FileSystemEventHandler
import time
# --- Configuration du Design --- # ==========================================
# CONFIGURATION GLOBALE
# ==========================================
# Lien RAW officiel de ton dépôt Gitea
UPDATE_URL = "https://git.7ka1.com/7ka1/7LnA_Antivirus_Linux_Free_ClamAV_Based/raw/branch/main/7lna.py"
QUARANTINE_DIR = os.path.expanduser("~/.7lna_quarantine")
WATCH_FOLDER = os.path.expanduser("~/Téléchargements")
# Design global
ctk.set_appearance_mode("dark") ctk.set_appearance_mode("dark")
ctk.set_default_color_theme("blue") ctk.set_default_color_theme("blue")
# ==========================================
# GESTIONNAIRE DU BOUCLIER TEMPS RÉEL
# ==========================================
class RealTimeShieldHandler(FileSystemEventHandler): class RealTimeShieldHandler(FileSystemEventHandler):
"""Gère les événements système : quand un fichier est créé."""
def __init__(self, app_instance): def __init__(self, app_instance):
self.app = app_instance self.app = app_instance
def on_created(self, event): def on_created(self, event):
# On ignore les dossiers, on ne scanne que les fichiers
if not event.is_directory: if not event.is_directory:
# Petit délai pour laisser le temps au téléchargement de se terminer time.sleep(1.5) # Laisse le temps au téléchargement de se terminer
time.sleep(1)
self.app.trigger_realtime_scan(event.src_path) self.app.trigger_realtime_scan(event.src_path)
# ==========================================
# APPLICATION PRINCIPALE
# ==========================================
class Antivirus7LnA(ctk.CTk): class Antivirus7LnA(ctk.CTk):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.title("7LnA Security Suite - Real-Time Edition") self.title("7LnA Security Suite")
self.geometry("1000x650") self.geometry("1050x650")
self.minsize(800, 500) self.minsize(850, 550)
# --- Configuration Système --- # Création du dossier de quarantaine
self.quarantine_dir = os.path.expanduser("~/.7lna_quarantine") os.makedirs(QUARANTINE_DIR, exist_ok=True)
os.makedirs(self.quarantine_dir, exist_ok=True)
# Variables du Bouclier Temps Réel
self.shield_observer = None self.shield_observer = None
self.shield_active = False self.shield_active = False
self.watch_folder = os.path.expanduser("~/Téléchargements") # Par défaut sur Ubuntu FR
if not os.path.exists(self.watch_folder):
self.watch_folder = os.path.expanduser("~/Downloads") # Fallback en anglais
self.check_dependencies() self.check_dependencies()
self.setup_ui() self.setup_ui()
@@ -50,32 +58,28 @@ class Antivirus7LnA(ctk.CTk):
self.clamav_installed = True self.clamav_installed = True
except (subprocess.CalledProcessError, FileNotFoundError): except (subprocess.CalledProcessError, FileNotFoundError):
self.clamav_installed = False self.clamav_installed = False
messagebox.showwarning("Alerte Moteur", "ClamAV n'est pas détecté. Installez-le avec : sudo apt install clamav")
# ==========================================
# ARCHITECTURE DE L'INTERFACE
# ==========================================
def setup_ui(self): def setup_ui(self):
self.grid_rowconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=1) self.grid_columnconfigure(1, weight=1)
# --- Menu Latéral --- # --- BARRE LATÉRALE ---
self.sidebar = ctk.CTkFrame(self, width=220, corner_radius=0) self.sidebar = ctk.CTkFrame(self, width=220, corner_radius=0)
self.sidebar.grid(row=0, column=0, sticky="nsew") self.sidebar.grid(row=0, column=0, sticky="nsew")
self.sidebar.grid_rowconfigure(6, weight=1) self.sidebar.grid_rowconfigure(6, weight=1)
self.logo = ctk.CTkLabel(self.sidebar, text="🛡️ 7LnA", font=ctk.CTkFont(size=28, weight="bold")) ctk.CTkLabel(self.sidebar, text="🛡️ 7LnA", font=ctk.CTkFont(size=28, weight="bold")).grid(row=0, column=0, padx=20, pady=30)
self.logo.grid(row=0, column=0, padx=20, pady=(30, 30))
self.btn_dashboard = self.create_nav_button("📊 Tableau de Bord", 1, "dashboard") self.btn_dash = self.create_nav_button("📊 Tableau de Bord", 1, "dashboard")
self.btn_scanner = self.create_nav_button("🔍 Scanner Manuel", 2, "scanner") self.btn_scan = self.create_nav_button("🔍 Scanner Manuel", 2, "scanner")
self.btn_realtime = self.create_nav_button("⚡ Bouclier Temps Réel", 3, "realtime") self.btn_shield = self.create_nav_button("⚡ Bouclier Actif", 3, "shield")
self.btn_audit = self.create_nav_button("⚙️ Audit Système", 4, "audit") self.btn_audit = self.create_nav_button("⚙️ Audit Système", 4, "audit")
self.btn_update = self.create_nav_button("🔄 Mise à jour Base", 5, "update") self.btn_update = self.create_nav_button("🔄 Mise à jour", 5, "update")
self.version_label = ctk.CTkLabel(self.sidebar, text="Version 5.0 - Active Shield", text_color="gray") self.version_label = ctk.CTkLabel(self.sidebar, text="Version 5.0 - Ultimate", text_color="gray")
self.version_label.grid(row=6, column=0, pady=20, sticky="s") self.version_label.grid(row=6, column=0, pady=20, sticky="s")
# --- CONTENEUR DES VUES ---
self.views = {} self.views = {}
self.init_dashboard_view() self.init_dashboard_view()
self.init_scanner_view() self.init_scanner_view()
@@ -98,9 +102,7 @@ class Antivirus7LnA(ctk.CTk):
if view_name in self.views: if view_name in self.views:
self.views[view_name].grid(row=0, column=1, sticky="nsew", padx=20, pady=20) self.views[view_name].grid(row=0, column=1, sticky="nsew", padx=20, pady=20)
# ========================================== # --- VUE : TABLEAU DE BORD ---
# MODULE : TABLEAU DE BORD
# ==========================================
def init_dashboard_view(self): def init_dashboard_view(self):
frame = ctk.CTkFrame(self, fg_color="transparent") frame = ctk.CTkFrame(self, fg_color="transparent")
self.views["dashboard"] = frame self.views["dashboard"] = frame
@@ -110,12 +112,12 @@ class Antivirus7LnA(ctk.CTk):
status_card = ctk.CTkFrame(frame, fg_color="#1E8449" if self.clamav_installed else "#C0392B", corner_radius=15) status_card = ctk.CTkFrame(frame, fg_color="#1E8449" if self.clamav_installed else "#C0392B", corner_radius=15)
status_card.pack(fill="x", pady=10, ipady=20) status_card.pack(fill="x", pady=10, ipady=20)
status_text = "Moteur ClamAV Connecté" if self.clamav_installed else "Moteur Hors Ligne" status_text = "Moteur ClamAV Opérationnel" if self.clamav_installed else "Moteur ClamAV Introuvable"
ctk.CTkLabel(status_card, text=f"{'' if self.clamav_installed else ''} {status_text}", font=ctk.CTkFont(size=18, weight="bold"), text_color="white").pack(expand=True) ctk.CTkLabel(status_card, text=f"{'' if self.clamav_installed else ''} {status_text}", font=ctk.CTkFont(size=18, weight="bold"), text_color="white").pack(expand=True)
# ========================================== ctk.CTkLabel(frame, text=f"📂 Dossier de quarantaine : {QUARANTINE_DIR}").pack(anchor="w", pady=10)
# MODULE : SCANNER MANUEL
# ========================================== # --- VUE : SCANNER MANUEL ---
def init_scanner_view(self): def init_scanner_view(self):
frame = ctk.CTkFrame(self, fg_color="transparent") frame = ctk.CTkFrame(self, fg_color="transparent")
frame.grid_rowconfigure(2, weight=1) frame.grid_rowconfigure(2, weight=1)
@@ -124,26 +126,70 @@ class Antivirus7LnA(ctk.CTk):
ctk.CTkLabel(frame, text="Analyse Antivirus Manuelle", font=ctk.CTkFont(size=24, weight="bold")).grid(row=0, column=0, columnspan=2, sticky="w", pady=(0, 20)) ctk.CTkLabel(frame, text="Analyse Antivirus Manuelle", font=ctk.CTkFont(size=24, weight="bold")).grid(row=0, column=0, columnspan=2, sticky="w", pady=(0, 20))
self.btn_scan_f = ctk.CTkButton(frame, text="📄 Analyser un Fichier", command=lambda: self.start_scan(is_dir=False), height=40) self.btn_scan_f = ctk.CTkButton(frame, text="📄 Analyser un Fichier", command=lambda: self.start_manual_scan(is_dir=False), height=40)
self.btn_scan_f.grid(row=1, column=0, padx=(0, 10), sticky="ew") self.btn_scan_f.grid(row=1, column=0, padx=(0, 10), sticky="ew")
self.btn_scan_d = ctk.CTkButton(frame, text="📁 Analyser un Dossier", command=lambda: self.start_scan(is_dir=True), height=40, fg_color="#2E86C1") self.btn_scan_d = ctk.CTkButton(frame, text="📁 Analyser un Dossier", command=lambda: self.start_manual_scan(is_dir=True), height=40, fg_color="#2E86C1")
self.btn_scan_d.grid(row=1, column=1, padx=(10, 0), sticky="ew") self.btn_scan_d.grid(row=1, column=1, padx=(10, 0), sticky="ew")
self.scan_console = ctk.CTkTextbox(frame, font=ctk.CTkFont(family="Consolas", size=13)) self.scan_console = ctk.CTkTextbox(frame, font=ctk.CTkFont(family="Consolas", size=13))
self.scan_console.grid(row=2, column=0, columnspan=2, pady=20, sticky="nsew") self.scan_console.grid(row=2, column=0, columnspan=2, pady=20, sticky="nsew")
self.scan_console.insert("end", "[*] Prêt pour une analyse manuelle.\n") self.scan_console.insert("end", "[*] Prêt. Les menaces seront automatiquement isolées.\n")
def start_scan(self, is_dir): def start_manual_scan(self, is_dir):
path = filedialog.askdirectory() if is_dir else filedialog.askopenfilename() path = filedialog.askdirectory() if is_dir else filedialog.askopenfilename()
if path: if path:
threading.Thread(target=self.run_clamav_engine, args=(path, is_dir, self.scan_console), daemon=True).start() threading.Thread(target=self.run_clamav_scan, args=(path, is_dir, self.scan_console), daemon=True).start()
def run_clamav_engine(self, path, is_dir, console): # --- VUE : BOUCLIER TEMPS RÉEL ---
console.insert("end", f"\n🚀 Lancement de l'analyse sur : {path}\n") def init_realtime_view(self):
frame = ctk.CTkFrame(self, fg_color="transparent")
frame.grid_rowconfigure(2, weight=1)
frame.grid_columnconfigure(0, weight=1)
self.views["shield"] = frame
header = ctk.CTkFrame(frame, fg_color="transparent")
header.grid(row=0, column=0, sticky="ew", pady=(0, 20))
ctk.CTkLabel(header, text="⚡ Bouclier Actif", font=ctk.CTkFont(size=24, weight="bold")).pack(side="left")
self.btn_toggle_shield = ctk.CTkButton(header, text="Activer le Bouclier", fg_color="#27AE60", hover_color="#1E8449", command=self.toggle_shield)
self.btn_toggle_shield.pack(side="right")
ctk.CTkLabel(frame, text=f"Surveillance en direct de : {WATCH_FOLDER}\nLes nouveaux fichiers seront scannés instantanément.", justify="left").grid(row=1, column=0, sticky="w", pady=(0, 10))
self.rt_console = ctk.CTkTextbox(frame, font=ctk.CTkFont(family="Consolas", size=13))
self.rt_console.grid(row=2, column=0, sticky="nsew")
self.rt_console.insert("end", "[-] Bouclier désactivé. Cliquez sur le bouton pour démarrer.\n")
def toggle_shield(self):
if not self.shield_active:
self.shield_observer = Observer()
self.shield_observer.schedule(RealTimeShieldHandler(self), WATCH_FOLDER, recursive=False)
self.shield_observer.start()
self.shield_active = True
self.btn_toggle_shield.configure(text="Désactiver le Bouclier", fg_color="#C0392B", hover_color="#922B21")
self.rt_console.insert("end", f"\n[+] BOUCLIER ACTIVÉ sur {WATCH_FOLDER}\n[*] Analyse automatique prête...\n")
else:
self.shield_observer.stop()
self.shield_active = False
self.btn_toggle_shield.configure(text="Activer le Bouclier", fg_color="#27AE60", hover_color="#1E8449")
self.rt_console.insert("end", "\n[-] Bouclier DÉSACTIVÉ.\n")
self.rt_console.see("end")
def trigger_realtime_scan(self, filepath):
self.rt_console.insert("end", f"\n⚡ Détection auto : {os.path.basename(filepath)}\n")
threading.Thread(target=self.run_clamav_scan, args=(filepath, False, self.rt_console), daemon=True).start()
# --- MOTEUR CLAMAV (Commun au Manuel et au Temps Réel) ---
def run_clamav_scan(self, path, is_dir, console):
if not self.clamav_installed:
console.insert("end", "❌ Erreur : ClamAV n'est pas installé.\n")
return
console.insert("end", f"[*] Début de l'analyse : {path}\n")
console.see("end") console.see("end")
try: try:
cmd = ['clamscan', '-i', '--no-summary', f'--move={self.quarantine_dir}'] cmd = ['clamscan', '-i', '--no-summary', f'--move={QUARANTINE_DIR}']
if is_dir: cmd.append('-r') if is_dir: cmd.append('-r')
cmd.append(path) cmd.append(path)
@@ -152,7 +198,7 @@ class Antivirus7LnA(ctk.CTk):
for line in process.stdout: for line in process.stdout:
clean_line = line.strip() clean_line = line.strip()
if "FOUND" in clean_line: if "FOUND" in clean_line:
console.insert("end", f"☠️ DANGER : {clean_line}\n🛡️ Fichier isolé en quarantaine.\n") console.insert("end", f"☠️ DANGER : {clean_line}\n🛡️ Isolé en quarantaine.\n")
infected += 1 infected += 1
else: else:
console.insert("end", clean_line + "\n") console.insert("end", clean_line + "\n")
@@ -160,80 +206,77 @@ class Antivirus7LnA(ctk.CTk):
process.wait() process.wait()
if infected == 0: if infected == 0:
console.insert("end", " Analyse terminée. Système propre.\n") console.insert("end", "[+] Analyse terminée. Fichier(s) propre(s).\n")
else: else:
console.insert("end", f"🚨 {infected} menace(s) neutralisée(s) !\n") console.insert("end", f"🚨 {infected} menace(s) neutralisée(s) !\n")
except Exception as e: except Exception as e:
console.insert("end", f"❌ Erreur : {e}\n") console.insert("end", f"❌ Erreur système : {e}\n")
console.see("end") console.see("end")
# ========================================== # --- VUE : AUDIT SYSTÈME ---
# MODULE : BOUCLIER TEMPS RÉEL (NOUVEAU) def init_audit_view(self):
# ==========================================
def init_realtime_view(self):
frame = ctk.CTkFrame(self, fg_color="transparent") frame = ctk.CTkFrame(self, fg_color="transparent")
frame.grid_rowconfigure(2, weight=1) frame.grid_rowconfigure(1, weight=1)
frame.grid_columnconfigure(0, weight=1) frame.grid_columnconfigure(0, weight=1)
self.views["realtime"] = frame self.views["audit"] = frame
header = ctk.CTkFrame(frame, fg_color="transparent") header = ctk.CTkFrame(frame, fg_color="transparent")
header.grid(row=0, column=0, sticky="ew", pady=(0, 20)) header.grid(row=0, column=0, sticky="ew", pady=(0, 20))
ctk.CTkLabel(header, text="⚡ Bouclier Actif (Temps Réel)", font=ctk.CTkFont(size=24, weight="bold")).pack(side="left") ctk.CTkLabel(header, text="Vérification des Vulnérabilités", font=ctk.CTkFont(size=24, weight="bold")).pack(side="left")
ctk.CTkButton(header, text="Lancer l'Audit", command=self.run_audit_thread).pack(side="right")
self.btn_toggle_shield = ctk.CTkButton(header, text="Activer le Bouclier", fg_color="#27AE60", hover_color="#1E8449", command=self.toggle_shield) self.audit_console = ctk.CTkTextbox(frame, font=ctk.CTkFont(family="Consolas", size=13))
self.btn_toggle_shield.pack(side="right") self.audit_console.grid(row=1, column=0, sticky="nsew")
info_text = f"Dossier surveillé en permanence : {self.watch_folder}\nTout nouveau fichier sera scanné et neutralisé automatiquement." def run_audit_thread(self):
ctk.CTkLabel(frame, text=info_text, justify="left").grid(row=1, column=0, sticky="w", pady=(0, 10)) self.audit_console.delete("0.0", "end")
threading.Thread(target=self.perform_audit, daemon=True).start()
self.rt_console = ctk.CTkTextbox(frame, font=ctk.CTkFont(family="Consolas", size=13)) def perform_audit(self):
self.rt_console.grid(row=2, column=0, sticky="nsew") self.audit_console.insert("end", "[*] Ports réseaux ouverts (Recherche de Backdoors)...\n")
self.rt_console.insert("end", "[-] Bouclier désactivé. Cliquez sur le bouton pour l'activer.\n") try:
self.audit_console.insert("end", subprocess.check_output(['ss', '-tuln'], text=True))
except Exception:
self.audit_console.insert("end", "[-] Impossible de lire le réseau.\n")
def toggle_shield(self): self.audit_console.insert("end", "\n[*] Top 10 des processus gourmands...\n")
if not self.shield_active: try:
# Activer res = subprocess.check_output(['ps', '-eo', 'pid,user,%cpu,%mem,cmd', '--sort=-%cpu'], text=True)
event_handler = RealTimeShieldHandler(self) self.audit_console.insert("end", "\n".join(res.split('\n')[:11]) + "\n")
self.shield_observer = Observer() except Exception:
self.shield_observer.schedule(event_handler, self.watch_folder, recursive=False) self.audit_console.insert("end", "[-] Impossible de lire les processus.\n")
self.shield_observer.start()
self.shield_active = True
self.btn_toggle_shield.configure(text="Désactiver le Bouclier", fg_color="#C0392B", hover_color="#922B21")
self.rt_console.insert("end", f"\n[+] Bouclier ACTIVÉ sur {self.watch_folder}\n[*] En attente de nouveaux fichiers...\n")
else:
# Désactiver
self.shield_observer.stop()
self.shield_observer.join()
self.shield_active = False
self.btn_toggle_shield.configure(text="Activer le Bouclier", fg_color="#27AE60", hover_color="#1E8449")
self.rt_console.insert("end", "\n[-] Bouclier DÉSACTIVÉ.\n")
self.rt_console.see("end")
def trigger_realtime_scan(self, filepath):
"""Appelé automatiquement quand un nouveau fichier apparaît."""
self.rt_console.insert("end", f"\n⚡ Nouveau fichier détecté : {os.path.basename(filepath)}\n")
self.rt_console.insert("end", "[*] Analyse instantanée en cours...\n")
self.rt_console.see("end")
# On lance le scan dans un thread pour ne pas bloquer l'interface
threading.Thread(target=self.run_clamav_engine, args=(filepath, False, self.rt_console), daemon=True).start()
# ==========================================
# MODULES : AUDIT & UPDATE (Abregés pour l'exemple)
# ==========================================
def init_audit_view(self):
frame = ctk.CTkFrame(self, fg_color="transparent")
self.views["audit"] = frame
ctk.CTkLabel(frame, text="Audit Système", font=ctk.CTkFont(size=24, weight="bold")).pack(anchor="w")
ctk.CTkLabel(frame, text="Interface d'audit maintenue...").pack(pady=20)
# --- VUE : MISE À JOUR (OTA) ---
def init_update_view(self): def init_update_view(self):
frame = ctk.CTkFrame(self, fg_color="transparent") frame = ctk.CTkFrame(self, fg_color="transparent")
self.views["update"] = frame self.views["update"] = frame
ctk.CTkLabel(frame, text="Mise à jour (FreshClam)", font=ctk.CTkFont(size=24, weight="bold")).pack(anchor="w")
ctk.CTkLabel(frame, text="Utilisez 'sudo freshclam' dans le terminal.").pack(pady=20) ctk.CTkLabel(frame, text="Mises à jour de 7LnA", font=ctk.CTkFont(size=24, weight="bold")).pack(anchor="w", pady=(0, 20))
ctk.CTkLabel(frame, text="Vérifiez si une nouvelle version est disponible sur le dépôt officiel.\nL'application se mettra à jour automatiquement.", justify="left").pack(anchor="w", pady=10)
self.btn_update = ctk.CTkButton(frame, text="⬇️ Télécharger la dernière version", command=self.run_software_update, fg_color="#8E44AD", hover_color="#732D91")
self.btn_update.pack(anchor="w", pady=20)
self.update_console = ctk.CTkTextbox(frame, height=150, font=ctk.CTkFont(family="Consolas", size=13))
self.update_console.pack(fill="x", pady=10)
def run_software_update(self):
self.btn_update.configure(state="disabled")
self.update_console.insert("end", "[*] Connexion au serveur Git...\n")
try:
# os.path.abspath(__file__) trouve automatiquement le chemin exact du fichier en cours d'exécution
current_file_path = os.path.abspath(__file__)
urllib.request.urlretrieve(UPDATE_URL, current_file_path)
self.update_console.insert("end", "[+] Mise à jour téléchargée et appliquée !\n")
messagebox.showinfo("Mise à jour", "7LnA a été mis à jour avec succès. L'application va se fermer pour appliquer les changements.")
self.destroy()
except Exception as e:
self.update_console.insert("end", f"[-] Échec de la mise à jour : {e}\n")
self.btn_update.configure(state="normal")
if __name__ == "__main__": if __name__ == "__main__":