Actualiser 7lna.py

This commit is contained in:
2026-03-02 15:28:49 +00:00
parent 0aef5fb334
commit d059259e4d

201
7lna.py
View File

@@ -5,19 +5,17 @@ import threading
import subprocess
import urllib.request
import time
import random
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
# ==========================================
# 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_default_color_theme("blue")
@@ -30,7 +28,7 @@ class RealTimeShieldHandler(FileSystemEventHandler):
def on_created(self, event):
if not event.is_directory:
time.sleep(1.5) # Laisse le temps au téléchargement de se terminer
time.sleep(1.5)
self.app.trigger_realtime_scan(event.src_path)
# ==========================================
@@ -39,13 +37,11 @@ class RealTimeShieldHandler(FileSystemEventHandler):
class Antivirus7LnA(ctk.CTk):
def __init__(self):
super().__init__()
self.title("7LnA Security Suite")
self.geometry("1050x650")
self.minsize(850, 550)
self.title("7LnA Security Suite - Advanced Edition")
self.geometry("1100x700")
self.minsize(900, 600)
# Création du dossier de quarantaine
os.makedirs(QUARANTINE_DIR, exist_ok=True)
self.shield_observer = None
self.shield_active = False
@@ -64,20 +60,21 @@ class Antivirus7LnA(ctk.CTk):
self.grid_columnconfigure(1, weight=1)
# --- BARRE LATÉRALE ---
self.sidebar = ctk.CTkFrame(self, width=220, corner_radius=0)
self.sidebar = ctk.CTkFrame(self, width=240, corner_radius=0, fg_color="#111827")
self.sidebar.grid(row=0, column=0, sticky="nsew")
self.sidebar.grid_rowconfigure(6, weight=1)
self.sidebar.grid_rowconfigure(7, weight=1)
ctk.CTkLabel(self.sidebar, text="🛡️ 7LnA", font=ctk.CTkFont(size=28, weight="bold")).grid(row=0, column=0, padx=20, pady=30)
ctk.CTkLabel(self.sidebar, text="🛡️ 7LnA Sec", font=ctk.CTkFont(size=28, weight="bold"), text_color="#3B82F6").grid(row=0, column=0, padx=20, pady=30)
self.btn_dash = self.create_nav_button("📊 Tableau de Bord", 1, "dashboard")
self.btn_scan = self.create_nav_button("🔍 Scanner Manuel", 2, "scanner")
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_update = self.create_nav_button("🔄 Mise à jour", 5, "update")
self.btn_audit = self.create_nav_button("⚙️ Audit Réseau", 4, "audit")
self.btn_tools = self.create_nav_button("🧰 Outils Avancés", 5, "tools")
self.btn_update = self.create_nav_button("🔄 Mise à jour", 6, "update")
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 = ctk.CTkLabel(self.sidebar, text="v6.0 - Advanced", text_color="#6B7280")
self.version_label.grid(row=7, column=0, pady=20, sticky="s")
# --- CONTENEUR DES VUES ---
self.views = {}
@@ -85,13 +82,14 @@ class Antivirus7LnA(ctk.CTk):
self.init_scanner_view()
self.init_realtime_view()
self.init_audit_view()
self.init_tools_view()
self.init_update_view()
self.select_view("dashboard")
def create_nav_button(self, text, row, view_name):
btn = ctk.CTkButton(self.sidebar, text=text, anchor="w", fg_color="transparent",
text_color=("gray10", "#DCE4EE"), hover_color=("gray70", "gray30"),
text_color="#D1D5DB", hover_color="#1F2937", font=ctk.CTkFont(size=14),
command=lambda: self.select_view(view_name))
btn.grid(row=row, column=0, padx=20, pady=10, sticky="ew")
return btn
@@ -100,22 +98,32 @@ class Antivirus7LnA(ctk.CTk):
for view in self.views.values():
view.grid_forget()
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=30, pady=30)
# --- UTILITAIRES DE CONSOLE (COULEURS) ---
def setup_console_tags(self, console):
"""Ajoute le support des couleurs dans les consoles textuelles"""
console.tag_config("danger", foreground="#EF4444") # Rouge
console.tag_config("success", foreground="#10B981") # Vert
console.tag_config("warning", foreground="#F59E0B") # Orange
console.tag_config("info", foreground="#3B82F6") # Bleu
# --- VUE : TABLEAU DE BORD ---
def init_dashboard_view(self):
frame = ctk.CTkFrame(self, fg_color="transparent")
self.views["dashboard"] = frame
ctk.CTkLabel(frame, text="État du Système", font=ctk.CTkFont(size=24, weight="bold")).pack(anchor="w", pady=(0, 20))
ctk.CTkLabel(frame, text="État du Système", font=ctk.CTkFont(size=28, weight="bold")).pack(anchor="w", pady=(0, 20))
status_card = ctk.CTkFrame(frame, fg_color="#1E8449" if self.clamav_installed else "#C0392B", corner_radius=15)
status_card = ctk.CTkFrame(frame, fg_color="#064E3B" if self.clamav_installed else "#7F1D1D", corner_radius=15)
status_card.pack(fill="x", pady=10, ipady=20)
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=20, weight="bold"), text_color="white").pack(expand=True)
ctk.CTkLabel(frame, text=f"📂 Dossier de quarantaine : {QUARANTINE_DIR}").pack(anchor="w", pady=10)
info_frame = ctk.CTkFrame(frame, fg_color="#1F2937", corner_radius=10)
info_frame.pack(fill="x", pady=20, ipady=10)
ctk.CTkLabel(info_frame, text=f"📂 Dossier Quarantaine : {QUARANTINE_DIR}\n📁 Dossier Surveillé : {WATCH_FOLDER}", justify="left", font=ctk.CTkFont(size=14)).pack(padx=20, pady=10, anchor="w")
# --- VUE : SCANNER MANUEL ---
def init_scanner_view(self):
@@ -124,17 +132,18 @@ class Antivirus7LnA(ctk.CTk):
frame.grid_columnconfigure((0, 1), weight=1)
self.views["scanner"] = frame
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 Profonde", font=ctk.CTkFont(size=28, 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_manual_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=45, fg_color="#2563EB", hover_color="#1D4ED8")
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_manual_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=45, fg_color="#4F46E5", hover_color="#4338CA")
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), fg_color="#111827")
self.scan_console.grid(row=2, column=0, columnspan=2, pady=20, sticky="nsew")
self.scan_console.insert("end", "[*] Prêt. Les menaces seront automatiquement isolées.\n")
self.setup_console_tags(self.scan_console)
self.scan_console.insert("end", "[*] Moteur prêt. En attente de cible...\n", "info")
def start_manual_scan(self, is_dir):
path = filedialog.askdirectory() if is_dir else filedialog.askopenfilename()
@@ -151,15 +160,14 @@ class Antivirus7LnA(ctk.CTk):
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)
ctk.CTkLabel(header, text="⚡ Bouclier Actif", font=ctk.CTkFont(size=28, weight="bold")).pack(side="left")
self.btn_toggle_shield = ctk.CTkButton(header, text="Démarrer la Surveillance", fg_color="#059669", hover_color="#047857", command=self.toggle_shield, height=40)
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 = ctk.CTkTextbox(frame, font=ctk.CTkFont(family="Consolas", size=13), fg_color="#111827")
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")
self.setup_console_tags(self.rt_console)
self.rt_console.insert("end", "[-] Bouclier en attente.\n")
def toggle_shield(self):
if not self.shield_active:
@@ -167,27 +175,26 @@ class Antivirus7LnA(ctk.CTk):
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")
self.btn_toggle_shield.configure(text="Arrêter le Bouclier", fg_color="#DC2626", hover_color="#B91C1C")
self.rt_console.insert("end", f"\n[+] BOUCLIER ARMÉ sur {WATCH_FOLDER}\n", "success")
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.btn_toggle_shield.configure(text="Démarrer la Surveillance", fg_color="#059669", hover_color="#047857")
self.rt_console.insert("end", "\n[-] Bouclier désactivé.\n", "warning")
self.rt_console.see("end")
def trigger_realtime_scan(self, filepath):
self.rt_console.insert("end", f"\nDétection auto : {os.path.basename(filepath)}\n")
self.rt_console.insert("end", f"\nFichier capté : {os.path.basename(filepath)}\n", "info")
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) ---
# --- MOTEUR CLAMAV (Cœur) ---
def run_clamav_scan(self, path, is_dir, console):
if not self.clamav_installed:
console.insert("end", "❌ Erreur : ClamAV n'est pas installé.\n")
console.insert("end", "❌ Erreur critique : Moteur introuvable.\n", "danger")
return
console.insert("end", f"[*] Début de l'analyse : {path}\n")
console.see("end")
console.insert("end", f"[*] Analyse en cours : {path}\n")
try:
cmd = ['clamscan', '-i', '--no-summary', f'--move={QUARANTINE_DIR}']
if is_dir: cmd.append('-r')
@@ -198,7 +205,8 @@ class Antivirus7LnA(ctk.CTk):
for line in process.stdout:
clean_line = line.strip()
if "FOUND" in clean_line:
console.insert("end", f"☠️ DANGER : {clean_line}\n🛡️ Isolé en quarantaine.\n")
console.insert("end", f"☠️ MENACE : {clean_line}\n", "danger")
console.insert("end", "🛡️ Action : Isolé en quarantaine.\n", "warning")
infected += 1
else:
console.insert("end", clean_line + "\n")
@@ -206,79 +214,130 @@ class Antivirus7LnA(ctk.CTk):
process.wait()
if infected == 0:
console.insert("end", "[+] Analyse terminée. Fichier(s) propre(s).\n")
console.insert("end", "[+] Cible sécurisée (Propre).\n", "success")
else:
console.insert("end", f"🚨 {infected} menace(s) neutralisée(s) !\n")
console.insert("end", f"🚨 {infected} virus neutralisé(s) !\n", "danger")
except Exception as e:
console.insert("end", f"Erreur système : {e}\n")
console.insert("end", f"Panne moteur : {e}\n", "danger")
console.see("end")
# --- VUE : AUDIT SYSTÈME ---
# --- VUE : AUDIT & PARE-FEU ---
def init_audit_view(self):
frame = ctk.CTkFrame(self, fg_color="transparent")
frame.grid_rowconfigure(1, weight=1)
frame.grid_rowconfigure(2, weight=1)
frame.grid_columnconfigure(0, weight=1)
self.views["audit"] = frame
header = ctk.CTkFrame(frame, fg_color="transparent")
header.grid(row=0, column=0, sticky="ew", pady=(0, 20))
ctk.CTkLabel(frame, text="Audit Réseau & Pare-feu", font=ctk.CTkFont(size=28, weight="bold")).grid(row=0, column=0, sticky="w", pady=(0, 20))
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")
btn_frame = ctk.CTkFrame(frame, fg_color="transparent")
btn_frame.grid(row=1, column=0, sticky="ew", pady=(0, 10))
self.audit_console = ctk.CTkTextbox(frame, font=ctk.CTkFont(family="Consolas", size=13))
self.audit_console.grid(row=1, column=0, sticky="nsew")
ctk.CTkButton(btn_frame, text="Lancer l'Audit Processus", command=self.run_audit_thread, fg_color="#D97706", hover_color="#B45309").pack(side="left", padx=(0, 10))
ctk.CTkButton(btn_frame, text="Vérifier Statut UFW (Pare-feu)", command=self.check_firewall, fg_color="#4B5563", hover_color="#374151").pack(side="left")
self.audit_console = ctk.CTkTextbox(frame, font=ctk.CTkFont(family="Consolas", size=13), fg_color="#111827")
self.audit_console.grid(row=2, column=0, sticky="nsew")
self.setup_console_tags(self.audit_console)
def run_audit_thread(self):
self.audit_console.delete("0.0", "end")
threading.Thread(target=self.perform_audit, daemon=True).start()
def perform_audit(self):
self.audit_console.insert("end", "[*] Ports réseaux ouverts (Recherche de Backdoors)...\n")
self.audit_console.insert("end", "[*] Recherche de connexions fantômes (Backdoors)...\n", "info")
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")
except: pass
self.audit_console.insert("end", "\n[*] Top 10 des processus gourmands...\n")
self.audit_console.insert("end", "\n[*] Top 10 Processus (Charge CPU)...\n", "info")
try:
res = subprocess.check_output(['ps', '-eo', 'pid,user,%cpu,%mem,cmd', '--sort=-%cpu'], text=True)
self.audit_console.insert("end", "\n".join(res.split('\n')[:11]) + "\n")
except: pass
def check_firewall(self):
self.audit_console.delete("0.0", "end")
self.audit_console.insert("end", "[*] Interrogation du pare-feu Ubuntu (UFW)...\n", "info")
try:
# systemctl est utilisé pour éviter le prompt sudo de ufw
res = subprocess.check_output(['systemctl', 'is-active', 'ufw'], text=True).strip()
if res == "active":
self.audit_console.insert("end", "✅ PARE-FEU UFW ACTIF ET EN LIGNE.\n", "success")
else:
self.audit_console.insert("end", "⚠️ ATTENTION : PARE-FEU INACTIF.\nActivez-le via terminal avec 'sudo ufw enable'.\n", "danger")
except Exception:
self.audit_console.insert("end", "[-] Impossible de lire les processus.\n")
self.audit_console.insert("end", "[-] Impossible de déterminer l'état de UFW.\n", "warning")
# --- VUE : OUTILS AVANCÉS (NOUVEAU !) ---
def init_tools_view(self):
frame = ctk.CTkFrame(self, fg_color="transparent")
self.views["tools"] = frame
ctk.CTkLabel(frame, text="Boîte à Outils", font=ctk.CTkFont(size=28, weight="bold")).pack(anchor="w", pady=(0, 20))
# Outil 1 : Destructeur de fichiers
shred_card = ctk.CTkFrame(frame, fg_color="#1F2937", corner_radius=10)
shred_card.pack(fill="x", pady=10, ipady=15)
ctk.CTkLabel(shred_card, text="🔥 Destructeur de fichiers sécurisé (File Shredder)", font=ctk.CTkFont(size=16, weight="bold"), text_color="#EF4444").pack(anchor="w", padx=20)
ctk.CTkLabel(shred_card, text="Écrase un fichier avec des données aléatoires (3 passes) avant de le supprimer.\nEmpêche toute récupération par un logiciel tiers.", justify="left", text_color="#9CA3AF").pack(anchor="w", padx=20, pady=(5, 15))
ctk.CTkButton(shred_card, text="Détruire un fichier à jamais", fg_color="#DC2626", hover_color="#991B1B", command=self.run_shredder).pack(anchor="w", padx=20)
def run_shredder(self):
filepath = filedialog.askopenfilename(title="SÉLECTIONNEZ LE FICHIER À DÉTRUIRE")
if not filepath: return
confirm = messagebox.askyesno("DANGER IRRÉVERSIBLE", f"Voulez-vous vraiment DÉTRUIRE ce fichier ?\n\n{filepath}\n\nCette action est permanente et ne va PAS dans la corbeille.")
if confirm:
threading.Thread(target=self.shred_file, args=(filepath,), daemon=True).start()
def shred_file(self, filepath):
try:
file_size = os.path.getsize(filepath)
# 3 passages de réécriture
for i in range(3):
with open(filepath, "ba+", buffering=0) as f:
f.seek(0)
f.write(os.urandom(file_size))
# Suppression finale du système
os.remove(filepath)
messagebox.showinfo("Succès", "Fichier pulvérisé avec succès. Récupération impossible.")
except Exception as e:
messagebox.showerror("Erreur Shredder", f"Impossible de détruire le fichier.\nErreur : {e}")
# --- VUE : MISE À JOUR (OTA) ---
def init_update_view(self):
frame = ctk.CTkFrame(self, fg_color="transparent")
self.views["update"] = frame
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)
ctk.CTkLabel(frame, text="Mise à jour Cloud", font=ctk.CTkFont(size=28, weight="bold")).pack(anchor="w", pady=(0, 20))
ctk.CTkLabel(frame, text="Restez synchronisé avec le serveur officiel 7ka1 Git.", text_color="#9CA3AF").pack(anchor="w", pady=(0, 20))
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.btn_update = ctk.CTkButton(frame, text="⬇️ Forcer la mise à jour depuis Gitea", command=self.run_software_update, fg_color="#8B5CF6", hover_color="#7C3AED", height=45)
self.btn_update.pack(anchor="w")
self.update_console = ctk.CTkTextbox(frame, height=150, font=ctk.CTkFont(family="Consolas", size=13))
self.update_console.pack(fill="x", pady=10)
self.update_console = ctk.CTkTextbox(frame, height=150, font=ctk.CTkFont(family="Consolas", size=13), fg_color="#111827")
self.update_console.pack(fill="x", pady=20)
self.setup_console_tags(self.update_console)
def run_software_update(self):
self.btn_update.configure(state="disabled")
self.update_console.insert("end", "[*] Connexion au serveur Git...\n")
self.update_console.insert("end", "[*] Négociation avec git.7ka1.com...\n", "info")
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.update_console.insert("end", "[+] Code source remplacé avec succès !\n", "success")
messagebox.showinfo("Mise à jour Appliquée", "Redémarrage requis pour initialiser la nouvelle version.")
self.destroy()
except Exception as e:
self.update_console.insert("end", f"[-] Échec de la mise à jour : {e}\n")
self.update_console.insert("end", f"[-] Échec de la liaison avec le serveur : {e}\n", "danger")
self.btn_update.configure(state="normal")
if __name__ == "__main__":
app = Antivirus7LnA()
app.mainloop()