Files
WGSecure/app/core/config.py
T
2026-06-01 22:31:22 +02:00

133 lines
3.9 KiB
Python

import json
import os
import hashlib
import secrets
from typing import Any
from app.utils.platform_utils import get_config_dir
_CONFIG_FILE = "config.json"
_DEFAULT: dict[str, Any] = {
"version": "0.1.0",
"admin_password_hash": "",
"admin_salt": "",
"mfa_enabled": False,
"mfa_secret": "",
"wg": {
"interface_name": "wgs0",
"server_endpoint": "",
"server_port": 51820,
"server_public_key": "",
"client_private_key": "",
"client_public_key": "",
"client_address": "10.8.0.2/24",
"dns": "1.1.1.1",
"allowed_ips": "0.0.0.0/0",
"keepalive": 25,
},
"ui": {
"minimize_to_tray": True,
"autostart": False,
"theme": "auto",
},
}
class Config:
def __init__(self):
self._path = os.path.join(get_config_dir(), _CONFIG_FILE)
self._data: dict[str, Any] = {}
self.load()
def load(self):
if os.path.exists(self._path):
try:
with open(self._path, "r", encoding="utf-8") as f:
saved = json.load(f)
self._data = self._merge(_DEFAULT, saved)
except Exception:
self._data = dict(_DEFAULT)
else:
self._data = dict(_DEFAULT)
def save(self):
os.makedirs(os.path.dirname(self._path), exist_ok=True)
with open(self._path, "w", encoding="utf-8") as f:
json.dump(self._data, f, indent=2, ensure_ascii=False)
def _merge(self, base: dict, override: dict) -> dict:
result = dict(base)
for k, v in override.items():
if k in result and isinstance(result[k], dict) and isinstance(v, dict):
result[k] = self._merge(result[k], v)
else:
result[k] = v
return result
def get(self, *keys: str, default=None) -> Any:
node = self._data
for k in keys:
if not isinstance(node, dict) or k not in node:
return default
node = node[k]
return node
def set(self, *keys_and_value) -> None:
*keys, value = keys_and_value
node = self._data
for k in keys[:-1]:
node = node.setdefault(k, {})
node[keys[-1]] = value
# -- Admin password --
def set_admin_password(self, password: str):
if not password:
# Mot de passe vide = suppression de la protection
self._data["admin_salt"] = ""
self._data["admin_password_hash"] = ""
else:
salt = secrets.token_hex(16)
hashed = hashlib.sha256((salt + password).encode()).hexdigest()
self._data["admin_salt"] = salt
self._data["admin_password_hash"] = hashed
self.save()
def check_admin_password(self, password: str) -> bool:
salt = self._data.get("admin_salt", "")
stored = self._data.get("admin_password_hash", "")
if not stored:
return True # Pas encore de mot de passe configuré
candidate = hashlib.sha256((salt + password).encode()).hexdigest()
return secrets.compare_digest(candidate, stored)
def has_admin_password(self) -> bool:
return bool(self._data.get("admin_password_hash", ""))
# -- Propriétés WireGuard --
@property
def wg(self) -> dict:
return self._data["wg"]
@property
def mfa_enabled(self) -> bool:
return bool(self._data.get("mfa_enabled", False))
@mfa_enabled.setter
def mfa_enabled(self, value: bool):
self._data["mfa_enabled"] = value
@property
def mfa_secret(self) -> str:
return self._data.get("mfa_secret", "")
@mfa_secret.setter
def mfa_secret(self, value: str):
self._data["mfa_secret"] = value
@property
def configured(self) -> bool:
wg = self._data["wg"]
return bool(wg.get("server_endpoint") and wg.get("client_private_key"))