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
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
"""Historique des sessions de connexion WGSecure."""
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
from app.utils.platform_utils import get_config_dir
|
||||
|
||||
_FILE = "sessions.json"
|
||||
_MAX = 200
|
||||
|
||||
|
||||
def _path() -> str:
|
||||
return os.path.join(get_config_dir(), _FILE)
|
||||
|
||||
|
||||
def start_session(server: str, profile: str) -> int:
|
||||
"""Démarre une nouvelle session, retourne son id."""
|
||||
sid = int(datetime.now().timestamp())
|
||||
sessions = _load()
|
||||
sessions.append({
|
||||
"id": sid,
|
||||
"start": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"end": None,
|
||||
"duration": None,
|
||||
"server": server,
|
||||
"profile": profile,
|
||||
"rx": 0,
|
||||
"tx": 0,
|
||||
})
|
||||
_save(sessions)
|
||||
return sid
|
||||
|
||||
|
||||
def end_session(sid: int, rx: int = 0, tx: int = 0) -> None:
|
||||
sessions = _load()
|
||||
for s in sessions:
|
||||
if s.get("id") == sid:
|
||||
start_dt = datetime.strptime(s["start"], "%Y-%m-%d %H:%M:%S")
|
||||
secs = int((datetime.now() - start_dt).total_seconds())
|
||||
s["end"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
s["duration"] = secs
|
||||
s["rx"] = rx
|
||||
s["tx"] = tx
|
||||
break
|
||||
_save(sessions)
|
||||
|
||||
|
||||
def get_sessions(n: int = 50) -> list[dict]:
|
||||
return list(reversed(_load()[-n:]))
|
||||
|
||||
|
||||
def clear() -> None:
|
||||
_save([])
|
||||
|
||||
|
||||
def fmt_duration(secs: int | None) -> str:
|
||||
if secs is None:
|
||||
return "—"
|
||||
h, r = divmod(int(secs), 3600)
|
||||
m, s = divmod(r, 60)
|
||||
if h:
|
||||
return f"{h}h {m:02d}m"
|
||||
if m:
|
||||
return f"{m}m {s:02d}s"
|
||||
return f"{s}s"
|
||||
|
||||
|
||||
def fmt_bytes(n: int) -> str:
|
||||
for unit, div in [("GB", 1_073_741_824), ("MB", 1_048_576), ("KB", 1024)]:
|
||||
if n >= div:
|
||||
return f"{n/div:.1f} {unit}"
|
||||
return f"{n} B"
|
||||
|
||||
|
||||
def _load() -> list[dict]:
|
||||
p = _path()
|
||||
if not os.path.exists(p):
|
||||
return []
|
||||
try:
|
||||
with open(p, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
||||
def _save(sessions: list[dict]) -> None:
|
||||
try:
|
||||
with open(_path(), "w", encoding="utf-8") as f:
|
||||
json.dump(sessions[-_MAX:], f, indent=2, ensure_ascii=False)
|
||||
except Exception:
|
||||
pass
|
||||
@@ -0,0 +1,50 @@
|
||||
"""Journal des événements de connexion WGSecure."""
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
from app.utils.platform_utils import get_config_dir
|
||||
|
||||
_FILE = "events.json"
|
||||
_MAX_ENTRIES = 200
|
||||
|
||||
|
||||
def _path() -> str:
|
||||
return os.path.join(get_config_dir(), _FILE)
|
||||
|
||||
|
||||
def log_event(msg: str, kind: str = "info") -> None:
|
||||
"""Ajoute un événement horodaté au journal."""
|
||||
events = _load()
|
||||
events.append({
|
||||
"ts": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"kind": kind, # info | success | error | warning
|
||||
"msg": msg,
|
||||
})
|
||||
_save(events[-_MAX_ENTRIES:])
|
||||
|
||||
|
||||
def get_events(n: int = 50) -> list[dict]:
|
||||
return _load()[-n:]
|
||||
|
||||
|
||||
def clear() -> None:
|
||||
_save([])
|
||||
|
||||
|
||||
def _load() -> list[dict]:
|
||||
p = _path()
|
||||
if not os.path.exists(p):
|
||||
return []
|
||||
try:
|
||||
with open(p, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
||||
def _save(events: list[dict]) -> None:
|
||||
try:
|
||||
with open(_path(), "w", encoding="utf-8") as f:
|
||||
json.dump(events, f, ensure_ascii=False)
|
||||
except Exception:
|
||||
pass
|
||||
@@ -143,6 +143,281 @@ def test_connection(cfg: Config, timeout: int = 5) -> tuple[bool, str]:
|
||||
return False, str(e)
|
||||
|
||||
|
||||
def parse_conf_file(path: str) -> dict | None:
|
||||
"""Parse un fichier .conf WireGuard et retourne les valeurs extraites."""
|
||||
result: dict = {}
|
||||
section = None
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
for raw in f:
|
||||
line = raw.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
if line.startswith("["):
|
||||
section = line.strip("[]").lower()
|
||||
continue
|
||||
if "=" not in line:
|
||||
continue
|
||||
key, val = (x.strip() for x in line.split("=", 1))
|
||||
if section == "interface":
|
||||
if key == "PrivateKey":
|
||||
result["client_private_key"] = val
|
||||
elif key == "Address":
|
||||
result["client_address"] = val.split(",")[0].strip()
|
||||
elif key == "DNS":
|
||||
result["dns"] = val.split(",")[0].strip()
|
||||
elif section == "peer":
|
||||
if key == "PublicKey":
|
||||
result["server_public_key"] = val
|
||||
elif key == "Endpoint" and ":" in val:
|
||||
host, port = val.rsplit(":", 1)
|
||||
result["server_endpoint"] = host.strip("[]")
|
||||
try:
|
||||
result["server_port"] = int(port)
|
||||
except ValueError:
|
||||
pass
|
||||
elif key == "AllowedIPs":
|
||||
result["allowed_ips"] = val
|
||||
elif key == "PersistentKeepalive":
|
||||
try:
|
||||
result["keepalive"] = int(val)
|
||||
except ValueError:
|
||||
pass
|
||||
# Dériver la clé publique depuis la clé privée importée
|
||||
if "client_private_key" in result and "client_public_key" not in result:
|
||||
try:
|
||||
priv_bytes = base64.b64decode(result["client_private_key"])
|
||||
priv = X25519PrivateKey.from_private_bytes(priv_bytes)
|
||||
pub_bytes = priv.public_key().public_bytes_raw()
|
||||
result["client_public_key"] = base64.b64encode(pub_bytes).decode()
|
||||
except Exception:
|
||||
pass
|
||||
return result or None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def export_conf_file(cfg: Config, dest_path: str) -> tuple[bool, str]:
|
||||
"""Exporte la configuration courante vers un fichier .conf."""
|
||||
try:
|
||||
content = build_client_config(cfg)
|
||||
with open(dest_path, "w") as f:
|
||||
f.write(content)
|
||||
if not is_windows():
|
||||
os.chmod(dest_path, 0o600)
|
||||
return True, dest_path
|
||||
except Exception as e:
|
||||
return False, str(e)
|
||||
|
||||
|
||||
def get_interface_bytes(iface: str) -> tuple[int, int] | None:
|
||||
"""Retourne (rx_bytes, tx_bytes) depuis /proc/net/dev (Linux)."""
|
||||
try:
|
||||
with open("/proc/net/dev") as f:
|
||||
for line in f:
|
||||
if iface in line:
|
||||
parts = line.split()
|
||||
return int(parts[1]), int(parts[9])
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def ping_server(host: str, timeout: int = 2) -> int | None:
|
||||
"""Ping ICMP du serveur. Retourne la latence en ms, ou None si inaccessible."""
|
||||
if not host:
|
||||
return None
|
||||
if is_windows():
|
||||
code, out, _ = run_command(
|
||||
["ping", "-n", "1", "-w", str(timeout * 1000), host], timeout + 2
|
||||
)
|
||||
else:
|
||||
code, out, _ = run_command(
|
||||
["ping", "-c", "1", "-W", str(timeout), host], timeout + 2
|
||||
)
|
||||
if code != 0:
|
||||
return None
|
||||
# Parser "time=X.X ms" ou "temps=X.X ms"
|
||||
import re
|
||||
m = re.search(r"[Tt]ime[<=]([\d.]+)\s*ms", out)
|
||||
if m:
|
||||
return int(float(m.group(1)))
|
||||
return None
|
||||
|
||||
|
||||
# ── Kill switch ──────────────────────────────────────────────────────────
|
||||
|
||||
_KS_CHAIN = "WGS_KILLSWITCH"
|
||||
|
||||
|
||||
def enable_kill_switch(cfg: Config) -> tuple[bool, str]:
|
||||
"""Active le kill switch : bloque tout trafic hors du tunnel WireGuard."""
|
||||
if is_windows():
|
||||
return False, "Kill switch non disponible sur Windows (utilisez le pare-feu Windows)"
|
||||
|
||||
iface = cfg.wg.get("interface_name", "wgs0")
|
||||
server = cfg.wg.get("server_endpoint", "")
|
||||
port = str(cfg.wg.get("server_port", 51820))
|
||||
|
||||
# Créer la chaîne dédiée (idempotent)
|
||||
run_privileged(["iptables", "-N", _KS_CHAIN])
|
||||
run_privileged(["iptables", "-F", _KS_CHAIN])
|
||||
|
||||
rules = [
|
||||
["iptables", "-A", _KS_CHAIN, "-o", "lo", "-j", "ACCEPT"],
|
||||
["iptables", "-A", _KS_CHAIN, "-o", iface, "-j", "ACCEPT"],
|
||||
["iptables", "-A", _KS_CHAIN, "-m", "state",
|
||||
"--state", "ESTABLISHED,RELATED", "-j", "ACCEPT"],
|
||||
]
|
||||
if server:
|
||||
rules.append(["iptables", "-A", _KS_CHAIN,
|
||||
"-d", server, "-p", "udp", "--dport", port, "-j", "ACCEPT"])
|
||||
rules.append(["iptables", "-A", _KS_CHAIN, "-j", "REJECT",
|
||||
"--reject-with", "icmp-net-unreachable"])
|
||||
|
||||
for rule in rules:
|
||||
code, _, err = run_privileged(rule)
|
||||
if code != 0:
|
||||
disable_kill_switch(cfg)
|
||||
return False, f"Erreur iptables : {err}"
|
||||
|
||||
# Insérer la chaîne dans OUTPUT (évite les doublons)
|
||||
run_privileged(["iptables", "-D", "OUTPUT", "-j", _KS_CHAIN])
|
||||
code, _, err = run_privileged(["iptables", "-I", "OUTPUT", "-j", _KS_CHAIN])
|
||||
if code != 0:
|
||||
disable_kill_switch(cfg)
|
||||
return False, err
|
||||
|
||||
return True, f"Kill switch activé (interface {iface})"
|
||||
|
||||
|
||||
def disable_kill_switch(cfg: Config) -> tuple[bool, str]:
|
||||
"""Désactive le kill switch."""
|
||||
if is_windows():
|
||||
return True, "N/A"
|
||||
run_privileged(["iptables", "-D", "OUTPUT", "-j", _KS_CHAIN])
|
||||
run_privileged(["iptables", "-F", _KS_CHAIN])
|
||||
run_privileged(["iptables", "-X", _KS_CHAIN])
|
||||
return True, "Kill switch désactivé"
|
||||
|
||||
|
||||
def kill_switch_active() -> bool:
|
||||
if is_windows():
|
||||
return False
|
||||
code, out, _ = run_command(["iptables", "-L", "OUTPUT", "-n"])
|
||||
return _KS_CHAIN in out
|
||||
|
||||
|
||||
# ── Test DNS leak ─────────────────────────────────────────────────────────
|
||||
|
||||
def dns_leak_test(cfg: Config) -> dict:
|
||||
"""
|
||||
Teste si le DNS fuit en dehors du tunnel.
|
||||
Retourne {"status": ok|leak|unknown, "resolvers": [...], "expected": str}
|
||||
"""
|
||||
expected_dns = cfg.wg.get("dns", "")
|
||||
resolvers: list[str] = []
|
||||
|
||||
# 1. Lire /etc/resolv.conf (Linux) ou ipconfig /all (Windows)
|
||||
if not is_windows():
|
||||
try:
|
||||
with open("/etc/resolv.conf") as f:
|
||||
for line in f:
|
||||
if line.startswith("nameserver"):
|
||||
parts = line.split()
|
||||
if len(parts) >= 2:
|
||||
resolvers.append(parts[1])
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
code, out, _ = run_command(["ipconfig", "/all"])
|
||||
if code == 0:
|
||||
import re
|
||||
resolvers = re.findall(r"DNS Servers.*?:(.*?)(?:\n\S|\Z)",
|
||||
out, re.DOTALL)
|
||||
|
||||
# 2. Résoudre un domaine test via dig/nslookup pour voir quel serveur répond
|
||||
probe_ip: str = ""
|
||||
code, out, _ = run_command(["dig", "+short", "+time=3", "whoami.akamai.net"], 6)
|
||||
if code == 0:
|
||||
lines = [l.strip() for l in out.splitlines() if l.strip()]
|
||||
if lines:
|
||||
probe_ip = lines[-1]
|
||||
|
||||
if not resolvers:
|
||||
return {"status": "unknown", "resolvers": [], "expected": expected_dns,
|
||||
"probe_ip": probe_ip}
|
||||
|
||||
# 3. Comparer avec le DNS configuré
|
||||
if expected_dns and any(expected_dns in r for r in resolvers):
|
||||
status = "ok"
|
||||
elif expected_dns:
|
||||
status = "leak"
|
||||
else:
|
||||
status = "unknown"
|
||||
|
||||
return {
|
||||
"status": status,
|
||||
"resolvers": resolvers,
|
||||
"expected": expected_dns,
|
||||
"probe_ip": probe_ip,
|
||||
}
|
||||
|
||||
|
||||
# ── Génération config serveur ─────────────────────────────────────────────
|
||||
|
||||
def generate_server_config(
|
||||
server_port: int = 51820,
|
||||
server_address: str = "10.8.0.1/24",
|
||||
client_address: str = "10.8.0.2/24",
|
||||
client_allowed_ips: str = "10.8.0.2/32",
|
||||
) -> dict:
|
||||
"""
|
||||
Génère une paire complète (server_conf, client_conf) avec de nouvelles clés.
|
||||
Retourne un dict avec server_priv/pub, client_priv/pub, server_conf, client_conf.
|
||||
"""
|
||||
srv_priv, srv_pub = generate_keypair()
|
||||
cli_priv, cli_pub = generate_keypair()
|
||||
psk = generate_preshared_key()
|
||||
|
||||
server_conf = "\n".join([
|
||||
"[Interface]",
|
||||
f"PrivateKey = {srv_priv}",
|
||||
f"Address = {server_address}",
|
||||
f"ListenPort = {server_port}",
|
||||
"PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE",
|
||||
"PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE",
|
||||
"",
|
||||
"# === Peer client ===",
|
||||
"[Peer]",
|
||||
f"PublicKey = {cli_pub}",
|
||||
f"PresharedKey = {psk}",
|
||||
f"AllowedIPs = {client_allowed_ips}",
|
||||
])
|
||||
|
||||
client_conf = "\n".join([
|
||||
"[Interface]",
|
||||
f"PrivateKey = {cli_priv}",
|
||||
f"Address = {client_address}",
|
||||
"DNS = 1.1.1.1",
|
||||
"",
|
||||
"[Peer]",
|
||||
f"PublicKey = {srv_pub}",
|
||||
f"PresharedKey = {psk}",
|
||||
"AllowedIPs = 0.0.0.0/0",
|
||||
"Endpoint = <SERVER_IP>:" + str(server_port),
|
||||
"PersistentKeepalive = 25",
|
||||
])
|
||||
|
||||
return {
|
||||
"server_priv": srv_priv, "server_pub": srv_pub,
|
||||
"client_priv": cli_priv, "client_pub": cli_pub,
|
||||
"psk": psk,
|
||||
"server_conf": server_conf,
|
||||
"client_conf": client_conf,
|
||||
}
|
||||
|
||||
|
||||
def get_status_info(cfg: Config) -> dict:
|
||||
name = cfg.wg.get("interface_name", "wgs0")
|
||||
info = {
|
||||
|
||||
Reference in New Issue
Block a user