Files
WGSecure/Makefile
T
2026-08-31 11:16:04 +02:00

253 lines
12 KiB
Makefile

## ──────────────────────────────────────────────
## WGSecure (WGS) — Makefile
## Compilation Linux & Windows via PyInstaller
## ──────────────────────────────────────────────
APP := wgsecure
VERSION := 0.4.1
VENV := .venv
PYTHON := $(VENV)/bin/python3
PIP := $(VENV)/bin/pip
SRC := main.py
DIST := dist
BUILD := build
ICON := /tmp/wgsecure_icon_build.png
# Options PyInstaller communes aux deux plateformes
PI_OPTS := \
--noconfirm \
--clean \
--name $(APP) \
--hidden-import pyotp \
--hidden-import qrcode \
--hidden-import qrcode.image.pil \
--hidden-import PIL \
--hidden-import PIL.Image \
--hidden-import cryptography \
--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 setup-sudoers check-privileges clean clean-all help venv
# ── Cible par défaut ────────────────────────────────────────────────────────
all: linux
# ── Environnement virtuel ────────────────────────────────────────────────────
# Le venv est reconstruit si la version de Python du système a changé : un venv
# créé pour python3.13 pointe vers .venv/lib/python3.13/site-packages, que
# python3.14 n'ouvre pas. L'interpréteur démarrait alors sans aucune de ses
# dépendances (« No module named PyQt6 ») sans que make ne le remarque.
venv:
@if [ -x $(PYTHON) ] && \
[ "$$($(PYTHON) -c 'import sys;print("%d.%d"%sys.version_info[:2])' 2>/dev/null)" \
= "$$(python3 -c 'import sys;print("%d.%d"%sys.version_info[:2])')" ] && \
$(PYTHON) -c 'import PyQt6' >/dev/null 2>&1; then \
echo " ✅ Environnement virtuel valide ($(VENV))"; \
else \
echo " ♻️ (Re)création de l'environnement virtuel $(VENV)…"; \
rm -rf $(VENV); \
python3 -m venv $(VENV); \
$(PIP) install --upgrade pip --quiet; \
$(PIP) install -r requirements.txt --quiet; \
fi
# ── Génération de l'icône PNG (utilisée par PyInstaller) ────────────────────
icon:
@$(PYTHON) -c "\
import sys; sys.path.insert(0,'.');\
from PyQt6.QtWidgets import QApplication; app=QApplication(sys.argv);\
from app.ui.icons import icon_app;\
pix=icon_app().pixmap(256,256); pix.save('$(ICON)','PNG');\
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: install icon
@echo ""
@echo " 🐧 Compilation Linux (PyInstaller onefile)…"
@echo ""
$(PYTHON) -m PyInstaller $(PI_OPTS) \
--onefile \
--icon=$(ICON) \
$(SRC)
@echo ""
@echo " Binaire Linux $(DIST)/$(APP)"
@echo ""
# ── Binaire Windows (via Wine + Python Windows) ──────────────────────────────
windows: icon
@echo ""
@echo " 🪟 Compilation Windows (Wine + PyInstaller)…"
@echo ""
@which wine > /dev/null 2>&1 \
|| (echo " Wine non installé sudo apt install wine"; exit 1)
@wine $(WINE_PYTHON) -m PyInstaller $(PI_OPTS) \
--onefile \
--windowed \
--icon=$(ICON) \
$(SRC) \
|| (echo ""; \
echo " ❌ Échec : Python Windows introuvable dans Wine."; \
echo " → Installez-le avec : make setup-wine"; \
echo ""; exit 1)
@echo ""
@echo " ✅ Binaire Windows → $(DIST)/$(APP).exe"
@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 $(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
@mv $(DIST)/$(APP) $(DIST)/$(APP)-$(VERSION)-linux-x86_64
@echo " 📦 Release → $(DIST)/$(APP)-$(VERSION)-linux-x86_64"
# ── Installation GNOME (utilisateur local, sans sudo) ────────────────────────
INSTALL_BIN := $(HOME)/.local/bin
INSTALL_ICON := $(HOME)/.local/share/icons/hicolor/256x256/apps
INSTALL_APPS := $(HOME)/.local/share/applications
install-gnome: linux
@echo ""
@echo " 🐧 Installation de WGSecure pour GNOME…"
@mkdir -p $(INSTALL_BIN) $(INSTALL_ICON) $(INSTALL_APPS)
@cp $(DIST)/$(APP) $(INSTALL_BIN)/$(APP)
@chmod +x $(INSTALL_BIN)/$(APP)
@echo " ✅ Binaire → $(INSTALL_BIN)/$(APP)"
@cp $(ICON) $(INSTALL_ICON)/$(APP).png
@echo " ✅ Icône → $(INSTALL_ICON)/$(APP).png"
@printf '[Desktop Entry]\nType=Application\nName=WGSecure\nComment=WireGuard GUI avec MFA TOTP\nExec=%s\nIcon=%s\nCategories=Network;Security;\nStartupWMClass=wgsecure\nTerminal=false\n' \
"$(INSTALL_BIN)/$(APP)" "$(APP)" \
> $(INSTALL_APPS)/$(APP).desktop
@echo " ✅ Lanceur → $(INSTALL_APPS)/$(APP).desktop"
@gtk-update-icon-cache -f -t $(HOME)/.local/share/icons/hicolor 2>/dev/null || true
@update-desktop-database $(INSTALL_APPS) 2>/dev/null || true
@echo ""
@echo " 🎉 Installation terminée. WGSecure est disponible dans le menu GNOME."
@echo ""
uninstall-gnome:
@echo " 🗑️ Désinstallation de WGSecure…"
@rm -f $(INSTALL_BIN)/$(APP)
@rm -f $(INSTALL_ICON)/$(APP).png
@rm -f $(INSTALL_APPS)/$(APP).desktop
@gtk-update-icon-cache -f -t $(HOME)/.local/share/icons/hicolor 2>/dev/null || true
@update-desktop-database $(INSTALL_APPS) 2>/dev/null || true
@echo " ✅ WGSecure désinstallé"
# ── Dépendances Python ────────────────────────────────────────────────────────
install: venv
$(PIP) install -r requirements.txt
$(PIP) install pyinstaller
@echo " ✅ Dépendances installées dans $(VENV)"
# ── Diagnostic des droits ────────────────────────────────────────────────────
check-privileges:
@echo ""
@echo " 🔐 Droits requis par WGSecure :"
@$(PYTHON) -c "\
import sys; sys.path.insert(0, '.'); \
from app.utils.platform_utils import privilege_report; \
rows = privilege_report(); \
print(' (exécution en root : aucun droit à configurer)') if not rows else None; \
[print(' ' + ('✅' if ok else '⚠️ ') + ' ' + name.ljust(12) + ('sans mot de passe' if ok else 'dialogue polkit à chaque appel').ljust(32) + '— ' + role) for name, ok, role in rows]; \
print() if not rows else print(chr(10) + ' ⚠️ → lancez make setup-sudoers pour supprimer les dialogues.' if any(not ok for _, ok, _ in rows) else chr(10) + ' ✅ Tout est configuré.')"
@echo ""
# ── Droits sudo wg-quick sans dialogue de mot de passe ───────────────────────
setup-sudoers:
@echo ""
@echo " 🔧 Configuration sudoers (wg-quick + nettoyage réseau, sans mot de passe)…"
@$(PYTHON) -c "\
import os, subprocess, tempfile, shutil; \
user = os.environ.get('USER', os.path.basename(os.path.expanduser('~'))); \
w = lambda n: shutil.which(n) or ''; \
cmds = [c for c in ( \
w('wg-quick'), \
w('wg'), \
w('ip') + ' link delete dev *' if w('ip') else '', \
w('resolvconf') + ' -d *' if w('resolvconf') else '', \
w('resolvectl') + ' revert *' if w('resolvectl') else '', \
w('install') + ' -D -m 600 -o root -g root * /etc/wireguard/*' if w('install') else '', \
) if c]; \
rules = ''.join(user + ' ALL=(ALL) NOPASSWD: ' + c + chr(10) for c in cmds); \
fd, tmp = tempfile.mkstemp(prefix='wgsecure_sudoers_', dir=os.path.expanduser('~')); \
os.write(fd, rules.encode()); os.close(fd); os.chmod(tmp, 0o600); \
chk = subprocess.run(['visudo', '-cqf', tmp], capture_output=True); \
ok = chk.returncode == 0; \
r = subprocess.run(['pkexec', 'bash', '-c', 'install -m 440 -o root -g root ' + tmp + ' /etc/sudoers.d/wgsecure']) if ok else None; \
os.unlink(tmp); \
print(' ❌ Règles sudoers invalides, rien installé : ' + chk.stderr.decode().strip()) if not ok else \
print(' ✅ /etc/sudoers.d/wgsecure configuré — plus de dialogue admin.' if r.returncode == 0 else ' ❌ Échec.')"
@echo ""
# ── Réinitialisation du mot de passe administrateur ──────────────────────────
reset-password:
@echo ""
@echo " ⚠️ Réinitialisation du mot de passe administrateur WGSecure…"
@$(PYTHON) -c "\
import sys; sys.path.insert(0,'.');\
from app.core.config import Config;\
cfg = Config();\
cfg.set_admin_password('');\
print(' ✅ Mot de passe supprimé — accès admin sans restriction au prochain démarrage.')"
@echo ""
# ── Lancer l'application ─────────────────────────────────────────────────────
run: venv
DISPLAY=:0 $(PYTHON) $(SRC)
run-admin: venv
DISPLAY=:0 $(PYTHON) $(SRC) --admin
# ── Nettoyage ────────────────────────────────────────────────────────────────
clean:
@echo " 🧹 Nettoyage…"
@rm -rf $(BUILD) $(DIST) *.spec
@find . -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null; true
@find . -name "*.pyc" -delete 2>/dev/null; true
@echo " Artefacts supprimés"
clean-all: clean
@rm -rf $(VENV)
@echo " Venv supprimé"
# ── Aide ─────────────────────────────────────────────────────────────────────
help:
@echo ""
@echo " ╔══════════════════════════════════════════════╗"
@echo " 🛡️ WGSecure v$(VERSION) Makefile "
@echo " ╠══════════════════════════════════════════════╣"
@echo " make install Installe les dépendances "
@echo " make linux Binaire Linux (onefile) "
@echo " make windows Binaire Windows (Wine) "
@echo " make release Linux + nommage release "
@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 "
@echo " make clean Supprime les artefacts "
@echo " ╚══════════════════════════════════════════════╝"
@echo ""