Update
This commit is contained in:
+121
-23
@@ -2,33 +2,40 @@ import json
|
||||
import os
|
||||
import hashlib
|
||||
import secrets
|
||||
from copy import deepcopy
|
||||
from typing import Any
|
||||
from app.utils.platform_utils import get_config_dir
|
||||
|
||||
|
||||
_CONFIG_FILE = "config.json"
|
||||
|
||||
_WG_DEFAULT: dict[str, Any] = {
|
||||
"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,
|
||||
}
|
||||
|
||||
_DEFAULT: dict[str, Any] = {
|
||||
"version": "0.1.0",
|
||||
"version": "0.4.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,
|
||||
},
|
||||
"active_profile": "Défaut",
|
||||
"profiles": {},
|
||||
"wg": deepcopy(_WG_DEFAULT),
|
||||
"ui": {
|
||||
"minimize_to_tray": True,
|
||||
"autostart": False,
|
||||
"theme": "auto",
|
||||
"auto_reconnect": False,
|
||||
"reconnect_interval": 30,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -46,9 +53,9 @@ class Config:
|
||||
saved = json.load(f)
|
||||
self._data = self._merge(_DEFAULT, saved)
|
||||
except Exception:
|
||||
self._data = dict(_DEFAULT)
|
||||
self._data = deepcopy(_DEFAULT)
|
||||
else:
|
||||
self._data = dict(_DEFAULT)
|
||||
self._data = deepcopy(_DEFAULT)
|
||||
|
||||
def save(self):
|
||||
os.makedirs(os.path.dirname(self._path), exist_ok=True)
|
||||
@@ -79,11 +86,10 @@ class Config:
|
||||
node = node.setdefault(k, {})
|
||||
node[keys[-1]] = value
|
||||
|
||||
# -- Admin password --
|
||||
# ── Mot de passe admin ────────────────────────────────────────────────
|
||||
|
||||
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:
|
||||
@@ -97,19 +103,26 @@ class Config:
|
||||
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é
|
||||
return True
|
||||
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 --
|
||||
# ── WireGuard ─────────────────────────────────────────────────────────
|
||||
|
||||
@property
|
||||
def wg(self) -> dict:
|
||||
return self._data["wg"]
|
||||
|
||||
@property
|
||||
def configured(self) -> bool:
|
||||
wg = self._data["wg"]
|
||||
return bool(wg.get("server_endpoint") and wg.get("client_private_key"))
|
||||
|
||||
# ── MFA ───────────────────────────────────────────────────────────────
|
||||
|
||||
@property
|
||||
def mfa_enabled(self) -> bool:
|
||||
return bool(self._data.get("mfa_enabled", False))
|
||||
@@ -126,7 +139,92 @@ class Config:
|
||||
def mfa_secret(self, value: str):
|
||||
self._data["mfa_secret"] = value
|
||||
|
||||
# ── Multi-profils ─────────────────────────────────────────────────────
|
||||
|
||||
@property
|
||||
def configured(self) -> bool:
|
||||
wg = self._data["wg"]
|
||||
return bool(wg.get("server_endpoint") and wg.get("client_private_key"))
|
||||
def active_profile(self) -> str:
|
||||
return self._data.get("active_profile", "Défaut")
|
||||
|
||||
def list_profiles(self) -> list[str]:
|
||||
return list(self._data.get("profiles", {}).keys())
|
||||
|
||||
def save_profile(self, name: str) -> None:
|
||||
"""Sauvegarde la config WireGuard courante sous un nom de profil."""
|
||||
self._data.setdefault("profiles", {})[name] = deepcopy(self._data["wg"])
|
||||
self._data["active_profile"] = name
|
||||
self.save()
|
||||
|
||||
def load_profile(self, name: str) -> bool:
|
||||
"""Charge un profil sauvegardé dans la config active."""
|
||||
profiles = self._data.get("profiles", {})
|
||||
if name not in profiles:
|
||||
return False
|
||||
self._data["wg"] = deepcopy(profiles[name])
|
||||
self._data["active_profile"] = name
|
||||
self.save()
|
||||
return True
|
||||
|
||||
def delete_profile(self, name: str) -> bool:
|
||||
profiles = self._data.get("profiles", {})
|
||||
if name not in profiles:
|
||||
return False
|
||||
del profiles[name]
|
||||
if self._data.get("active_profile") == name:
|
||||
self._data["active_profile"] = "Défaut"
|
||||
self.save()
|
||||
return True
|
||||
|
||||
def rename_profile(self, old: str, new: str) -> bool:
|
||||
profiles = self._data.get("profiles", {})
|
||||
if old not in profiles or new in profiles:
|
||||
return False
|
||||
profiles[new] = profiles.pop(old)
|
||||
if self._data.get("active_profile") == old:
|
||||
self._data["active_profile"] = new
|
||||
self.save()
|
||||
return True
|
||||
|
||||
# ── Autostart ─────────────────────────────────────────────────────────
|
||||
|
||||
def set_autostart(self, enabled: bool) -> None:
|
||||
self._data["ui"]["autostart"] = enabled
|
||||
self._apply_autostart(enabled)
|
||||
self.save()
|
||||
|
||||
def _apply_autostart(self, enabled: bool) -> None:
|
||||
import sys
|
||||
from app.utils.platform_utils import is_linux, is_windows
|
||||
script = os.path.abspath(os.path.join(
|
||||
os.path.dirname(__file__), "..", "..", "main.py"
|
||||
))
|
||||
if is_linux():
|
||||
autostart_dir = os.path.expanduser("~/.config/autostart")
|
||||
desktop = os.path.join(autostart_dir, "wgsecure.desktop")
|
||||
if enabled:
|
||||
os.makedirs(autostart_dir, exist_ok=True)
|
||||
content = (
|
||||
"[Desktop Entry]\nType=Application\nName=WGSecure\n"
|
||||
f"Exec=python3 {script}\nIcon=wgsecure\n"
|
||||
"Hidden=false\nX-GNOME-Autostart-enabled=true\n"
|
||||
)
|
||||
with open(desktop, "w") as f:
|
||||
f.write(content)
|
||||
else:
|
||||
try:
|
||||
os.unlink(desktop)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
elif is_windows():
|
||||
import winreg
|
||||
key = r"Software\Microsoft\Windows\CurrentVersion\Run"
|
||||
try:
|
||||
reg = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key, 0,
|
||||
winreg.KEY_SET_VALUE)
|
||||
if enabled:
|
||||
winreg.SetValueEx(reg, "WGSecure", 0, winreg.REG_SZ,
|
||||
f'pythonw "{script}"')
|
||||
else:
|
||||
winreg.DeleteValue(reg, "WGSecure")
|
||||
winreg.CloseKey(reg)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user