This commit is contained in:
tuxgyver
2026-06-29 10:19:16 +02:00
parent 2f9ca6b553
commit ea2e6d772b
5 changed files with 82 additions and 33 deletions
+57 -14
View File
@@ -5,7 +5,9 @@
APP := wgsecure
VERSION := 0.4.0
PYTHON := python3
VENV := .venv
PYTHON := $(VENV)/bin/python3
PIP := $(VENV)/bin/pip
SRC := main.py
DIST := dist
BUILD := build
@@ -25,11 +27,18 @@ PI_OPTS := \
--hidden-import cryptography.hazmat.primitives.asymmetric.x25519 \
--collect-submodules PyQt6
.PHONY: all linux windows release install install-gnome uninstall-gnome run run-admin icon reset-password clean help
.PHONY: all linux windows release install install-gnome uninstall-gnome run run-admin icon reset-password setup-sudoers clean clean-all help venv
# ── Cible par défaut ────────────────────────────────────────────────────────
all: linux
# ── Environnement virtuel ────────────────────────────────────────────────────
venv: $(VENV)/bin/python3
$(VENV)/bin/python3:
python3 -m venv $(VENV)
$(PIP) install --upgrade pip --quiet
# ── Génération de l'icône PNG (utilisée par PyInstaller) ────────────────────
icon:
@$(PYTHON) -c "\
@@ -41,7 +50,7 @@ print(' Icône générée →', '$(ICON)')" 2>/dev/null
@test -f $(ICON) || (echo " Génération icône échouée"; exit 1)
# ── Binaire Linux ────────────────────────────────────────────────────────────
linux: icon
linux: install icon
@echo ""
@echo " 🐧 Compilation Linux (PyInstaller onefile)"
@echo ""
@@ -60,7 +69,7 @@ windows: icon
@echo ""
@which wine > /dev/null 2>&1 \
|| (echo " Wine non installé sudo apt install wine"; exit 1)
@wine python -m PyInstaller $(PI_OPTS) \
@wine $(WINE_PYTHON) -m PyInstaller $(PI_OPTS) \
--onefile \
--windowed \
--icon=$(ICON) \
@@ -74,11 +83,25 @@ windows: icon
@echo ""
# ── Installation de Python dans Wine ─────────────────────────────────────────
WINE_PY_VER := 3.11.9
WINE_PY_URL := https://www.python.org/ftp/python/$(WINE_PY_VER)/python-$(WINE_PY_VER)-amd64.exe
WINE_PY_EXE := /tmp/python-$(WINE_PY_VER)-amd64.exe
WINE_PYTHON := $(HOME)/.wine/drive_c/users/$(USER)/AppData/Local/Programs/Python/Python311/python.exe
setup-wine:
@echo " 📦 Installation Python + pip dans Wine…"
winetricks python3
wine pip install -r requirements.txt
wine pip install pyinstaller
@echo " 📦 Installation Python $(WINE_PY_VER) Windows dans Wine…"
@which wine > /dev/null 2>&1 \
|| (echo " ❌ wine non installé → sudo apt install wine"; exit 1)
@test -f $(WINE_PY_EXE) \
|| (echo " ⬇️ Téléchargement Python Windows…" \
&& curl -L -o $(WINE_PY_EXE) $(WINE_PY_URL))
@echo " 🔧 Installation silencieuse…"
wine $(WINE_PY_EXE) /quiet InstallAllUsers=0 PrependPath=1
@echo " 📦 Installation des dépendances…"
wine $(WINE_PYTHON) -m pip install --upgrade pip
wine $(WINE_PYTHON) -m pip install -r requirements.txt
wine $(WINE_PYTHON) -m pip install pyinstaller
@echo " ✅ Python Windows prêt dans Wine"
# ── Release (Linux renommé avec version) ─────────────────────────────────────
release: clean linux
@@ -119,10 +142,25 @@ uninstall-gnome:
@echo " ✅ WGSecure désinstallé"
# ── Dépendances Python ────────────────────────────────────────────────────────
install:
$(PYTHON) -m pip install -r requirements.txt
$(PYTHON) -m pip install pyinstaller
@echo " ✅ Dépendances installées"
install: venv
$(PIP) install -r requirements.txt
$(PIP) install pyinstaller
@echo " ✅ Dépendances installées dans $(VENV)"
# ── Droits sudo wg-quick sans dialogue de mot de passe ───────────────────────
setup-sudoers:
@echo ""
@echo " 🔧 Configuration sudoers pour wg-quick (sans mot de passe)…"
@$(PYTHON) -c "\
import os, subprocess; \
user = os.environ.get('USER', os.path.basename(os.path.expanduser('~'))); \
rule = user + ' ALL=(ALL) NOPASSWD: /usr/bin/wg-quick\n'; \
tmp = '/tmp/wgsecure_sudoers_tmp'; \
open(tmp, 'w').write(rule); \
r = subprocess.run(['pkexec', 'bash', '-c', 'cp ' + tmp + ' /etc/sudoers.d/wgsecure && chmod 440 /etc/sudoers.d/wgsecure']); \
os.unlink(tmp); \
print(' ✅ /etc/sudoers.d/wgsecure configuré — WGSecure n\\'a plus besoin de dialogue admin.' if r.returncode == 0 else ' ❌ Échec. Exécutez manuellement : sudo bash -c \"echo ' + user + ' ALL=(ALL) NOPASSWD: /usr/bin/wg-quick > /etc/sudoers.d/wgsecure && chmod 440 /etc/sudoers.d/wgsecure\"')"
@echo ""
# ── Réinitialisation du mot de passe administrateur ──────────────────────────
reset-password:
@@ -137,10 +175,10 @@ print(' ✅ Mot de passe supprimé — accès admin sans restriction au procha
@echo ""
# ── Lancer l'application ─────────────────────────────────────────────────────
run:
run: venv
DISPLAY=:0 $(PYTHON) $(SRC)
run-admin:
run-admin: venv
DISPLAY=:0 $(PYTHON) $(SRC) --admin
# ── Nettoyage ────────────────────────────────────────────────────────────────
@@ -151,6 +189,10 @@ clean:
@find . -name "*.pyc" -delete 2>/dev/null; true
@echo " Artefacts supprimés"
clean-all: clean
@rm -rf $(VENV)
@echo " Venv supprimé"
# ── Aide ─────────────────────────────────────────────────────────────────────
help:
@echo ""
@@ -164,6 +206,7 @@ help:
@echo " make setup-wine Python Windows dans Wine "
@echo " make install-gnome Installe dans GNOME "
@echo " make uninstall-gnome Désinstalle de GNOME "
@echo " make setup-sudoers wg-quick sans sudo "
@echo " make reset-password Supprime le MDP admin "
@echo " make run Lance l'application "
@echo " make run-admin Lance en mode admin "
+1 -1
View File
@@ -19,7 +19,7 @@ _WG_DEFAULT: dict[str, Any] = {
"client_public_key": "",
"client_address": "10.8.0.2/24",
"dns": "1.1.1.1",
"allowed_ips": "0.0.0.0/0",
"allowed_ips": "10.8.0.0/24",
"keepalive": 25,
}
+4 -18
View File
@@ -48,11 +48,7 @@ def build_client_config(cfg: Config) -> str:
def get_client_config_path(cfg: Config) -> str:
name = cfg.wg.get("interface_name", "wgs0")
if is_windows():
config_dir = get_config_dir()
else:
config_dir = get_wg_config_dir()
return os.path.join(config_dir, f"{name}.conf")
return os.path.join(get_config_dir(), f"{name}.conf")
def write_client_config(cfg: Config) -> tuple[bool, str]:
@@ -65,18 +61,8 @@ def write_client_config(cfg: Config) -> tuple[bool, str]:
if not is_windows():
os.chmod(path, 0o600)
return True, path
except PermissionError:
# Écriture via sudo sur Linux
config_dir_path = get_config_dir()
tmp = os.path.join(config_dir_path, "wgs_tmp.conf")
with open(tmp, "w") as f:
f.write(content)
code, _, err = run_privileged(["cp", tmp, path])
os.unlink(tmp)
if code == 0:
run_privileged(["chmod", "600", path])
return True, path
return False, err
except Exception as e:
return False, str(e)
def is_connected(cfg: Config) -> bool:
@@ -341,7 +327,7 @@ def generate_server_config(
"[Peer]",
f"PublicKey = {srv_pub}",
f"PresharedKey = {psk}",
"AllowedIPs = 0.0.0.0/0",
"AllowedIPs = 10.8.0.0/24",
"Endpoint = <SERVER_IP>:" + str(server_port),
"PersistentKeepalive = 25",
])
+10
View File
@@ -605,4 +605,14 @@ class MainWindow(QMainWindow):
event.ignore()
self.hide()
else:
self._status_timer.stop()
self._clock_timer.stop()
self._bw_timer.stop()
self._ping_timer.stop()
self._reconnect_timer.stop()
try:
if wg_core.is_connected(self._cfg):
wg_core.disconnect(self._cfg)
except Exception:
pass
event.accept()
+10
View File
@@ -108,4 +108,14 @@ class SystemTray(QSystemTrayIcon):
def _quit(self):
self._poll.stop()
try:
if wg_core.is_connected(self._cfg):
wg_core.disconnect(self._cfg)
except Exception:
pass
self._win._status_timer.stop()
self._win._clock_timer.stop()
self._win._bw_timer.stop()
self._win._ping_timer.stop()
self._win._reconnect_timer.stop()
QApplication.quit()