From 5b3d74607a4660909e853f5d741f6cc4b394666c Mon Sep 17 00:00:00 2001 From: 7ka1 <7ka1@noreply.localhost> Date: Thu, 19 Mar 2026 14:12:08 +0000 Subject: [PATCH] Actualiser 7lna.py --- 7lna.py | 187 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 156 insertions(+), 31 deletions(-) diff --git a/7lna.py b/7lna.py index 8992d21..5e39650 100644 --- a/7lna.py +++ b/7lna.py @@ -14,9 +14,15 @@ import secrets import json import platform import shutil +import base64 from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler +# --- Imports pour le chiffrement AES-256 (Vault) --- +from cryptography.fernet import Fernet +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC + # ========================================== # CONFIGURATION GLOBALE # ========================================== @@ -24,20 +30,11 @@ UPDATE_URL = "https://git.7ka1.com/7ka1/7LnA_Antivirus_Linux_Free_ClamAV_Based/r QUARANTINE_DIR = os.path.expanduser("~/.7lna_quarantine") WATCH_FOLDER = os.path.expanduser("~/Téléchargements") HISTORY_FILE = os.path.expanduser("~/.7lna_history.json") +VAULT_FILE = os.path.expanduser("~/.7lna_vault.enc") # Fichier chiffré du coffre-fort ctk.set_appearance_mode("dark") ctk.set_default_color_theme("blue") -# ========================================== -# UTILITAIRES SYSTÈME -# ========================================== -def send_desktop_notification(title, message, is_critical=False): - try: - urgency = 'critical' if is_critical else 'normal' - subprocess.Popen(['notify-send', '-u', urgency, '-a', '7LnA Security', title, message]) - except Exception: - pass - class RealTimeShieldHandler(FileSystemEventHandler): def __init__(self, app_instance): self.app = app_instance @@ -52,7 +49,7 @@ class RealTimeShieldHandler(FileSystemEventHandler): class Antivirus7LnA(ctk.CTk): def __init__(self): super().__init__() - self.title("7LnA Security Suite - V10.1 Quantum Edition") + self.title("7LnA Security Suite - V10.3 Quantum Edition") self.geometry("1250x850") self.minsize(1000, 700) @@ -62,13 +59,26 @@ class Antivirus7LnA(ctk.CTk): self.shield_observer = None self.shield_active = False - self.zero_usb_mode = False # <--- AJOUT : État du mode Zero USB + self.zero_usb_mode = False + self.gaming_mode = False # <--- État du mode Gaming/Discret self.check_dependencies() self.setup_ui() threading.Thread(target=self.monitor_usb_drives, daemon=True).start() + # --- UTILITAIRES SYSTÈME (Intégré à la classe pour gérer le Gaming Mode) --- + def send_desktop_notification(self, title, message, is_critical=False): + # Si le mode Gaming est actif et que l'alerte n'est pas critique, on bloque la notification + if self.gaming_mode and not is_critical: + return + + try: + urgency = 'critical' if is_critical else 'normal' + subprocess.Popen(['notify-send', '-u', urgency, '-a', '7LnA Security', title, message]) + except Exception: + pass + def check_dependencies(self): try: subprocess.run(['clamscan', '--version'], capture_output=True, check=True) @@ -83,7 +93,7 @@ class Antivirus7LnA(ctk.CTk): # --- BARRE LATÉRALE --- self.sidebar = ctk.CTkFrame(self, width=260, corner_radius=0, fg_color="#111827") self.sidebar.grid(row=0, column=0, sticky="nsew") - self.sidebar.grid_rowconfigure(10, weight=1) + self.sidebar.grid_rowconfigure(11, weight=1) ctk.CTkLabel(self.sidebar, text="🛡️ 7LnA Sec", font=ctk.CTkFont(size=30, weight="bold"), text_color="#3B82F6").grid(row=0, column=0, padx=20, pady=(30, 20)) @@ -92,13 +102,14 @@ class Antivirus7LnA(ctk.CTk): self.btn_shield = self.create_nav_button("⚡ Bouclier Actif", 3, "shield") 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_quarantine = self.create_nav_button("📦 Quarantaine", 6, "quarantine") - self.btn_schedule = self.create_nav_button("📅 Planification", 7, "schedule") - self.btn_history = self.create_nav_button("📜 Rapports", 8, "history") - self.btn_update = self.create_nav_button("🔄 Mise à jour", 9, "update") + self.btn_vault = self.create_nav_button("🔐 Coffre-fort (AES)", 6, "vault") # <--- AJOUT BOUTON VAULT + self.btn_quarantine = self.create_nav_button("📦 Quarantaine", 7, "quarantine") + self.btn_schedule = self.create_nav_button("📅 Planification", 8, "schedule") + self.btn_history = self.create_nav_button("📜 Rapports", 9, "history") + self.btn_update = self.create_nav_button("🔄 Mise à jour", 10, "update") - self.version_label = ctk.CTkLabel(self.sidebar, text="v10.1 - Quantum", text_color="#6B7280", font=ctk.CTkFont(weight="bold")) - self.version_label.grid(row=10, column=0, pady=20, sticky="s") + self.version_label = ctk.CTkLabel(self.sidebar, text="v10.3 - Quantum", text_color="#6B7280", font=ctk.CTkFont(weight="bold")) + self.version_label.grid(row=11, column=0, pady=20, sticky="s") self.views = {} self.init_dashboard_view() @@ -106,6 +117,7 @@ class Antivirus7LnA(ctk.CTk): self.init_realtime_view() self.init_audit_view() self.init_tools_view() + self.init_vault_view() # <--- INIT VAULT VIEW self.init_quarantine_view() self.init_schedule_view() self.init_history_view() @@ -158,14 +170,13 @@ class Antivirus7LnA(ctk.CTk): known_mounts = current_mounts except: pass - # <--- MODIFICATION : Logique Zero USB intégrée def prompt_usb_scan(self, path, name): if self.zero_usb_mode: - send_desktop_notification("⚡ Zero USB Actif", f"Analyse automatique forcée pour : {name}", is_critical=True) + self.send_desktop_notification("⚡ Zero USB Actif", f"Analyse automatique forcée pour : {name}", is_critical=True) self.select_view("scanner") threading.Thread(target=self.run_clamav_scan, args=(path, True, self.scan_console), daemon=True).start() else: - send_desktop_notification("USB Détectée", f"Disque {name} branché.") + self.send_desktop_notification("USB Détectée", f"Disque {name} branché.") if messagebox.askyesno("Protection USB", f"Nouveau périphérique USB détecté :\n{name}\n\nVoulez-vous l'analyser ?"): self.select_view("scanner") threading.Thread(target=self.run_clamav_scan, args=(path, True, self.scan_console), daemon=True).start() @@ -186,18 +197,32 @@ class Antivirus7LnA(ctk.CTk): sys_info = f"🖥️ OS : {platform.system()} {platform.release()} | 👤 Compte : {os.getlogin()}" ctk.CTkLabel(sys_frame, text=sys_info, font=ctk.CTkFont(size=16, weight="bold")).pack(padx=20, pady=10, anchor="w") - # <--- AJOUT : Switch pour activer/désactiver le Mode Zero USB + # Switch Zero USB self.zero_usb_switch = ctk.CTkSwitch(frame, text="🛡️ Mode Zero USB (Scan auto des clés USB)", command=self.toggle_zero_usb, font=ctk.CTkFont(size=16, weight="bold"), - progress_color="#DC2626") # Rouge pour indiquer un mode "agressif" - self.zero_usb_switch.pack(pady=20, anchor="w", padx=20) + progress_color="#DC2626") + self.zero_usb_switch.pack(pady=(20, 10), anchor="w", padx=20) + + # Switch Mode Gaming/Discret + self.gaming_switch = ctk.CTkSwitch(frame, text="🎮 Mode Gaming / Discret (Silencieux & Basse Priorité CPU)", + command=self.toggle_gaming_mode, + font=ctk.CTkFont(size=16, weight="bold"), + progress_color="#8B5CF6") + self.gaming_switch.pack(pady=10, anchor="w", padx=20) - # <--- AJOUT : Fonction de bascule pour le Switch def toggle_zero_usb(self): self.zero_usb_mode = self.zero_usb_switch.get() etat = "ACTIVÉ" if self.zero_usb_mode else "DÉSACTIVÉ" - send_desktop_notification("Paramètre de Sécurité", f"Mode Zero USB {etat}") + self.send_desktop_notification("Paramètre de Sécurité", f"Mode Zero USB {etat}") + + def toggle_gaming_mode(self): + self.gaming_mode = self.gaming_switch.get() + if self.gaming_mode: + # Envoi d'une dernière notification avant de se taire + self.send_desktop_notification("🎮 Mode Gaming Activé", "Notifications muettes. L'antivirus tourne en basse priorité.", is_critical=True) + else: + self.send_desktop_notification("🎮 Mode Gaming Désactivé", "Les ressources système et notifications sont restaurées.") # --- FONCTION D'AUTHENTIFICATION GLOBALE --- def get_sudo_password(self, callback_func, title="Sécurité Administrateur", msg="Privilèges requis pour cette action.\nEntrez votre mot de passe session :"): @@ -253,7 +278,7 @@ class Antivirus7LnA(ctk.CTk): self.scan_console = ctk.CTkTextbox(frame, font=ctk.CTkFont(family="Consolas", size=13), fg_color="#111827", corner_radius=10) self.scan_console.grid(row=4, column=0, columnspan=3, pady=20, sticky="nsew") self.setup_console_tags(self.scan_console) - self.scan_console.insert("end", f"{self.get_time_prefix()}[*] Moteur de détection V10.1 prêt...\n", "info") + self.scan_console.insert("end", f"{self.get_time_prefix()}[*] Moteur de détection V10.3 prêt...\n", "info") def run_rootkit_scan(self): self.get_sudo_password(lambda pwd: threading.Thread(target=self._exec_rootkit, args=(pwd,), daemon=True).start()) @@ -361,9 +386,15 @@ class Antivirus7LnA(ctk.CTk): console.insert("end", f"{self.get_time_prefix()}[*] Analyse : {path}\n") if console == self.scan_console: self.scan_progress.start() try: - cmd = ['clamscan', '-i', '--no-summary', f'--move={QUARANTINE_DIR}'] + cmd = [] + # Si le Mode Gaming est actif, on utilise 'nice' pour baisser la priorité CPU du scan (sur Linux, nice 15 est très bas) + if self.gaming_mode: + cmd.extend(['nice', '-n', '15']) + + cmd.extend(['clamscan', '-i', '--no-summary', f'--move={QUARANTINE_DIR}']) if is_dir: cmd.append('-r') cmd.append(path) + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) infected = 0 for line in process.stdout: @@ -377,7 +408,7 @@ class Antivirus7LnA(ctk.CTk): console.see("end") process.wait() if infected == 0: console.insert("end", f"{self.get_time_prefix()}[+] Fichier propre.\n", "success") - else: send_desktop_notification("🚨 VIRUS NEUTRALISÉ", f"{infected} menace(s) trouvée(s).", is_critical=True) + else: self.send_desktop_notification("🚨 VIRUS NEUTRALISÉ", f"{infected} menace(s) trouvée(s).", is_critical=True) except Exception as e: console.insert("end", f"{self.get_time_prefix()}❌ Erreur : {e}\n", "danger") finally: if console == self.scan_console: self.scan_progress.stop() @@ -460,7 +491,7 @@ class Antivirus7LnA(ctk.CTk): self.audit_console.insert("end", f"\n{self.get_time_prefix()}[+] Scan terminé. {count} appareils détectés sur votre WiFi.\n", "info") if count > 15: - send_desktop_notification("WiFi Guard", f"Attention : Beaucoup d'appareils ({count}) sont connectés à votre réseau.", is_critical=True) + self.send_desktop_notification("WiFi Guard", f"Attention : Beaucoup d'appareils ({count}) sont connectés à votre réseau.", is_critical=True) except Exception as e: self.audit_console.insert("end", f"❌ Erreur : {e}\n", "danger") @@ -565,6 +596,100 @@ class Antivirus7LnA(ctk.CTk): messagebox.showinfo("Succès", "Fichier détruit.") except: pass + # ========================================== + # --- VUE : COFFRE-FORT (NOUVEAU) --- + # ========================================== + def init_vault_view(self): + frame = ctk.CTkFrame(self, fg_color="transparent") + frame.grid_rowconfigure(2, weight=1) + frame.grid_columnconfigure(0, weight=1) + self.views["vault"] = frame + + ctk.CTkLabel(frame, text="🔐 Coffre-fort AES-256", font=ctk.CTkFont(size=34, weight="bold")).grid(row=0, column=0, sticky="w", pady=(0, 20)) + + # Panel de connexion + self.vault_login_frame = ctk.CTkFrame(frame, fg_color="#1F2937", corner_radius=10) + self.vault_login_frame.grid(row=1, column=0, sticky="ew", ipady=20) + + ctk.CTkLabel(self.vault_login_frame, text="Entrez le mot de passe maître :", font=ctk.CTkFont(size=16)).pack(pady=(20, 10)) + self.vault_pwd_entry = ctk.CTkEntry(self.vault_login_frame, show="*", width=300) + self.vault_pwd_entry.pack(pady=10) + + ctk.CTkButton(self.vault_login_frame, text="Déverrouiller / Créer", fg_color="#2563EB", hover_color="#1D4ED8", command=self.unlock_vault).pack(pady=10) + ctk.CTkLabel(self.vault_login_frame, text="Note: Si le coffre n'existe pas, ce mot de passe sera utilisé pour le créer.", text_color="#9CA3AF").pack() + + # Panel de l'éditeur (caché par défaut) + self.vault_editor_frame = ctk.CTkFrame(frame, fg_color="transparent") + + header_editor = ctk.CTkFrame(self.vault_editor_frame, fg_color="transparent") + header_editor.pack(fill="x", pady=(0, 10)) + ctk.CTkLabel(header_editor, text="Vos notes sécurisées :", font=ctk.CTkFont(size=18, weight="bold"), text_color="#10B981").pack(side="left") + ctk.CTkButton(header_editor, text="🔒 Sauvegarder et Verrouiller", fg_color="#059669", hover_color="#047857", command=self.save_vault).pack(side="right") + + self.vault_textbox = ctk.CTkTextbox(self.vault_editor_frame, font=ctk.CTkFont(family="Consolas", size=14), fg_color="#111827", corner_radius=10) + self.vault_textbox.pack(fill="both", expand=True) + + self.current_vault_pwd = None + self.current_vault_salt = None + + def _derive_key(self, password, salt): + kdf = PBKDF2HMAC( + algorithm=hashes.SHA256(), + length=32, + salt=salt, + iterations=480000, + ) + return base64.urlsafe_b64encode(kdf.derive(password.encode())) + + def unlock_vault(self): + pwd = self.vault_pwd_entry.get() + if not pwd: return + + if os.path.exists(VAULT_FILE): + try: + with open(VAULT_FILE, "rb") as f: data = f.read() + salt = data[:16] + encrypted = data[16:] + key = self._derive_key(pwd, salt) + fernet = Fernet(key) + decrypted = fernet.decrypt(encrypted).decode() + + # Succès ! + self.current_vault_pwd = pwd + self.current_vault_salt = salt + self.show_vault_editor(decrypted) + except Exception: + messagebox.showerror("Accès Refusé", "Mot de passe incorrect ou fichier corrompu.") + else: + # Nouveau coffre + self.current_vault_pwd = pwd + self.current_vault_salt = os.urandom(16) + self.show_vault_editor("=== VOTRE COFFRE EST VIDE ===\n\nÉcrivez vos identifiants ou notes secrètes ici...") + + def show_vault_editor(self, content): + self.vault_login_frame.grid_forget() + self.vault_editor_frame.grid(row=2, column=0, sticky="nsew") + self.vault_pwd_entry.delete(0, 'end') + self.vault_textbox.delete("0.0", "end") + self.vault_textbox.insert("end", content) + + def save_vault(self): + data = self.vault_textbox.get("0.0", "end") + key = self._derive_key(self.current_vault_pwd, self.current_vault_salt) + fernet = Fernet(key) + encrypted = fernet.encrypt(data.encode()) + + with open(VAULT_FILE, "wb") as f_out: + f_out.write(self.current_vault_salt + encrypted) + + self.current_vault_pwd = None + self.current_vault_salt = None + self.vault_textbox.delete("0.0", "end") + + self.vault_editor_frame.grid_forget() + self.vault_login_frame.grid(row=1, column=0, sticky="ew", ipady=20) + self.send_desktop_notification("Coffre-fort", "Fichier chiffré avec succès et verrouillé.") + # ----- PLANIFICATION ----- def init_schedule_view(self): frame = ctk.CTkFrame(self, fg_color="transparent")