import os from dotenv import load_dotenv load_dotenv() # Force la lecture du fichier .env en local import uuid import json from fasthtml.common import * from starlette.staticfiles import StaticFiles from starlette.responses import FileResponse, Response, HTMLResponse, RedirectResponse from starlette.middleware.base import BaseHTTPMiddleware from modules.theme import get_theme_hdrs from modules.database import nettoyer_vieilles_discussions, HISTORY_FILE, load_history, save_history from modules.ui_components import render_main_page, render_sidebar, render_login_page from modules.chat_handler import handle_chat_request from modules.security import verifier_et_bloquer_vpn, journaliser_ip from modules.auth_manager import IDENTIFIANTS_ADMIN, verifier_mot_de_passe from modules.logger import log_event from modules.billing_manager import charger_soldes, sauvegarder_soldes # Lancement du module d'auto-mise à jour en arrière-plan import modules.model_updater dossier_media = "/DATA/AppData/MULTI-IA-AETHAS38/RAG/Media" os.makedirs(dossier_media, exist_ok=True) # --- MIDDLEWARE DE SÉCURITÉ --- class SecurityMiddleware(BaseHTTPMiddleware): async def dispatch(self, request, call_next): ip = request.headers.get("X-Forwarded-For", request.client.host).split(",")[0].strip() utilisateur = request.cookies.get("aethas_user", "visiteur") # EXCLUSION DE /Media POUR NE PAS BLOQUER L'IMAGE if not request.url.path.startswith(("/Logo", "/login", "/Media")): if verifier_et_bloquer_vpn(ip, utilisateur): return HTMLResponse("
VPN ou Proxy strictement interdit.
", status_code=403) # Exclusion stricte du spam de logs (Silence pour /ping et /favicon) if request.url.path not in ["/ping", "/favicon.ico"]: journaliser_ip(ip, f"Accès à {request.url.path}") return await call_next(request) nettoyer_vieilles_discussions() app, rt = fast_app( hdrs=get_theme_hdrs(), secret_key="super_secret_aethas", middleware=[Middleware(SecurityMiddleware)] ) app.mount("/Logo", StaticFiles(directory="Logo"), name="Logo") # (J'ai supprimé l'ancien montage /Media capricieux de Docker) # --- ROUTE DÉDIÉE POUR L'AFFICHAGE ET TÉLÉCHARGEMENT DES MÉDIAS --- # --- ROUTE DÉDIÉE AVEC ÉCRAN DE DIAGNOSTIC --- @rt('/Media/{fname}') def get(fname: str): chemin = os.path.join(dossier_media, fname) if os.path.exists(chemin): return FileResponse(chemin) # Si le fichier est introuvable, on force l'affichage de ce que Python voit réellement try: fichiers = os.listdir(dossier_media) except Exception as e: fichiers = f"Erreur de lecture du dossier : {e}" return HTMLResponse(f"""Fichier demandé : {fname}
Chemin complet cherché par Python : {chemin}
Contenu physique du dossier tel que vu par le conteneur :
{fichiers}