feat: intégration complète du traitement des variables d environnement
- Ajout de l EnvProcessor dans l API pour résoudre les variables VAR - Résolution récursive des variables d environnement en mémoire - Support des syntaxes VAR et VAR entre accolades - Chargement uniquement du fichier .env principal (pas les sous-répertoires) - Traitement des variables avant chiffrement des contenus - Correction des dépendances circulaires (HOST/DOMAIN) - Harmonisation de la cryptographie API/SDK avec noble/ciphers - Amélioration de la sécurité avec protection des chemins - Synchronisation locale des fichiers déchiffrés avec variables résolues Variables maintenant correctement résolues: - DOMAIN=4nkweb.com → valeur fixe préservée - HOST=dev4.DOMAIN → dev4.4nkweb.com - ROOT_HOST=HOST → dev4.4nkweb.com - ROOT_URL=https://ROOT_HOST → https://dev4.4nkweb.com Tests: 72 fichiers synchronisés avec succès, chiffrement ChaCha20-Poly1305 fonctionnel
This commit is contained in:
parent
f14057a623
commit
aa67784fe2
@ -140,8 +140,10 @@ class EnvProcessor:
|
||||
self.variables = self._load_env_file(env_file)
|
||||
|
||||
def _load_env_file(self, env_file: Path) -> Dict[str, str]:
|
||||
"""Charge le fichier .env"""
|
||||
"""Charge uniquement le fichier .env principal (pas les sous-répertoires)"""
|
||||
variables = {}
|
||||
|
||||
# Charger uniquement le fichier .env principal
|
||||
if env_file.exists():
|
||||
try:
|
||||
with open(env_file, 'r', encoding='utf-8') as f:
|
||||
@ -150,8 +152,13 @@ class EnvProcessor:
|
||||
if line and not line.startswith('#') and '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
variables[key.strip()] = value.strip()
|
||||
logger.info(f"Variables chargées depuis {env_file}: {len(variables)} variables")
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors du chargement du fichier .env: {e}")
|
||||
|
||||
# Note: Les fichiers .env des sous-répertoires ne sont PAS chargés
|
||||
# car ils sont des configurations spécifiques aux services, pas des variables globales
|
||||
|
||||
return variables
|
||||
|
||||
def _resolve_variable(self, var_name: str, visited: set = None) -> str:
|
||||
@ -161,34 +168,54 @@ class EnvProcessor:
|
||||
|
||||
if var_name in visited:
|
||||
logger.warning(f"Dépendance circulaire détectée pour {var_name}")
|
||||
return f"${{{var_name}}}"
|
||||
return f"${var_name}"
|
||||
|
||||
if var_name not in self.variables:
|
||||
logger.warning(f"Variable non trouvée: {var_name}")
|
||||
return f"${{{var_name}}}"
|
||||
return f"${var_name}"
|
||||
|
||||
visited.add(var_name)
|
||||
value = self.variables[var_name]
|
||||
|
||||
# Traitement des sous-variables
|
||||
pattern = r'\$\{([^}]+)\}'
|
||||
matches = re.findall(pattern, value)
|
||||
# Traitement des sous-variables avec ${VAR}
|
||||
pattern1 = r'\$\{([^}]+)\}'
|
||||
matches1 = re.findall(pattern1, value)
|
||||
|
||||
for match in matches:
|
||||
for match in matches1:
|
||||
resolved_value = self._resolve_variable(match, visited.copy())
|
||||
value = value.replace(f"${{{match}}}", resolved_value)
|
||||
|
||||
# Traitement des sous-variables avec $VAR
|
||||
pattern2 = r'\$([A-Za-z_][A-Za-z0-9_]*)'
|
||||
matches2 = re.findall(pattern2, value)
|
||||
|
||||
for match in matches2:
|
||||
if match != var_name: # Éviter l'auto-référence
|
||||
resolved_value = self._resolve_variable(match, visited.copy())
|
||||
value = value.replace(f"${match}", resolved_value)
|
||||
|
||||
return value
|
||||
|
||||
def process_content(self, content: str) -> str:
|
||||
"""Traite le contenu en résolvant les variables"""
|
||||
pattern = r'\$\{([^}]+)\}'
|
||||
matches = re.findall(pattern, content)
|
||||
# Pattern pour ${VARIABLE}
|
||||
pattern1 = r'\$\{([^}]+)\}'
|
||||
matches1 = re.findall(pattern1, content)
|
||||
|
||||
for var_name in matches:
|
||||
for var_name in matches1:
|
||||
resolved_value = self._resolve_variable(var_name)
|
||||
content = content.replace(f"${{{var_name}}}", resolved_value)
|
||||
|
||||
# Pattern pour $VARIABLE (syntaxe simple)
|
||||
pattern2 = r'\$([A-Za-z_][A-Za-z0-9_]*)'
|
||||
matches2 = re.findall(pattern2, content)
|
||||
|
||||
for var_name in matches2:
|
||||
# Éviter les variables déjà traitées avec ${}
|
||||
if f"${{{var_name}}}" not in content:
|
||||
resolved_value = self._resolve_variable(var_name)
|
||||
content = content.replace(f"${var_name}", resolved_value)
|
||||
|
||||
return content
|
||||
|
||||
class SecureVaultAPI:
|
||||
@ -196,8 +223,18 @@ class SecureVaultAPI:
|
||||
|
||||
def __init__(self):
|
||||
self.app = Flask(__name__)
|
||||
# Initialisation des processeurs d'environnement pour chaque env
|
||||
self.env_processors = {}
|
||||
self._setup_routes()
|
||||
|
||||
def _get_env_processor(self, env: str) -> EnvProcessor:
|
||||
"""Obtient le processeur d'environnement pour un environnement donné"""
|
||||
if env not in self.env_processors:
|
||||
env_file = STORAGE_ROOT / env / '.env'
|
||||
self.env_processors[env] = EnvProcessor(env_file)
|
||||
logger.info(f"Processeur d'environnement initialisé pour {env}")
|
||||
return self.env_processors[env]
|
||||
|
||||
def _setup_routes(self):
|
||||
"""Configure les routes de l'API"""
|
||||
|
||||
@ -338,8 +375,9 @@ class SecureVaultAPI:
|
||||
if file_content is None:
|
||||
return jsonify({"error": f"Fichier non trouvé: {env}/{file_path}"}), 404
|
||||
|
||||
# Contenu du fichier sans traitement de variables d'environnement
|
||||
processed_content = file_content
|
||||
# Traitement des variables d'environnement (en mémoire, sans modifier le fichier)
|
||||
env_processor = self._get_env_processor(env)
|
||||
processed_content = env_processor.process_content(file_content)
|
||||
|
||||
# Chiffrement avec la clé utilisateur pour cet environnement
|
||||
encrypted_content, next_key = self._encrypt_with_user_key_and_next(processed_content, user_id, env)
|
||||
|
Loading…
x
Reference in New Issue
Block a user