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 subprocess
import urllib.request import urllib.request
import time import time
import random
from watchdog.observers import Observer from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler from watchdog.events import FileSystemEventHandler
# ========================================== # ==========================================
# CONFIGURATION GLOBALE # 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" 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") QUARANTINE_DIR = os.path.expanduser("~/.7lna_quarantine")
WATCH_FOLDER = os.path.expanduser("~/Téléchargements") 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")
@@ -30,7 +28,7 @@ class RealTimeShieldHandler(FileSystemEventHandler):
def on_created(self, event): def on_created(self, event):
if not event.is_directory: 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) self.app.trigger_realtime_scan(event.src_path)
# ========================================== # ==========================================
@@ -39,13 +37,11 @@ class RealTimeShieldHandler(FileSystemEventHandler):
class Antivirus7LnA(ctk.CTk): class Antivirus7LnA(ctk.CTk):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.title("7LnA Security Suite") self.title("7LnA Security Suite - Advanced Edition")
self.geometry("1050x650") self.geometry("1100x700")
self.minsize(850, 550) self.minsize(900, 600)
# Création du dossier de quarantaine
os.makedirs(QUARANTINE_DIR, exist_ok=True) os.makedirs(QUARANTINE_DIR, exist_ok=True)
self.shield_observer = None self.shield_observer = None
self.shield_active = False self.shield_active = False
@@ -64,20 +60,21 @@ class Antivirus7LnA(ctk.CTk):
self.grid_columnconfigure(1, weight=1) self.grid_columnconfigure(1, weight=1)
# --- BARRE LATÉRALE --- # --- 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(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_dash = self.create_nav_button("📊 Tableau de Bord", 1, "dashboard")
self.btn_scan = self.create_nav_button("🔍 Scanner Manuel", 2, "scanner") self.btn_scan = self.create_nav_button("🔍 Scanner Manuel", 2, "scanner")
self.btn_shield = self.create_nav_button("⚡ Bouclier Actif", 3, "shield") 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 Réseau", 4, "audit")
self.btn_update = self.create_nav_button("🔄 Mise à jour", 5, "update") 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 = ctk.CTkLabel(self.sidebar, text="v6.0 - Advanced", text_color="#6B7280")
self.version_label.grid(row=6, column=0, pady=20, sticky="s") self.version_label.grid(row=7, column=0, pady=20, sticky="s")
# --- CONTENEUR DES VUES --- # --- CONTENEUR DES VUES ---
self.views = {} self.views = {}
@@ -85,13 +82,14 @@ class Antivirus7LnA(ctk.CTk):
self.init_scanner_view() self.init_scanner_view()
self.init_realtime_view() self.init_realtime_view()
self.init_audit_view() self.init_audit_view()
self.init_tools_view()
self.init_update_view() self.init_update_view()
self.select_view("dashboard") self.select_view("dashboard")
def create_nav_button(self, text, row, view_name): def create_nav_button(self, text, row, view_name):
btn = ctk.CTkButton(self.sidebar, text=text, anchor="w", fg_color="transparent", 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)) command=lambda: self.select_view(view_name))
btn.grid(row=row, column=0, padx=20, pady=10, sticky="ew") btn.grid(row=row, column=0, padx=20, pady=10, sticky="ew")
return btn return btn
@@ -100,22 +98,32 @@ class Antivirus7LnA(ctk.CTk):
for view in self.views.values(): for view in self.views.values():
view.grid_forget() view.grid_forget()
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=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 --- # --- VUE : 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
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_card.pack(fill="x", pady=10, ipady=20)
status_text = "Moteur ClamAV Opérationnel" if self.clamav_installed else "Moteur ClamAV Introuvable" 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 --- # --- VUE : SCANNER MANUEL ---
def init_scanner_view(self): def init_scanner_view(self):
@@ -124,17 +132,18 @@ class Antivirus7LnA(ctk.CTk):
frame.grid_columnconfigure((0, 1), weight=1) frame.grid_columnconfigure((0, 1), weight=1)
self.views["scanner"] = frame 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_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.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.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): 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()
@@ -151,15 +160,14 @@ class Antivirus7LnA(ctk.CTk):
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", font=ctk.CTkFont(size=24, weight="bold")).pack(side="left") ctk.CTkLabel(header, text="⚡ Bouclier Actif", font=ctk.CTkFont(size=28, 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 = 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") 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), fg_color="#111827")
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.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): def toggle_shield(self):
if not self.shield_active: 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.schedule(RealTimeShieldHandler(self), WATCH_FOLDER, recursive=False)
self.shield_observer.start() self.shield_observer.start()
self.shield_active = True self.shield_active = True
self.btn_toggle_shield.configure(text="Désactiver le Bouclier", fg_color="#C0392B", hover_color="#922B21") self.btn_toggle_shield.configure(text="Arrêter le Bouclier", fg_color="#DC2626", hover_color="#B91C1C")
self.rt_console.insert("end", f"\n[+] BOUCLIER ACTIVÉ sur {WATCH_FOLDER}\n[*] Analyse automatique prête...\n") self.rt_console.insert("end", f"\n[+] BOUCLIER ARMÉ sur {WATCH_FOLDER}\n", "success")
else: else:
self.shield_observer.stop() self.shield_observer.stop()
self.shield_active = False self.shield_active = False
self.btn_toggle_shield.configure(text="Activer le Bouclier", fg_color="#27AE60", hover_color="#1E8449") 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") self.rt_console.insert("end", "\n[-] Bouclier désactivé.\n", "warning")
self.rt_console.see("end") self.rt_console.see("end")
def trigger_realtime_scan(self, filepath): 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() 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): def run_clamav_scan(self, path, is_dir, console):
if not self.clamav_installed: 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 return
console.insert("end", f"[*] Début de l'analyse : {path}\n") console.insert("end", f"[*] Analyse en cours : {path}\n")
console.see("end")
try: try:
cmd = ['clamscan', '-i', '--no-summary', f'--move={QUARANTINE_DIR}'] cmd = ['clamscan', '-i', '--no-summary', f'--move={QUARANTINE_DIR}']
if is_dir: cmd.append('-r') if is_dir: cmd.append('-r')
@@ -198,7 +205,8 @@ 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🛡️ Isolé en quarantaine.\n") console.insert("end", f"☠️ MENACE : {clean_line}\n", "danger")
console.insert("end", "🛡️ Action : Isolé en quarantaine.\n", "warning")
infected += 1 infected += 1
else: else:
console.insert("end", clean_line + "\n") console.insert("end", clean_line + "\n")
@@ -206,79 +214,130 @@ class Antivirus7LnA(ctk.CTk):
process.wait() process.wait()
if infected == 0: 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: 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: 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") console.see("end")
# --- VUE : AUDIT SYSTÈME --- # --- VUE : AUDIT & PARE-FEU ---
def init_audit_view(self): def init_audit_view(self):
frame = ctk.CTkFrame(self, fg_color="transparent") 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) frame.grid_columnconfigure(0, weight=1)
self.views["audit"] = frame self.views["audit"] = frame
header = ctk.CTkFrame(frame, fg_color="transparent") 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))
header.grid(row=0, column=0, sticky="ew", pady=(0, 20))
ctk.CTkLabel(header, text="Vérification des Vulnérabilités", font=ctk.CTkFont(size=24, weight="bold")).pack(side="left") btn_frame = ctk.CTkFrame(frame, fg_color="transparent")
ctk.CTkButton(header, text="Lancer l'Audit", command=self.run_audit_thread).pack(side="right") 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)) 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))
self.audit_console.grid(row=1, column=0, sticky="nsew") 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): def run_audit_thread(self):
self.audit_console.delete("0.0", "end") self.audit_console.delete("0.0", "end")
threading.Thread(target=self.perform_audit, daemon=True).start() threading.Thread(target=self.perform_audit, daemon=True).start()
def perform_audit(self): 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: try:
self.audit_console.insert("end", subprocess.check_output(['ss', '-tuln'], text=True)) self.audit_console.insert("end", subprocess.check_output(['ss', '-tuln'], text=True))
except Exception: except: pass
self.audit_console.insert("end", "[-] Impossible de lire le réseau.\n")
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: try:
res = subprocess.check_output(['ps', '-eo', 'pid,user,%cpu,%mem,cmd', '--sort=-%cpu'], text=True) 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") 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: 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) --- # --- 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="Mises à jour de 7LnA", font=ctk.CTkFont(size=24, weight="bold")).pack(anchor="w", pady=(0, 20)) ctk.CTkLabel(frame, text="Mise à jour Cloud", font=ctk.CTkFont(size=28, 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="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 = 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", pady=20) self.btn_update.pack(anchor="w")
self.update_console = ctk.CTkTextbox(frame, height=150, font=ctk.CTkFont(family="Consolas", size=13)) 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=10) self.update_console.pack(fill="x", pady=20)
self.setup_console_tags(self.update_console)
def run_software_update(self): def run_software_update(self):
self.btn_update.configure(state="disabled") 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: try:
# os.path.abspath(__file__) trouve automatiquement le chemin exact du fichier en cours d'exécution
current_file_path = os.path.abspath(__file__) current_file_path = os.path.abspath(__file__)
urllib.request.urlretrieve(UPDATE_URL, current_file_path) urllib.request.urlretrieve(UPDATE_URL, current_file_path)
self.update_console.insert("end", "[+] Mise à jour téléchargée et appliquée !\n") self.update_console.insert("end", "[+] Code source remplacé avec succès !\n", "success")
messagebox.showinfo("Mise à jour", "7LnA a été mis à jour avec succès. L'application va se fermer pour appliquer les changements.") messagebox.showinfo("Mise à jour Appliquée", "Redémarrage requis pour initialiser la nouvelle version.")
self.destroy() self.destroy()
except Exception as e: 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") self.btn_update.configure(state="normal")
if __name__ == "__main__": if __name__ == "__main__":
app = Antivirus7LnA() app = Antivirus7LnA()
app.mainloop() app.mainloop()