Actualiser 7lna.py
This commit is contained in:
187
7lna.py
187
7lna.py
@@ -14,15 +14,9 @@ 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
|
||||
# ==========================================
|
||||
@@ -30,11 +24,20 @@ 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
|
||||
@@ -49,7 +52,7 @@ class RealTimeShieldHandler(FileSystemEventHandler):
|
||||
class Antivirus7LnA(ctk.CTk):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.title("7LnA Security Suite - V10.3 Quantum Edition")
|
||||
self.title("7LnA Security Suite - V10.1 Quantum Edition")
|
||||
self.geometry("1250x850")
|
||||
self.minsize(1000, 700)
|
||||
|
||||
@@ -59,26 +62,13 @@ class Antivirus7LnA(ctk.CTk):
|
||||
|
||||
self.shield_observer = None
|
||||
self.shield_active = False
|
||||
self.zero_usb_mode = False
|
||||
self.gaming_mode = False # <--- État du mode Gaming/Discret
|
||||
self.zero_usb_mode = False # <--- AJOUT : État du mode Zero USB
|
||||
|
||||
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)
|
||||
@@ -93,7 +83,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(11, weight=1)
|
||||
self.sidebar.grid_rowconfigure(10, 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))
|
||||
|
||||
@@ -102,14 +92,13 @@ 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_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.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.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.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.views = {}
|
||||
self.init_dashboard_view()
|
||||
@@ -117,7 +106,6 @@ 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()
|
||||
@@ -170,13 +158,14 @@ 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:
|
||||
self.send_desktop_notification("⚡ Zero USB Actif", f"Analyse automatique forcée pour : {name}", is_critical=True)
|
||||
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:
|
||||
self.send_desktop_notification("USB Détectée", f"Disque {name} branché.")
|
||||
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()
|
||||
@@ -197,32 +186,18 @@ 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")
|
||||
|
||||
# Switch Zero USB
|
||||
# <--- AJOUT : Switch pour activer/désactiver le Mode 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")
|
||||
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)
|
||||
progress_color="#DC2626") # Rouge pour indiquer un mode "agressif"
|
||||
self.zero_usb_switch.pack(pady=20, 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É"
|
||||
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.")
|
||||
send_desktop_notification("Paramètre de Sécurité", f"Mode Zero USB {etat}")
|
||||
|
||||
# --- 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 :"):
|
||||
@@ -278,7 +253,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.3 prêt...\n", "info")
|
||||
self.scan_console.insert("end", f"{self.get_time_prefix()}[*] Moteur de détection V10.1 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())
|
||||
@@ -386,15 +361,9 @@ 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 = []
|
||||
# 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}'])
|
||||
cmd = ['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:
|
||||
@@ -408,7 +377,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: self.send_desktop_notification("🚨 VIRUS NEUTRALISÉ", f"{infected} menace(s) trouvée(s).", is_critical=True)
|
||||
else: 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()
|
||||
@@ -491,7 +460,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:
|
||||
self.send_desktop_notification("WiFi Guard", f"Attention : Beaucoup d'appareils ({count}) sont connectés à votre réseau.", is_critical=True)
|
||||
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")
|
||||
@@ -596,100 +565,6 @@ 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")
|
||||
|
||||
Reference in New Issue
Block a user