"""Mode admin pour l'application Pseudonymisation (D-13). Le mode admin déverrouille des fonctionnalités cachées au bêta-testeur : - VLM Ollama (D-11) — détection visuelle par LLM local - Paramètres avancés sensibles (stopwords personnalisés, force_terms, etc.) - Profils techniques (regex_overrides) Activation possible (par ordre de priorité) : 1. Variable d'environnement : `ANON_ADMIN=1` 2. Fichier `.admin` à la racine de l'application (à côté de l'EXE / du module) Pour désactiver : supprimer le fichier `.admin` et la variable d'env. Aucun mot de passe pour la v1.0 — c'est juste un verrou "interdit aux distraits" qui empêche le bêta-testeur ou un utilisateur final de tomber sur des options qui pourraient leak des données (envoi à Ollama externe, modifications config critique). """ from __future__ import annotations import os from pathlib import Path from typing import Optional _ADMIN_CACHED: Optional[bool] = None def _project_root() -> Path: """Retourne le dossier racine de l'application (compat dev + EXE).""" try: return Path(__file__).parent.resolve() except NameError: return Path.cwd() def is_admin(force_refresh: bool = False) -> bool: """Retourne True si le mode admin est actif. Résultat caché en module (les vérifications coûtent presque rien mais `is_admin()` peut être appelé dans des boucles serrées). `force_refresh` permet de re-vérifier après un changement de configuration. """ global _ADMIN_CACHED if _ADMIN_CACHED is not None and not force_refresh: return _ADMIN_CACHED # Priorité 1 : variable d'env env_val = os.environ.get("ANON_ADMIN", "").strip().lower() if env_val in ("1", "true", "yes", "on"): _ADMIN_CACHED = True return True # Priorité 2 : fichier .admin admin_file = _project_root() / ".admin" if admin_file.exists(): _ADMIN_CACHED = True return True _ADMIN_CACHED = False return False def admin_required(feature_name: str = "fonctionnalité") -> None: """Lève RuntimeError si pas admin. À utiliser comme garde au début d'une méthode sensible. """ if not is_admin(): raise RuntimeError( f"Mode admin requis pour {feature_name}. " f"Activez via ANON_ADMIN=1 ou créez le fichier .admin " f"à la racine de l'application." )