# Changelog — WGSecure (WGS) Toutes les modifications notables de ce projet sont documentées ici. Format basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/). Ce projet suit le [Versionnage Sémantique](https://semver.org/lang/fr/). --- ## [0.13.0] — 2026-09-08 ### Ajouté - **Un thème clair, au choix dans Paramètres → Apparence.** Le thème sombre reste celui par défaut : rien ne change sur les postes déjà installés tant que le réglage n'est pas touché. Le choix est lu au lancement — les feuilles de style sont posées dans les constructeurs des fenêtres, et les repeindre à chaud supposerait de reconstruire celle qui porte l'état du tunnel, ses fils d'exécution et ses minuteries. Le message de confirmation l'annonce plutôt que de laisser croire à un réglage sans effet. - Le module de thème publie désormais deux palettes derrière les mêmes noms. Les cent soixante-dix appels répartis dans l'interface lisent `theme.BG` sans rien savoir du thème actif : ajouter une palette n'a demandé de toucher aucun widget. ### Modifié - **Les couleurs qui vivaient encore hors du module de thème l'ont rejoint.** Le graphe de bande passante peignait son fond en dur — un panneau sombre au milieu d'une page claire — et sept de ses teintes sont maintenant des jetons. Quatre couleurs de survol de la fenêtre principale, recopiées à la main, désignent les jetons de même valeur. - **Le texte posé sur un aplat saturé ne suit plus la couleur de texte ordinaire.** Bouton plein, onglet actif, bandeau, ligne sélectionnée : ils portaient `TEXT`, blanc en thème sombre et presque noir en thème clair, où il aurait disparu sur le fond d'accent. Un jeton distinct le dit, blanc dans les deux thèmes. - Trois variantes d'état des champs et des boutons — lecture seule, désactivé, flèches de compteur — étaient écrites en dur dans la feuille de style commune sous forme de voiles blancs translucides, c'est-à-dire invisibles sur un fond clair. Elles deviennent des jetons de palette. ### Corrigé - **Deux endroits figeaient le thème au chargement de leur module** et auraient gardé les teintes sombres quel que soit le réglage : la feuille de style de la fenêtre d'historique, construite au niveau du module, et la table état → couleur du diagnostic, évaluée comme attribut de classe. La première devient une fonction, la seconde ne retient que la puce et demande la couleur au thème à l'affichage. - **Le bandeau de titre du panneau d'administration s'affichait blanc sur gris pâle en thème clair.** Il prend le fond en creux de la fenêtre, sur lequel le blanc des bandeaux d'onglets — qui sont, eux, des aplats saturés — ne se voyait pas. --- ## [0.12.1] — 2026-09-08 ### Corrigé - **Sous Windows, l'application n'était jamais relancée après une mise à jour.** Trois choses y concouraient : le service lance l'installeur avec `/VERYSILENT`, l'entrée `[Run]` qui rouvre l'application porte `skipifsilent` et s'en trouve écartée, et `RestartApplications=no` laisse le Restart Manager fermer sans rouvrir. Le service annonçait pourtant que l'application redémarrerait. Lui rendre l'entrée `[Run]` n'aurait rien réglé : l'installeur étant lancé par le service, il tourne en LocalSystem dans la session 0, où l'application se serait ouverte sans bureau visible et avec les privilèges du système. La relance revient donc au service, seul composant capable d'ouvrir un processus dans la session d'un autre, et que l'installeur redémarre une fois les binaires en place. Le jeton est celui de la session console : l'application repart avec les droits de l'utilisateur. - **Le marqueur de relance est posé par l'installeur, non par le service.** Le service ne saurait qu'avoir lancé un installeur, quand celui-ci sait que l'installation a abouti. Il porte de surcroît déjà la correction, si bien que la première mise à jour en bénéficie — un marqueur écrit par l'ancien service ne serait apparu qu'à la deuxième. Il n'est posé qu'en installation silencieuse : une installation lancée à la main rouvre déjà l'application par son entrée `[Run]`. - **L'installeur copiait par-dessus un binaire encore verrouillé.** L'attente censée laisser mourir le service demandait à `RenameFile` de renommer le fichier sur lui-même et tenait l'échec pour un verrou. Elle ne mesurait rien : Windows autorise le renommage de l'image d'un processus vivant — c'est ce qui rend `restartreplace` possible — et `MoveFile` refuse de toute façon une destination existante. La réponse était donc la même quel que soit l'état réel du service. La copie échouait, `restartreplace` reportait le remplacement au redémarrage suivant, et l'installeur s'achevait en annonçant une réussite que rien n'avait accomplie. L'attente porte maintenant sur la disparition du processus, relevée par `tasklist` — dont le nom d'image, contrairement aux libellés d'état de `sc.exe`, n'est pas traduit sur un Windows français. --- ## [0.12.0] — 2026-09-08 ### Ajouté - **Une saisie de code réussie se voit enfin à l'écran.** Le message du serveur partait dans le seul journal, pendant que la fenêtre de saisie se refermait : rien ne distinguait un code accepté d'un code ignoré, et la durée obtenue — précisément ce que l'utilisateur venait de demander — restait invisible. Une confirmation l'annonce désormais avec son échéance et le temps restant. - **Le client vérifie ensuite que le trafic atteint réellement le réseau distant.** Le serveur peut enregistrer l'autorisation sans que la règle de pare-feu s'applique ; le réseau reste alors muet malgré un code accepté, et l'utilisateur ne pouvait que le découvrir seul, plus tard. La vérification observe ce qui passe, là où le sondage se contente de demander au serveur ce qu'il a enregistré. Son verdict rejoint le journal, succès comme échec, en nommant la cible et en renvoyant à l'administrateur. ### Corrigé - **Un refus du serveur pouvait faire lever une exception au lieu de s'afficher.** Contre un serveur antérieur à la v0.3.2, qui exige encore un identifiant que ce poste ne transmet plus, `POST /api/session` répond 422 — et le `detail` d'une erreur de validation FastAPI est une *liste*, non une phrase. Elle atterrissait telle quelle dans le champ `message` de la réponse, que l'interface passe ensuite à Qt : le refus n'était pas montré, il interrompait le traitement de la réponse. Seule une chaîne est désormais retenue comme message, et ce cas précis explique ce qu'il faut faire — mettre le serveur à jour. Un corps JSON qui n'est pas un objet, qui provoquait la même interruption un cran plus tôt, est écarté de même. --- ## [0.11.0] — 2026-09-08 ### Ajouté - **Mise à jour de l'application, servie par le serveur depuis l'intérieur du tunnel.** Les binaires ne peuvent pas venir du dépôt Gitea, qui est privé : un jeton embarqué dans une application distribuée est un jeton donné à tous ses utilisateurs. Ils viennent donc du serveur WGSecure, où le contrôle d'accès existe déjà — l'API n'est joignable que par le tunnel, et on y parvient parce que sa clé WireGuard y est déclarée. Aucun secret n'est embarqué dans le client. - **Un bandeau propose la version disponible ; rien ne s'installe sans un clic.** La vérification est automatique — au montage du tunnel, puis toutes les demi-heures —, le téléchargement attend le bouton. Cette application monte un VPN : une version défaillante qui se propagerait seule couperait l'accès d'un parc entier sans que personne ne l'ait demandé. La croix rouge reporte la proposition pour la session ; elle revient au démarrage suivant. - **Barre de progression** pendant le téléchargement, alimentée depuis le thread qui le mène. Sur une centaine de mégaoctets, l'application paraissait figée et rien ne distinguait une attente d'un échec. - **L'artefact est vérifié contre son empreinte SHA-256 avant d'être mis en place**, et le fichier temporaire est détruit à la moindre anomalie. Le canal est déjà authentifié par WireGuard ; le condensat couvre ce que le chiffrement ne couvre pas — un téléchargement tronqué, un disque plein, un artefact mal publié. - **Sous Windows, l'installation passe par le service**, qui tourne en LocalSystem et écrit dans Program Files sans invite d'élévation. La commande ne prend aucun paramètre : le service lit le manifeste, télécharge et vérifie lui-même. Lui passer un fichier déjà téléchargé aurait donné à tout compte du poste — le canal de communication est ouvert aux utilisateurs interactifs — le moyen de faire exécuter ce qu'il veut avec les privilèges du système. - Nouvelle cible `make publish-updates`, qui dépose artefacts et manifeste sur le serveur. `ANNOUNCE=` annonce les binaires sous un autre numéro, pour exercer la chaîne sans compiler une seconde version. ### Sécurité - **Le service n'obéit plus qu'à un seul compte.** Le premier appelant devient propriétaire et son identifiant est retenu ; ensuite, seuls ce compte et les administrateurs sont servis. Le canal étant ouvert à tout utilisateur interactif, n'importe quel compte du poste pouvait jusqu'ici couper le tunnel d'un autre, ou poser une règle de résolution DNS valable pour la machine entière, sans être administrateur. - **Le contenu d'un fichier `.conf` installé par le service est vérifié**, et non plus son seul chemin : les directives exécutables y sont refusées, la taille est bornée, la structure contrôlée. Elles auraient fait exécuter des commandes avec les privilèges du système. ### Corrigé - **Le remplacement du binaire échouait sous Linux** (« Fichier texte occupé »). Le téléchargement atterrissait dans `/tmp`, souvent un autre système de fichiers que la destination : la mise en place se faisait alors par copie, donc par écriture dans l'exécutable en cours, ce que le noyau refuse. Le fichier est désormais téléchargé à côté de sa destination et mis en place par renommage, qui ne touche qu'une entrée de répertoire et laisse le programme tourner jusqu'à sa fermeture. L'application propose ensuite de redémarrer, plutôt que de laisser deviner. - **La mise à jour ne s'installait pas sous Windows.** Les deux exécutables à remplacer tournent au moment de la mise à jour, et Windows verrouille l'image d'un processus vivant : l'installeur, lancé de surcroît par le service dont il devait remplacer le binaire, abandonnait en silence. Il ferme maintenant l'application par le gestionnaire de redémarrage, arrête les tunnels et le service avant la copie — en attendant la libération réelle du fichier, l'ordre d'arrêt rendant la main avant la fin de celui-ci — et garde en dernier recours le remplacement au redémarrage. Le service, lui, lance l'installeur détaché sans l'attendre. - **La proposition de mise à jour ne revenait jamais** si le serveur n'était pas joignable à l'instant précis où le tunnel montait — routes non encore posées, quarantaine en cours. La question se repose désormais toutes les demi-heures. - **Le texte du bandeau était illisible** et deux boutons se disputaient l'attention. Un seul bouton vert, et une croix rouge pour reporter. - **Compiler Linux puis Windows produisait des binaires corrompus.** Les deux cibles partageaient le répertoire de travail de PyInstaller, que l'option `--clean` vide au démarrage : lancées à la suite, chacune effaçait les fichiers intermédiaires de l'autre. Un installeur Windows gonflé de 44 Mo et un binaire Linux tronqué, dont l'archive ne se décompressait plus, ont été produits ainsi. Chaque cible a maintenant son propre répertoire. --- ## [0.10.0] — 2026-09-08 ### Supprimé - **L'assistant « configuration serveur + client ».** Il datait d'avant la v0.8.0 et produisait un serveur WireGuard nu — sans API d'authentification, sans quarantaine, sans code à 6 chiffres — c'est-à-dire un modèle incompatible avec le fonctionnement actuel, où le serveur enrôle le compte et fournit le fichier `.conf`. Son bouton « Appliquer le volet client » écrasait de surcroît les clés du client et la clé publique du serveur : sur un poste déjà enrôlé, il rompait le lien avec le serveur, qui déclare l'ancienne clé publique, sans que rien ne l'annonce. - **Le champ Identifiant VPN**, sans emploi depuis que le serveur reconnaît le poste à l'adresse de son tunnel. Un champ qui ne fait rien est pire qu'un champ absent : il laisse croire qu'il compte. Les configurations existantes en sont purgées au chargement, profils compris. ### Modifié - **Le sous-onglet Tunnel passe d'une liste de quinze champs à trois groupes** : l'essentiel — adresse du client, IPs autorisées, DNS —, le split-DNS enfin nommé comme tel, et un repli « Avancé ». Trois champs portaient « DNS » dans la même liste sans que rien ne dise lesquels allaient ensemble. - **Ce qui vient du serveur est replié et verrouillé** : adresse, port et clé publique du serveur rejoignent « Avancé », aux côtés du nom d'interface, de l'URL de l'API, du keepalive et du MTU. Ils décrivent un pair déjà déclaré côté serveur ; les modifier à la main ne produit aucune erreur visible, seulement un handshake qui n'aboutit jamais. - **Le sous-onglet « Fuite DNS » devient « Résolution des noms »** : il faisait trois choses sous un titre qui n'en annonçait qu'une. Son verdict « Statut inconnu » recouvrait trois causes appelant trois gestes différents — tunnel arrêté, aucun DNS déclaré, aucun résolveur système — chacune est désormais nommée avec l'action qui suit. - La pastille de la page « À propos » n'affirme plus rien qu'elle ne sache : elle déduisait « Code d'accès serveur » ou « Aucun code d'accès » de la seule configuration locale, alors qu'un poste sans identifiant pouvait parfaitement être tenu en quarantaine. ### Ajouté - **Nouvelle étape de diagnostic « Serveur DNS du réseau distant »**, qui comble un angle mort : le tunnel monte, le trafic passe, la résolution est au vert, et pas un nom interne ne se résout. Deux causes, l'une et l'autre muettes jusqu'ici. Ou bien le serveur DNS distant n'est couvert par aucune « IP autorisée » et rien ne le route dans le tunnel ; ou bien il l'est, mais son adresse tombe aussi dans une plage que porte une carte du poste — cas d'un réseau distant en 192.168.1.0/24 vu depuis un poste chez lui — et la route locale l'emporte. Ce second cas ne se déduit pas de la configuration : l'étape interroge la route réellement retenue par le noyau, sans émettre le moindre paquet, et propose la route d'hôte qui reprend la main. ### Corrigé - **Le verrouillage des champs issus d'un `.conf` importé ne survivait pas à la fermeture du panneau.** Il existait depuis la v0.8.3, mais le chargement des valeurs le levait sans condition : rouvrir le panneau Administrateur, ou simplement changer de profil, rendait de nouveau éditables — en silence — l'adresse, le port et la clé publique du serveur. L'état est désormais enregistré et suit la configuration chargée, profils compris. - **Le rapport de diagnostic n'occupait qu'une fraction de la largeur disponible.** Chaque étape s'écrivait sur deux lignes, libellé puis détail indenté : le texte tenait sur 224 px quelle que soit la taille de la fenêtre, laissant jusqu'à 79 % de blanc à droite. Il est passé en tableau à deux colonnes, occupe toute la largeur et tient sur 38 % de hauteur en moins. - **La fenêtre du panneau Administrateur était trop courte et les libellés s'y chevauchaient.** Sa hauteur augmente de 15 %, et surtout son plancher passe de 520 à 703 px : la page de test réclame 569 px de contenu incompressible, et toute réduction en deçà écrasait les champs les uns sur les autres. - Deux encarts explicatifs portaient des retours à la ligne écrits à la main, qui figeaient leur largeur : la fenêtre s'élargissait, le texte non. --- ## [0.9.1] — 2026-09-08 ### Modifié - **L'identifiant VPN n'est plus demandé, ni même transmis.** Le serveur reconnaît le poste à l'adresse source de son tunnel, comme il le fait pour l'état de l'accès depuis la v0.8.6 ; il n'y avait aucune raison que l'ouverture, elle, réclame un nom que le serveur possédait déjà. Le champ disparaît de la fenêtre de saisie. Celui du panneau Administrateur reste, désormais purement indicatif. Nécessite la v0.3.2 du serveur, qui accepte les deux formes le temps que les postes soient à jour. - Ce choix resserre aussi la sécurité : sur WireGuard l'adresse source est garantie par le routage par clé — un pair ne peut pas émettre depuis l'adresse d'un autre — alors qu'un identifiant transmis en clair permettait de demander l'ouverture d'un compte depuis n'importe où. Il ferme au passage l'énumération de comptes que la route d'ouverture rendait possible. - **La ligne *Accès distant* distingue « Non géré par le serveur » de « Non vérifié ».** Trois décisions d'interface — proposer ou non la saisie automatique, le libellé de cette ligne, l'aspect du bouton — se fondaient sur « un identifiant est-il configuré sur ce poste ? », une question qui ne renseigne en rien sur ce que le serveur, lui, connaît. Elles suivent maintenant sa réponse, qui sépare « aucun pair à cette adresse » de « accès fermé, code attendu ». Un poste non enrôlé n'est donc plus sollicité pour un code qui n'ouvrirait rien. ### Corrigé - **La fenêtre de saisie réclamait l'identifiant à chaque ouverture, et l'authentification échouait.** Les deux symptômes n'en faisaient qu'un : l'identifiant n'était enregistré qu'après une authentification réussie, or aucune n'aboutissait — il était donc redemandé sans fin. Sans objet désormais, puisqu'il n'est plus demandé. - **Régression de la v0.9.0 : la passerelle du tunnel était calculée à `0.0.0.1` en tunnel intégral.** La déduction retenait la route par défaut des IPs autorisées (`0.0.0.0/0`) comme réseau du tunnel et en prenait le premier hôte. Sondage d'état et validation de code partaient alors vers une adresse qui n'existe pas, sans autre issue que de renseigner l'URL de l'API à la main. Seuls les réseaux contenant l'adresse du client sont désormais retenus, le plus spécifique d'abord, avec repli sur le /24 (ou /64) usuel faute de candidat. Le diagnostic « Pair joignable dans le tunnel » souffrait du même défaut et en bénéficie. - Une demande d'ouverture distingue à présent le silence du réseau d'un refus du serveur, comme le sondage d'état le faisait déjà : un serveur injoignable ne fait plus passer pour refusé ce qu'il n'a jamais examiné. ### Technique - `AuthResult` porte un champ `enrolled`, renseigné par le seul sondage d'état : sur une demande d'ouverture, le même code HTTP signifie « identifiant ou code invalide », ce qui est tout autre chose. - Côté serveur (dépôt WGSecure-Serveur, v0.3.2) : `POST /api/session` désigne le compte par l'adresse de l'appelant, `username` devient facultatif et n'est plus que vérifié, et l'état d'accès répond 401 pour un pair inconnu au lieu de 403 — 404 restant réservé au repli « serveur antérieur à la v0.3.0 ». --- ## [0.9.0] — 2026-09-08 ### Corrigé - **L'adresse du serveur d'authentification était devinée de travers dès que le client n'était pas en /24.** Elle se déduisait en retranchant le dernier octet de l'adresse du client, ce qui suppose un réseau /24 et ignore les IPs autorisées. Or une adresse client en /32 est la forme la plus courante et ne décrit aucun réseau : un poste en 10.6.1.7/32 sur un 10.6.0.0/16 était expédié vers 10.6.1.1, qui n'existe pas. Sondage et validation échouaient tous deux, sans autre issue que de renseigner `api_url` à la main. La déduction passe désormais par la même fonction que le diagnostic (`tunnel_gateway`), qui gère le /32, l'IPv6 et le repli sur les IPs autorisées. Une adresse IPv6 est encadrée de crochets, sans quoi son « : » se confondait avec celui du port. - **Une révocation décidée par le serveur restait invisible.** Le client ne demandait l'état de l'accès qu'au retour du tunnel : un redémarrage du serveur, une purge de sa table de sessions ou une décision d'administrateur n'étaient annoncés par rien. L'application affichait « Ouvert ✓ » devant un réseau muet, bouton et entrée de systray masqués, jusqu'à la chute du tunnel — et indéfiniment face à un serveur qui n'annonce pas d'échéance. L'accès est reconfirmé chaque minute tant qu'il est cru ouvert. - **Fermer la fenêtre de saisie pendant la vérification perdait une authentification réussie.** « Plus tard », la touche Échap et la croix restaient actifs le temps de la requête, qui peut durer dix secondes. Fermer là rendait la main sur un refus alors que le serveur pouvait encore accepter : sa réponse arrivait après coup et n'était lue par personne. L'accès était ouvert côté serveur, l'application affichait la quarantaine, et le code saisi était consommé pour rien. La fenêtre ne se ferme plus tant qu'une requête est en vol. - **Le repli pour serveurs anciens, introduit en 0.8.7, pouvait déclarer l'accès ouvert alors qu'il ne l'était pas.** Il tenait pour preuve toute réponse du serveur DNS du split-DNS, sans vérifier que celui-ci était joint *par le tunnel*. Une adresse d'entreprise également routée par le réseau local du poste — télétravail depuis un site jumeau, autre VPN déjà monté — répondait donc hors tunnel : accès déclaré ouvert, sans échéance donc sans fin, bouton masqué. Le repli censé éviter le blocage le provoquait. La route est vérifiée d'abord, sans émettre le moindre paquet. - **Sur un poste derrière un proxy d'entreprise, la requête d'authentification partait au proxy.** `urllib` lit `http_proxy` dans l'environnement : la requête vers l'adresse privée du tunnel était détournée, et la réponse du proxy — souvent un 404 — prise pour celle du serveur, déclenchant justement le repli ci-dessus. Panne parfaitement intermittente : selon l'environnement de lancement, cela passait ou non. Le serveur d'authentification n'étant joignable que par l'intérieur du tunnel, tout proxy est désormais ignoré. - **Un serveur momentanément muet était traité comme un refus.** Un hoquet réseau au montage du tunnel faisait surgir la fenêtre de saisie et brûler un code, alors que l'accès était peut-être déjà ouvert. Le client distingue maintenant « le serveur refuse » de « le serveur n'a rien dit » : un refus fait autorité et referme du premier coup, un silence déclenche un second sondage trois secondes plus tard avant de déranger l'utilisateur, et n'entame un accès établi qu'après trois minutes sans réponse. - **Renoncer à saisir un code refermait un accès pourtant ouvert.** L'état était réécrit à la fermeture de la fenêtre quoi qu'il arrive : un sondage abouti pendant qu'elle était ouverte — les minuteries tournent — pouvait établir que l'accès l'était, que « Plus tard » remettait aussitôt à fermé. Renoncer à saisir un code ne referme rien côté serveur ; plus rien côté poste non plus. - La fenêtre de saisie est détruite après usage. Ni sa validation ni son abandon ne passaient par la fermeture attendue par Qt : son minuteur continuait à battre indéfiniment, et la fenêtre survivait à sa propre disparition, son thread n'étant plus attendu à l'arrêt de l'application. ### Ajouté - **Trois sous-onglets dans la page « À propos »** : Mode d'emploi, Prérequis et Sécurité, aux côtés de Fonctions, Garanties, Technique, Journal et Auteur. Le mode d'emploi couvre la première configuration pas à pas, les gestes du quotidien et les pannes courantes ; les prérequis listent paquets, ports et privilèges par plateforme ; la page Sécurité détaille l'authentification, la cryptographie, la protection des secrets au repos et la réduction de la surface d'attaque. ### Sécurité - L'URL de l'API n'est plus reprise telle quelle : seuls les schémas `http` et `https` sont acceptés. Identifiant et code d'accès partent dans cette URL, et une valeur saisie de travers les aurait envoyés ailleurs que prévu, ou aurait échoué sans dire pourquoi. - Rappel, inchangé et hors de portée du client : l'API par défaut est en clair et le serveur n'est pas authentifié. La confidentialité vient du tunnel seul. Si le serveur laisse les pairs en quarantaine se joindre entre eux, un pair malveillant peut usurper l'adresse de l'API et moissonner identifiants et codes. Filtrer le trafic intra-tunnel côté serveur, ou exposer l'API en TLS et renseigner `api_url` en `https://` — le client le gère déjà. ### Technique - `AuthResult` porte un champ `authoritative`, qui dit si le serveur a réellement répondu. C'est lui qui permet de ne plus confondre refus et silence. - `_tunnel_gateway` devient `tunnel_gateway` : la déduction de l'adresse du serveur dans le tunnel avait deux implémentations divergentes, il n'en reste qu'une. - **Nouvelle cible `make windows-release`**, qui enchaîne les quatre gestes manuels de la production des artefacts Windows dans le seul ordre qui fonctionne, et vérifie d'emblée que la version du `Makefile` et celle de `wgsecure.iss` concordent — les bumper séparément produisait un installeur au mauvais numéro, que `publish` ne retrouvait pas. --- ## [0.8.7] — 2026-09-07 ### Corrigé - **L'application avortait à l'arrêt (`QThread: Destroyed while thread is still running`, code 134).** `prepare_quit()` attend la fin des threads en cours avant de laisser détruire quoi que ce soit, mais sa liste en oubliait deux. Le premier est le sondage d'état ajouté en 0.8.6 — une régression introduite par cette version. Le second est le thread de validation de la fenêtre de saisie, parenté à cette fenêtre depuis la v0.8.2 et jamais attendu : il suffisait de fermer la fenêtre de code pendant qu'une requête était en vol, ce qui arrive dès que le serveur tarde à répondre. Les deux sont désormais attendus, le second via `AccessCodeDialog.wait_for_worker()`. Reproduit puis vérifié avec un serveur qui accepte les connexions sans jamais répondre. - Le sondage d'état est borné à **4 secondes** au lieu des 10 de la validation d'un code. Sans cela, le correctif ci-dessus transformait le plantage en interface figée le temps du délai d'expiration : l'arrêt attend ce thread. Un sondage qui échoue ne coûte rien — le bouton reste disponible — là où une validation ratée gâche un code déjà saisi. ### Ajouté - **Temps restant sur la ligne *Accès distant*** du panneau Détails : « Ouvert ✓ jusqu'à 08/09 à 09:56 (reste 7 h 12 min) ». La date n'est rappelée que si l'échéance tombe un autre jour — la durée est réglable jusqu'à 168 h côté serveur. Le décompte est arrondi à la minute et non tronqué, sans quoi une fenêtre de 8 h fraîchement ouverte s'affichait « 7 h 59 min ». Rafraîchi au rythme du sondage de statut existant, sans minuteur supplémentaire. - **Repli pour les serveurs antérieurs à la v0.3.0**, qui n'exposent pas `GET /api/session`. Face à un 404 — et à un 404 seulement — le client observe si le trafic atteint réellement le réseau distant, en sondant le serveur DNS du split-DNS déjà configuré. La quarantaine jette le trafic traversant : toute réponse de cet hôte prouve qu'elle est levée, un refus de connexion compris (le paquet a atteint la machine). L'accès est alors affiché ouvert, mais sans échéance : la sonde constate, elle ne peut pas dater. Un 403 reste une réponse qui fait autorité et n'est jamais contredite par la sonde ; sans `split_dns_server` configuré, aucun repli. --- ## [0.8.6] — 2026-09-07 ### Corrigé - **Le bouton « Saisir le code d'accès » réclamait un code déjà validé après une reconnexion.** L'application tenait pour acquis que l'autorisation obtenue ne survivait pas à la chute du tunnel — un commentaire du code l'affirmait même explicitement. C'est l'inverse : le serveur autorise l'adresse de tunnel du pair jusqu'à l'échéance enregistrée, et cette adresse ne change pas d'une reconnexion à l'autre. Une déconnexion/reconnexion ne révoque donc rien, mais le client oubliait tout et repartait de zéro. Il interroge désormais le serveur — nouvelle route `GET /api/session`, disponible à partir de la v0.3.0 du serveur — dès que le tunnel monte : au démarrage de l'application sur un tunnel déjà actif, après une reconnexion automatique, et avant toute invite de saisie. Quand l'accès est encore ouvert, aucune fenêtre ne s'ouvre et l'échéance réelle est reprise telle quelle. ### Modifié - Le sondage n'envoie aucun identifiant : le serveur reconnaît l'appelant à l'IP source de son tunnel, et ne renseigne donc jamais sur un autre compte que celui qui parle. - **Un serveur injoignable, une réponse illisible ou une version de serveur antérieure à la 0.3.0 ne valent pas « accès ouvert »** : dans ces trois cas le client ne conclut rien et laisse le bouton disponible. Avec un serveur ancien, le comportement est exactement celui de la 0.8.5 — la route manquante est traitée comme une absence d'information, pas comme un refus. - Le commentaire de `main_window.py` qui affirmait le contraire de la réalité (« elle ne vaut que pour l'adresse du pair, elle ne survit pas à la déconnexion ») est corrigé : elle survit précisément *parce qu'*elle vaut pour l'adresse du pair. --- ## [0.8.5] — 2026-09-07 ### Corrigé - **Le bouton « Saisir le code d'accès » restait masqué une fois l'autorisation expirée.** L'application marquait l'accès comme ouvert à la validation du code et ne revenait sur ce constat qu'à la chute du tunnel : rien ne consommait l'échéance que le serveur renvoie pourtant dans sa réponse, elle ne servait qu'à composer une phrase du journal. Passé le délai — un réglage serveur, invisible du poste — le pair retournait en quarantaine sans que l'interface en sache rien : elle affichait toujours « Ouvert ✓ », masquait le bouton et l'entrée de systray, et laissait l'utilisateur devant un réseau muet sans moyen visible de ressaisir un code. C'est exactement la situation que ce bouton existe pour éviter depuis la v0.8.2, et le seul cas qui lui échappait encore. Le client relit désormais l'échéance annoncée par le serveur et réévalue l'affichage à chaque rafraîchissement de statut, soit dans les trois secondes suivant l'expiration. - **L'heure de fin d'accès était annoncée en UTC mais présentée comme locale** : « ouvert jusqu'à 20:30 » pour une autorisation courant en réalité jusqu'à 22:30 heure de Paris, deux heures d'avance en été. L'horodatage est maintenant converti dans le fuseau du poste. ### Modifié - Nouvel état **« Autorisation expirée (code requis) »** sur la ligne *Accès distant*, distinct de « Quarantaine (code requis) » : l'utilisateur voit que son code a bien été accepté et que le délai a couru, plutôt que de croire que sa saisie n'a jamais abouti. - Quand l'accès est ouvert, la ligne indique l'heure de fin (« Ouvert ✓ jusqu'à 22:30 »), l'échéance n'étant plus une information jetée après affichage. - `vpn_session.authenticate()` retourne un `AuthResult(ok, message, access_until)` au lieu d'un couple `(bool, str)`, et la fenêtre de saisie passe de `TaskWorker` à `ValueWorker` : le premier n'achemine que `(bool, str, str)`, une signature partagée par tous les autres appels de l'application et qu'il aurait fallu élargir pour tout le monde. - Un serveur qui n'annonce aucune échéance laisse l'autorisation valable jusqu'à la déconnexion : le client ne lui en invente pas une, ce qui fermerait un accès encore ouvert. La durée reste décidée par le serveur, seule autorité en la matière. --- ## [0.8.4] — 2026-09-06 ### Corrigé - **Aucun moyen de saisir le code tant que le champ *Identifiant VPN* n'était pas renseigné** — ni bouton, ni entrée de systray, sur les deux plateformes. Ce champ, introduit en v0.8.0 et vide par défaut, conditionnait l'affichage des deux commandes : un poste que le serveur tenait bel et bien en quarantaine n'affichait donc rien pour en sortir, précisément dans la situation où il en avait besoin. La saisie ne dépend plus que du tunnel : monté et accès non ouvert, elle est atteignable. L'identifiant est demandé dans la fenêtre elle-même quand il manque, et enregistré une fois que le serveur l'a reconnu — jamais avant. - **L'état « Non géré par le serveur » était une affirmation sans vérification.** Le client la tirait de sa seule configuration locale, alors qu'il n'en sait rien : le serveur peut parfaitement tenir ce pair en quarantaine pendant que le poste ne mentionne aucun serveur. La ligne indique désormais « Non vérifié », qui est la vérité tant qu'aucun code n'a été validé. ### Modifié - L'invite spontanée après connexion reste, elle, conditionnée à un identifiant connu : une installation sans serveur d'authentification n'a aucune raison de voir surgir cette fenêtre à chaque connexion. Le bouton reflète la nuance — mis en avant quand un code est réellement attendu, discret sinon. --- ## [0.8.3] — 2026-09-06 ### Corrigé - **Le bouton « Saisir le code d'accès » n'apparaissait pas**, alors même que la ligne *Accès distant* indiquait la quarantaine. Il était bien créé et placé dans le layout, mais sous le bord inférieur d'une fenêtre restée à sa hauteur précédente. Rendre un widget visible ne met pas les layouts à jour immédiatement : Qt poste un `LayoutRequest` traité au tour de boucle suivant, et la fenêtre — de hauteur fixe, recalculée à chaque changement de contenu — se mesurait avant ce traitement, obtenant une hauteur en retard d'un cycle. Les layouts sont désormais remis à plat explicitement avant toute mesure. Corrige du même coup le repli du détail, qui souffrait du même retard sans que cela se voie. --- ## [0.8.2] — 2026-09-06 ### Corrigé - **Aucun moyen de saisir son code une fois en quarantaine.** La fenêtre de saisie ne s'ouvrait qu'une fois, dans la seconde suivant une connexion manuelle réussie. Un code refusé, une fenêtre fermée, une reconnexion automatique — qui n'ouvre volontairement aucune fenêtre modale, personne n'étant devant l'écran — ou l'expiration de l'autorisation au bout de 12 h laissaient l'utilisateur avec un tunnel monté, un réseau muet et pour seule issue une déconnexion/reconnexion. Un bouton **« Saisir le code d'accès »** apparaît désormais sous le bouton de connexion, et une entrée équivalente dans le menu du systray, dès qu'une saisie a un sens : identifiant VPN configuré, tunnel monté, accès non ouvert. Ils disparaissent le reste du temps, sans rien changer aux installations sans authentification serveur. - Le bouton apparaissait et disparaissait correctement, mais son calcul de hauteur se relançait à chaque cycle de rafraîchissement lorsque la fenêtre était repliée dans le systray : `isVisible()` y est faux pour tout enfant d'une fenêtre masquée, quel que soit l'état demandé. C'est `isHidden()` qui porte cette intention. --- ## [0.8.1] — 2026-09-06 ### Sécurité - **Le secret TOTP ne réside plus sur le poste client.** Il y était stocké en clair dans `config.json`, alors que l'application n'en a plus l'usage depuis que le serveur valide les codes : un secret d'authentification sans emploi, exposé pour rien. Il est effacé du fichier au premier lancement de cette version, avec le réglage qui l'accompagnait. ### Modifié - **Une seule saisie de code, et elle compte.** La v0.8.0 laissait cohabiter deux vérifications : la fenêtre MFA locale — qui contrôlait un code contre un secret que le poste détenait lui-même, et ne verrouillait donc que l'interface — puis la validation par le serveur. L'ancienne disparaît ; reste celle qui décide réellement de l'accès au réseau. - La fenêtre de saisie remplace la boîte de dialogue sommaire de la v0.8.0 : elle affiche le refus exact renvoyé par le serveur (code invalide, compte verrouillé, expiré) et laisse réessayer sans reconnecter le tunnel. La requête part dans un thread — un serveur qui ne répond pas ne fige plus l'application. - **Nouvelle ligne « Accès distant » dans le panneau de détails**, distincte de l'état du tunnel : *Ouvert*, *Quarantaine (code requis)*, ou *Non géré par le serveur*. Un tunnel monté sans code validé ne mène nulle part — sans cette ligne, l'application affichait « Connecté » devant un réseau muet. - L'auto-reconnexion n'est plus suspendue par le MFA : elle remonte le tunnel, et l'application signale simplement qu'un code reste à saisir. - Onglet **MFA** retiré du panneau Administrateur, avec la génération de secret et le QR code : c'est désormais le serveur qui les délivre. L'export QR de la configuration WireGuard, lui, reste en place. --- ## [0.8.0] — 2026-09-06 ### Sécurité - **Le code à 6 chiffres est désormais validé par le serveur, plus par l'application.** Jusqu'ici le secret TOTP était stocké côté client : l'application vérifiait un code qu'elle pouvait elle-même produire, et ne verrouillait donc que sa propre interface — un fichier `.conf` dérobé suffisait à entrer via le client WireGuard standard. Le tunnel monte maintenant en quarantaine réseau : le serveur ne laisse passer le trafic vers les ressources distantes qu'après validation du code, contre un secret que l'application ne détient pas. ### Modifié - **Le tunnel est installé une fois, puis simplement démarré et arrêté.** Créer ou supprimer un service Windows n'est jamais délégable à un utilisateur standard, le démarrer peut l'être : c'est la réinstallation à chaque connexion qui imposait une authentification administrateur à chaque connexion *et* déconnexion. Le démarrage emprunte trois voies en cascade — appel direct, service `wgsecure-helper`, puis élévation en dernier recours — pour fonctionner quelle que soit la configuration du poste. - Deux réglages dans le panneau Administrateur : l'identifiant VPN tel que connu du serveur, et l'URL de son API (déduite de l'adresse du client si laissée vide). --- ## [0.7.19] — 2026-09-05 ### Sécurité - **La clé privée ne subsiste plus en clair dans `%APPDATA%\WGSecure`.** Le fichier `.conf` généré pour monter le tunnel y restait indéfiniment, lisible par l'utilisateur : il est désormais écrasé puis supprimé dès que `wireguard.exe` l'a consommé (celui-ci en conserve sa propre copie, chiffrée par DPAPI, dans `ProgramData\WireGuard\Configurations`, et la désinstallation du tunnel ne prend que le nom de l'interface). Windows uniquement : sous Linux, `/etc/wireguard/.conf` reste indispensable à `wg-quick down`. - **Le `.conf` importé peut être effacé dans la foulée.** Après un import, l'application propose d'écraser et supprimer le fichier source, qui contient lui aussi la clé privée en clair — il traîne sinon dans Téléchargements ou sur le Bureau. Proposé et non imposé : c'est un fichier choisi par l'utilisateur, le détruire sans confirmation serait irrattrapable si l'import s'avérait incorrect. ### Corrigé - **« Erreur interne : module win32pipe has no attribute ImpersonateNamedPipeClient » à la connexion.** Cette fonction appartient à `win32security`, pas à `win32pipe` (vérifié par introspection de pywin32, et non plus supposé). --- ## [0.7.18] — 2026-09-05 ### Corrigé - **« Chemin de configuration hors du dossier attendu » à l'installation du tunnel par le service.** Le service exigeait que le `.conf` se trouve dans `%ProgramData%\WireGuard\`, alors que l'application l'écrit sous Windows dans `%APPDATA%\WGSecure\` (`get_client_config_path`) — le seul endroit où un utilisateur non-admin peut écrire. Ce dossier ne peut pas être recalculé par le service, qui tourne en LocalSystem et verrait le `%APPDATA%` de SYSTEM : la validation repose désormais sur l'usurpation d'identité du client du pipe (`ImpersonateNamedPipeClient`), le fichier devant être ouvrable **par l'appelant lui-même** — un utilisateur ne peut donc jamais faire lire à SYSTEM un fichier auquel il n'a pas déjà accès. S'y ajoutent des contrôles structurels (chemin absolu, sans remontée de répertoire, nommé exactement `.conf` dans un dossier `WGSecure`). - Les messages de refus indiquent maintenant ce qui a été reçu **et** ce qui était attendu, au lieu du seul chemin rejeté. --- ## [0.7.17] — 2026-09-05 ### Corrigé - **Le service `wgsecure-helper` ne démarrait jamais réellement** — cause racine des invites d'authentification qui persistaient malgré les v0.7.12 à v0.7.16. Lancé par le gestionnaire de services, l'exécutable ne reçoit aucune commande sur sa ligne d'appel : `win32serviceutil.HandleCommandLine()` se contentait alors d'afficher son aide et de sortir, sans jamais entrer dans le dispatcher de service. `SvcDoRun()` n'était donc jamais exécuté (d'où l'absence totale de fichier journal), le pipe n'existait jamais, et l'application retombait systématiquement sur l'élévation UAC. Le point d'entrée bascule désormais sur `servicemanager.PrepareToHostSingle()` + `StartServiceCtrlDispatcher()` quand le service est démarré par le SCM, et ne conserve `HandleCommandLine()` que pour les invocations manuelles (`install`, `start`, `debug`…). - Un échec de création du journal fichier est désormais signalé dans le journal d'événements Windows (source « WGSecureHelper ») au lieu de rester totalement silencieux. --- ## [0.7.16] — 2026-09-04 ### Corrigé - **Le service `wgsecure-helper` répondait au premier appel puis devenait injoignable** (connexion automatique au démarrage sans prompt, puis retour aux invites UAC ensuite). La boucle principale ne capturait que `pywintypes.error` et ne protégeait pas `CloseHandle` individuellement dans son nettoyage — une exception non prévue sur une requête, ou un échec de fermeture de handle, pouvait faire sortir de la boucle et arrêter tout le service. Chaque étape (création du pipe, connexion, traitement, fermeture) est désormais individuellement protégée par une capture large, avec un filet de sécurité final qui journalise toute erreur inattendue au lieu de laisser le service disparaître en silence. Gère aussi correctement `ERROR_PIPE_CONNECTED` (client connecté entre la création du pipe et l'appel `ConnectNamedPipe` — un cas normal, pas rare, qui faisait auparavant rater la requête). --- ## [0.7.15] — 2026-09-04 ### Corrigé - **Le service `wgsecure-helper` n'était jamais réellement utilisé par l'app** (split-DNS fonctionnait, mais toujours via le chemin élevé — 2 invites UAC à la connexion au lieu de 0). Le client du pipe (`app/utils/helper_ipc.py`) ne déclarait les signatures `ctypes` explicites que pour `CreateFileW` : sans elles, `ReadFile`/`WriteFile`/`CloseHandle` marshalaient le HANDLE (pointeur 64 bits) comme un entier 32 bits par défaut, le tronquant silencieusement — l'échange avec le service échouait alors systématiquement, et l'app retombait sur son ancien chemin élevé sans que rien ne le signale. Signatures explicites ajoutées pour chaque appel. --- ## [0.7.14] — 2026-09-04 ### Corrigé - **Le service `wgsecure-helper` n'était jamais enregistré par l'installeur.** Les entrées `[Run]` posant `sc.exe create ...` via l'échappement de guillemets `""` imbriqués d'Inno Setup produisaient une commande invalide — silencieusement : aucune erreur affichée pendant l'installation, alors que la même commande, lancée à la main avec une syntaxe équivalente, fonctionnait. Remplacé par un appel `Exec()` scripté (Pascal, `AddQuotes`) après la copie des fichiers, qui construit et lance la commande sans juggler des niveaux d'échappement de chaîne imbriqués. Même mécanisme pour la désinstallation (arrêt + suppression du service). --- ## [0.7.13] — 2026-09-04 ### Corrigé - **Pose de la règle split-DNS (NRPT) systématiquement en échec.** `Add-DnsClientNrptRule` n'a pas de paramètre `-Name` (contrairement à `Get-`/`Set-`/`Remove-DnsClientNrptRule` : la règle créée reçoit un identifiant GUID auto-généré) — `-Name` était résolu par PowerShell comme une abréviation ambiguë entre `-Namespace`/`-NameServers`/`-NameEncoding` (« le nom du paramètre "name" est ambigu »). Bug présent depuis l'introduction du split-DNS, resté invisible jusqu'à la v0.7.9 (les messages d'erreur d'une commande élevée remontaient vides). La règle est désormais identifiée/retrouvée via `-Comment`, comme le fait déjà le nettoyage générique du fichier. Corrige à la fois le chemin élevé classique et le service `wgsecure-helper` (v0.7.12), qui réutilise cette même fonction. --- ## [0.7.12] — 2026-09-04 ### Ajouté - **Service Windows privilégié `wgsecure-helper`.** Élimine les authentifications admin restantes à la connexion/déconnexion pour un compte non-admin. Tourne en LocalSystem, exécutable séparé jamais chargé par l'app principale ; expose cinq commandes fixes (`install_tunnel`, `uninstall_tunnel`, `set_split_dns`, `clear_split_dns`, `get_status`) via un pipe nommé sécurisé (SDDL explicite), chacune validant strictement ses paramètres — jamais de script/commande arbitraire accepté. L'app principale tente ce service en premier (client `ctypes` pur, sans nouvelle dépendance) et retombe sur le chemin élevé existant s'il est absent : purement additif, installation optionnelle. Corrige au passage le handshake qui ne se rafraîchissait jamais (`wg show` échouait systématiquement sans élévation complète, même avec les délégations de la v0.7.6). - L'ACL du service WireGuard (bouton « Configurer les permissions ») ne délègue que démarrer/arrêter un tunnel déjà installé, jamais le créer/supprimer — WGSecure réinstalle pourtant le tunnel à chaque connexion/déconnexion. C'est ce qui rendait les invites d'authentification inévitables malgré la v0.7.6 à v0.7.11 ; le nouveau service couvre cette étape. --- ## [0.7.11] — 2026-09-04 ### Corrigé - **« Configurer les permissions » échouait si un tunnel était actif.** `Restart-Service` refuse d'arrêter le service WireGuard tant qu'un tunnel dépendant (`WireGuardTunnel$`) tourne — ce qui annulait toute l'opération alors que l'ACL et le registre venaient d'être appliqués avec succès. Le redémarrage est désormais tenté en best-effort : un échec produit un avertissement (déconnectez le tunnel puis redémarrez le service, ou redémarrez la machine) sans faire échouer le reste. --- ## [0.7.10] — 2026-09-04 ### Corrigé - **« Configurer les permissions » échouait à chaque nouvelle tentative une fois le groupe déjà accordé.** Le cas « déjà membre du groupe » était détecté en cherchant le texte anglais `already a member` dans le message d'erreur — jamais présent sur un Windows en français, qui renvoie « est déjà membre du groupe ». Détection basée désormais sur `FullyQualifiedErrorId` (`MemberExists,...`), stable et indépendant de la langue du système. --- ## [0.7.9] — 2026-09-04 ### Corrigé - **`sc sdset` échouait toujours (erreur 1804, SDDL invalide).** Le correctif précédent ajoutait l'ACE en fin de chaîne SDDL, mais la sécurité d'un service porte souvent aussi une clause `S:` (SACL — étiquette d'intégrité obligatoire, ex. `S:(ML;;NW;;;LW)`) : l'ACE se retrouvait alors insérée après le `S:`, produisant une SDDL syntaxiquement invalide. L'ACE est désormais insérée à l'intérieur de la clause `D:`, avant tout `S:` éventuel. - **Caractères accentués corrompus dans les messages d'erreur Windows** (« échoué » affiché « ‚chou‚ »). Les outils console natifs (`sc.exe`, PowerShell non-Core) écrivent dans le codepage OEM de la console (CP850 en français), pas en UTF-8 ni en ANSI : `run_command()` décode désormais explicitement avec ce codepage. Le fichier de capture d'une commande élevée (v0.7.7) utilisait quant à lui la redirection `*>` brute, qui écrit en UTF-16LE par défaut sous Windows PowerShell — remplacée par `Out-File -Encoding utf8` explicite, lu en UTF-8. --- ## [0.7.8] — 2026-09-04 ### Corrigé - **ACL du service WireGuard jamais réellement posée par « Configurer les permissions ».** Le script PowerShell récupérait la SDDL actuelle via `Get-WmiObject ... .DACL.ToString()` — `.DACL` est un tableau d'objets PowerShell, pas une chaîne SDDL, donc `.ToString()` ne produisait pas la syntaxe attendue par `sc sdset`. L'échec n'était jamais vérifié : le bouton annonçait un succès alors que l'ACL n'était jamais appliquée, laissant l'installation/désinstallation du tunnel exiger une élévation en plus de celle (inévitable) du split-DNS — deux invites UAC au lieu d'une. Remplacé par `sc.exe sdshow` (format texte natif) avec insertion correcte de l'ACE et vérification explicite des codes de sortie (`sc sdset`, `Restart-Service`). --- ## [0.7.7] — 2026-09-04 ### Corrigé - **Messages d'erreur Windows toujours « erreur inconnue » pour toute opération élevée** (split-DNS, installation/désinstallation du tunnel). Un processus lancé via l'invite UAC (`ShellExecuteEx`/`runas`) ne peut jamais faire remonter son stdout/stderr au processus appelant — ni même via `Start-Process -RedirectStandardOutput`, qui échoue pour la même raison. La commande élevée écrit désormais elle-même sa sortie dans un fichier temporaire, relu ensuite : les messages d'échec redeviennent lisibles. - **Handshake jamais affiché sur la page d'accueil sous Windows.** `wg show` était abandonné sans même être tenté dès que le processus n'était pas administrateur. L'appel non élevé est désormais réellement essayé (sans jamais ouvrir de fenêtre UAC) — il peut réussir si le mécanisme ci-dessous est actif. ### Ajouté - **Délégation Windows étendue au mécanisme officiel WireGuard.** Le bouton « Configurer les permissions » active désormais aussi `LimitedOperatorUI` et l'ajout au groupe *Opérateurs de configuration réseau* (en plus de l'ACL du service déjà posée), pour élargir ce qu'un utilisateur non-admin peut faire sans invite UAC. - **Diagnostic Windows honnête sur le split-DNS.** Aucune délégation à un utilisateur non-admin n'existe pour les règles NRPT (`Add`/`Remove-DnsClientNrptRule`) — le panneau Tests & diagnostic le signale désormais explicitement au lieu de laisser croire que l'ACL du service suffit à supprimer tous les prompts. --- ## [0.7.6] — 2026-09-04 ### Ajouté - **Fichier log texte des opérations.** En plus du journal JSON interne (`events.json`, limité à 200 entrées et illisible hors de l'application), chaque événement est désormais aussi écrit dans `wgsecure.log` (rotation automatique, 1 Mo × 3 fichiers) dans le dossier applicatif (`%APPDATA%\WGSecure` sous Windows, `~/.wgsecure` sous Linux) — consultable avec un simple éditeur de texte pour diagnostiquer un échec (ex. configuration du split-DNS) sans dépendre de l'interface. ### Corrigé - **Messages du panneau Journal tronqués sans moyen de les lire en entier.** La barre de défilement horizontale était explicitement désactivée sur le panneau Journal, coupant net les messages longs (ex. une erreur NRPT complète sous Windows). Le défilement horizontal est réactivé et une infobulle affiche désormais le message complet au survol de chaque entrée. --- ## [0.7.5] — 2026-09-04 ### Corrigé - **Connexion Windows en échec silencieux sur « Accès refusé ».** `wireguard.exe /installtunnelservice` et `/uninstalltunnelservice` étaient lancés sans élévation en misant sur le manifeste UAC natif de `wireguard.exe` — qui ne s'auto-déclenche que lancé depuis l'explorateur ou via ShellExecute, jamais via l'appel process-à-process utilisé ici. Sans les ACLs du service accordées, la connexion échouait donc directement, sans jamais afficher la moindre invite. L'appel tente maintenant d'abord sans élévation (aucune UAC si les ACLs ont été accordées via le bouton dédié), puis retente avec une véritable élévation UAC (`ShellExecuteEx "runas"`) si le premier essai échoue. - **Diagnostic d'élévation Windows trompeur.** Le panneau Tests & diagnostic annonçait qu'une invite UAC apparaîtrait à chaque connexion sans mentionner que les ACLs accordées au service l'évitent — corrigé pour refléter les deux cas. --- ## [0.7.4] — 2026-09-04 ### Ajouté - **Diagnostic du split-DNS.** Le test de connexion vérifie désormais que le(s) domaine(s) configuré(s) en split-DNS se résolvent bien vers le réseau distant (et pas juste qu'un résolveur quelconque répond) ; un outil de résolution à la demande est disponible dans le panneau Admin pour tester n'importe quel nom précis. - **Verrouillage des champs après import d'un .conf.** Un fichier `.conf` importé décrit un pair déjà fonctionnel côté serveur : les champs se verrouillent désormais pour éviter qu'une modification manuelle ultérieure ne diverge silencieusement de la configuration réelle. Un bouton « Déverrouiller » reste disponible. - **Aperçu du fichier de configuration à la demande.** Remplace l'aperçu qui restait dupliqué en permanence à côté des champs du formulaire. ### Corrigé - **Split-DNS Linux reposé sur `resolvectl` par interface** au lieu d'un fichier global dans `/etc/systemd/resolved.conf.d/` suivi d'un redémarrage complet de `systemd-resolved`. Évite des droits que `make setup-sudoers` ne couvrait pas, une configuration en concurrence avec d'autres interfaces, et un résidu à nettoyer après un crash — systemd-resolved retire la config par lien dès que l'interface disparaît. - **Règle NRPT Windows incomplète.** Un domaine de split-DNS sans point de tête ne matchait que le nom exact, jamais ses sous-domaines ; les deux formes de namespace sont désormais posées, comme `~domaine` le fait déjà sous Linux. - **Échec silencieux de la configuration split-DNS.** Une erreur réelle d'`Add-DnsClientNrptRule` (Windows) ou de `resolvectl` (Linux) n'était pas remontée : le tunnel se déclarait « activé » même quand les noms du réseau distant ne se résolvaient jamais. Le message de succès affiche désormais un avertissement si le split-DNS n'a pas pu être appliqué. ### Interface - **Couleurs de l'interface consolidées dans `app/ui/theme.py`.** Les teintes codées en dur dans les boîtes de dialogue MFA et Historique sont remplacées par les jetons partagés du thème, pour rester cohérentes si le thème évolue. - Ajout du style des menus déroulants (`QComboBox`) dans le thème sombre. --- ## [0.7.3] — 2026-09-02 ### Ajouté - **Support du Split-DNS pour Linux et Windows.** Permet de configurer un serveur DNS dédié pour les noms du réseau distant (ex: 192.168.1.210) tout en utilisant le DNS système pour le reste du trafic internet. Sous Linux, utilise `systemd-resolved` ; sous Windows, utilise les règles NRPT. - **Bouton de configuration des permissions Windows.** Dans l'onglet Tests & diagnostic → Élévation, un nouveau bouton permet à l'administrateur de configurer les ACLs du service WireGuard pour autoriser l'utilisateur actuel à créer/supprimer ses tunnels sans invite UAC. ### Corrigé - **Appels à sc.exe supprimés sous Windows.** Remplacés par PowerShell `Get-Service` pour la détection, et `wireguard.exe` pour la gestion des services. Supprime les messages d'erreur "service inexistant" et évite les doubles appels à `uninstalltunnelservice`. - **UAC déclenchée par WGSecure sous Windows.** Désormais, `wireguard.exe` est appelé via `run_command()` (pas `run_privileged`) et gère lui-même l'élévation via son manifeste natif. Si l'utilisateur a les permissions ACLs, aucune UAC n'est affichée. - **Handshake bloqué par le redémarrage de systemd-resolved.** Le redémarrage de systemd-resolved est maintenant effectué de manière asynchrone pour éviter de bloquer le handshake WireGuard. ### Améliorations UI - **Infobulles ajoutées** sur tous les champs de configuration principaux pour guider l'utilisateur (endpoint, clés, DNS, AllowedIPs, etc.). --- ## [0.7.1] — 2026-09-01 ### Ajouté - **Diagnostic : DNS hors des IPs autorisées.** Sur un tunnel scindé (AllowedIPs ≠ 0.0.0.0/0), NetworkManager/systemd-resolved associe le DNS configuré à l'interface WireGuard avec un domaine de routage global (`~.`) : toute résolution de nom est alors tentée via cette interface, qui n'a de route que vers les réseaux listés dans les IPs autorisées. Un DNS hors de cette liste (typiquement un résolveur public comme 1.1.1.1 sur un tunnel qui ne route que des sous-réseaux internes) devient injoignable par ce chemin — la résolution échoue en bloc alors que le reste d'Internet continue de fonctionner (d'où un `ping` sur une IP qui réussit à côté d'un `ping` sur un nom qui échoue). Le test de connexion signale maintenant ce cas précis. ### Corrigé - **CHANGELOG.md absent de l'exécutable compilé.** `datas=[]` dans le build PyInstaller n'embarquait jamais le fichier, et son chemin — calculé depuis `__file__` — ne survivait de toute façon pas à l'extraction onefile : la page « À propos » restait vide une fois l'application compilée. Le fichier est désormais ajouté via `--add-data`, et son chemin bascule sur `sys._MEIPASS` en mode figé (frozen). - **Badge de latence toujours « hors ligne » alors que le tunnel fonctionne.** Il se basait uniquement sur un ping ICMP vers l'endpoint du serveur ; de nombreux serveurs ou pare-feux bloquent l'ICMP echo tout en laissant le tunnel WireGuard fonctionner normalement. Repli sur l'âge du dernier handshake réel quand l'ICMP échoue. - **Outils de diagnostic figeant l'application (« Ne répond plus »).** Le test de connexion, l'analyse de fuite DNS et la réparation DNS exécutaient leurs sondes (ping, `dig`, handshake, élévation de privilèges) directement sur le thread graphique — jusqu'à plusieurs secondes de gel total. Déportés sur des threads dédiés, comme le reste de l'application. - **Installeur Windows incomplet.** WireGuard for Windows, prérequis de WGSecure, n'était jamais installé automatiquement. `wgsecure.iss` l'installe désormais en silence s'il est absent, au même titre que le Visual C++ Redistributable ; `make installer-deps` télécharge les deux binaires. ## [0.7.0] — 2026-09-01 ### Ajouté - **Instance unique.** Un second lancement (icône du menu, raccourci double-cliqué, autostart concurrent d'un lancement manuel) réveille désormais l'instance déjà active au lieu d'ouvrir une deuxième fenêtre sur le même tunnel. Implémenté via un socket local nommé (`app/core/single_instance.py`), portable Linux/Windows. - **Lancement automatique et reconnexion automatique activés par défaut** pour une nouvelle installation (reconnexion à 15 s). Une configuration existante n'est jamais modifiée sans action explicite. - **Page « À propos » refaite** sur le modèle QuiOulé/TuxMarket : cinq onglets (Fonctions, Garanties, Technique, Journal, Auteur), en-tête avec pastilles d'état vivantes (MFA, configuration sudoers). Contenu déplacé dans `app/app_info.py`, séparé de la présentation ; version lue dynamiquement depuis `app.__version__`. ### Corrigé - **Dernier handshake et compteurs RX/TX qui ne s'affichaient plus.** `wg show` exige les droits root même en lecture seule ; l'appel se faisait sans élévation et échouait silencieusement dès que l'application ne tournait plus en root (le cas normal une fois `make setup-sudoers` en place). Nouvelle fonction `run_privileged_readonly` : élévation silencieuse via `sudo -n` uniquement, jamais de dialogue sur un sondage exécuté toutes les 3 secondes. - **Diagnostic des droits sudo trompeur.** `make check-privileges` testait chaque commande avec `--version`/`-V`, des appels qui ne correspondent à aucune règle NOPASSWD restreinte par motif (ex. `ip link delete dev *`) : le diagnostic affichait « dialogue à chaque appel » même quand tout était correctement configuré. Les sondes reproduisent maintenant un appel réel couvert par les règles installées. - **`make setup-sudoers` restait bloqué indéfiniment** hors session graphique (SSH, tmux, terminal sans agent polkit) : `pkexec` attendait une réponse d'un agent d'authentification absent. Remplacé par `sudo`, qui invite directement dans le terminal. La cible est aussi rendue idempotente : une relance ne redemande le mot de passe que si les règles ont changé. - **README obsolète** : retrait des mentions d'un Kill Switch iptables absent du code actuel (probablement retiré lors d'un refactor sans mise à jour de la doc) ; section sur l'élévation de privilèges corrigée pour refléter l'ordre réel (`sudo -n` → askpass → `pkexec`, et non l'inverse). ## [0.6.0] — 2026-09-01 ### Ajouté - **Test de handshake réel, sans monter le tunnel.** Le diagnostic s'arrêtait au constat « le port UDP ne rejette rien », qui est le maximum qu'une sonde aveugle puisse dire : un serveur WireGuard ignore silencieusement tout paquet non authentifié, si bien qu'un port non redirigé, une clé inconnue du serveur et un serveur en parfaite santé produisent exactement la même absence de réponse. Le tunnel n'étant pas monté, les étapes suivantes étaient sautées et le rapport concluait « chaîne validée » sur une configuration qui n'avait aucune chance de négocier. WGSecure construit désormais un vrai message d'initiation et interprète la réponse : il distingue un handshake complet, une clé pré-partagée attendue, en trop ou différente, un cookie anti-déni de service, un port fermé et un silence complet — sans ouvrir de tunnel ni demander de privilèges. - **Détection du filtrage sur port source.** Quand le serveur reste muet, une seconde tentative part depuis le port du serveur. S'il répond alors, c'est qu'un équipement en chemin n'accepte le trafic que si le port source égale le port de destination — une règle courante sur FortiGate, dont l'objet Service porte un `udp-portrange 51820:51820`. Un client WireGuard émettant depuis un port aléatoire ne peut jamais la satisfaire, et rien dans les journaux ne le disait. ### Modifié - **Fenêtre d'administration ramenée à 720 × 600** (minimum 640 × 520) : le découpage en sous-onglets a supprimé l'empilement qui imposait une grande fenêtre. - **Encarts d'introduction retirés au-dessus des sous-onglets**, où ils répétaient ce que les sous-onglets annoncent déjà. Ceux placés dans chaque sous-onglet sont conservés. ### Corrigé - **Verdict trompeur quand le tunnel est inactif.** « Chaîne validée jusqu'au tunnel » laissait croire que tout avait été vérifié, alors que les étapes sautées sont précisément celles qui échouent quand un tunnel refuse de négocier. Le rapport annonce maintenant « rien de bloquant détecté, mais le tunnel est inactif » et nomme les étapes non évaluées. - **Causes du handshake manquant** : le port UDP du serveur figure désormais parmi les pistes citées, un port erroné ne produisant aucune erreur visible. ### Technique - Nouveau module `app/core/wg_handshake.py` : implémentation de la poignée de main Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s du protocole WireGuard v1. Aucun état n'est conservé, la session négociée est jetée aussitôt et le serveur traite l'initiation comme celle d'un pair qui se reconnecte. ## [0.5.0] — 2026-09-01 ### Ajouté - **Option « Le serveur utilise une clé pré-partagée »** : la présence d'une PSK ne se devinait plus au fait que le champ soit rempli. Un serveur qui n'en utilise pas — le cas par défaut de WireGuard — déclenchait un avertissement à chaque diagnostic, et une clé oubliée dans le champ se retrouvait écrite dans la configuration alors que le serveur n'en attendait aucune, ce qui casse le handshake aussi sûrement qu'une clé manquante. Le champ et ses boutons suivent la case. - **Encart d'introduction en tête de chaque onglet** : les pages s'ouvraient sur un formulaire nu, sans dire ce qu'on y décidait ni ce qui se passait si on n'y touchait pas. ### Modifié - **Onglets « WireGuard » et « Clés » fusionnés** en un seul, découpé en sous-onglets *Tunnel*, *Clés* et *Profils & fichiers*. Les deux se chevauchaient : la clé publique du serveur se saisissait dans l'un pendant que l'assistant qui la produit vivait dans l'autre, et les quatre façons de sortir une configuration (aperçu, .conf, QR Code, volet serveur) étaient réparties entre les deux sans logique. - **Onglet « Test » en sous-onglets** *Chaîne de connexion*, *Fuite DNS* et *Droits* : les trois tests s'empilaient sur une page unique où le rapport de diagnostic, le plus long, se retrouvait comprimé entre les deux autres. - **Onglets « MFA » et « Sécurité » regroupés** sous *Sécurité*, en sous-onglets *MFA* et *Mot de passe* : ils répondent à la même question, qui a le droit de se connecter et d'administrer. La barre passe de sept onglets à cinq. - **Couleurs unifiées** : le panneau d'administration comptait vingt-quatre couleurs écrites en dur, cinq bandeaux d'onglets sans rapport de teinte entre eux, et des blocs de résultat dont le fond ne correspondait ni à celui de la page ni à celui de leurs voisins. Tout passe par une palette commune. - **L'aperçu de configuration se remplit à l'ouverture** au lieu d'exiger un clic sur « Rafraîchir ». ### Corrigé - **Section « Droits d'exécution » inadaptée sous Windows** : elle parlait de règles sudo, d'un fichier sudoers et de `make setup-sudoers`, qui n'existent pas sur cette plateforme, et concluait « privilèges root, rien à configurer » là où le rapport était simplement vide. Elle devient *Élévation*, vérifie les droits administrateur et la présence de WireGuard, et explique comment éviter la fenêtre UAC à chaque connexion. - **Causes du handshake manquant plus fidèles** : le message citait la clé pré-partagée sans savoir si elle était en jeu, et passait sous silence le port UDP du serveur — un port erroné ne produit aucune erreur visible, WireGuard ignorant silencieusement les paquets. ### Technique - Nouveau module `app/ui/theme.py` : jetons de couleur, styles de blocs de résultat par état, bandeaux et barres d'onglets. - Le drapeau `use_preshared_key` vaut `None` par défaut et non `False` : la fusion des valeurs par défaut recopie ce défaut dans toute configuration antérieure au drapeau, et `False` aurait désactivé la clé pré-partagée d'un tunnel qui fonctionnait. Une configuration existante conserve donc sa PSK, une configuration neuve démarre sans. ## [0.4.6] — 2026-09-01 ### Corrigé - **Handshake impossible quand le réseau local figure dans les « IPs autorisées »** : si la passerelle qui mène au serveur appartient à une plage autorisée, `wg-quick` route cette plage vers le tunnel avec une métrique de 0 — la route l'emporte sur celle de la carte réseau, la passerelle n'est plus joignable que par le tunnel, et le tunnel a justement besoin d'elle pour sortir. Le tunnel montait, l'interface existait, et plus aucun paquet de handshake ne quittait la machine. Le diagnostic détecte désormais ce cas et le signale comme point de blocage, au lieu du simple avertissement « imprimante et NAS passeront par le VPN » qui n'en disait pas la gravité. - **Rapport de test de connexion illisible** : le panneau de résultat était un simple libellé que la mise en page comprimait à quelques lignes tronquées, alors que le rapport en réclame le double. Il devient une zone de texte défilante en pleine largeur, et la fenêtre d'administration, jusque-là figée à 700 × 600, s'ouvre plus grande et se redimensionne librement. ### Technique - Nouvelle fonction `_next_hop()` (`app/core/wireguard.py`) : détermine la passerelle réellement empruntée pour joindre le serveur, via `ip route get` sous Linux et `Find-NetRoute` sous Windows. - `_dark_page()` accepte une option `scroll` : les onglets dont le contenu grandit à l'usage disposent d'une zone défilante. ## [0.4.5] — 2026-08-31 ### Corrigé - **Tunnel « connecté » sans jamais négocier de handshake** : la clé pré-partagée (PresharedKey) n'était écrite dans aucune configuration client. L'assistant « Générer config serveur + client » en produisait une, visible à l'écran, mais impossible à enregistrer ; et l'import d'un fichier `.conf` l'ignorait purement et simplement. Face à un serveur qui en attend une, le tunnel montait, l'interface existait, l'application affichait « Connecté » — et pas un paquet ne passait. La clé pré-partagée est désormais un champ à part entière : saisie, importée, exportée et écrite dans la configuration du tunnel. - **Latence du serveur jamais mesurée hors système anglophone** : la sortie de `ping` est traduite (« temps= » en français), et seule la forme anglaise était reconnue. Un serveur qui répondait correctement était rapporté comme injoignable. ### Ajouté - **Diagnostic complet de la chaîne de connexion** : le bouton « Lancer le test de connexion » ne se contentait plus d'un simple test UDP. Il déroule maintenant toute la chaîne et désigne l'étape exacte qui bloque : présence de WireGuard, complétude de la configuration, cohérence de la paire de clés du client, clé pré-partagée, résolution du nom du serveur, route empruntée, cohérence des « IPs autorisées », ping ICMP, port UDP, montage du tunnel, handshake, trafic chiffré, joignabilité du pair distant et résolution DNS dans le tunnel. - **Détection des deux pièges de routage classiques** : l'adresse du serveur incluse dans les « IPs autorisées » (le tunnel se coupe l'herbe sous le pied dès qu'il monte) et le réseau local couvert par ces mêmes plages (imprimante, NAS et box basculent dans le VPN). - **Champ MTU** : réglable, laissé automatique par défaut, importé et exporté avec les fichiers `.conf`. - **Bouton « Appliquer le volet client »** dans l'assistant de génération : reporte clés et clé pré-partagée directement dans la configuration, au lieu de les laisser dans une fenêtre à recopier. ### Modifié - **Statistiques du tunnel** : le dernier handshake est lu via `wg show latest-handshakes`, ce qui permet d'en donner l'ancienneté exacte et de signaler un pair qui a cessé de répondre. ## [0.4.4] — 2026-08-31 ### Corrigé - **Tunnel impossible à monter sous Windows** : les commandes envoyées à `wireguard.exe` utilisaient des options qui n'existent pas (`/installtunnel`, `/uninstalltunnel`). WireGuard affichait sa boîte d'aide et sortait sans rien faire : le bouton « Connecter » ne montait jamais le tunnel. Les vraies options `/installtunnelservice` et `/uninstalltunnelservice` sont désormais utilisées. - **WireGuard déclaré absent sous Windows** : l'installateur WireGuard n'ajoute pas son répertoire au PATH, et l'application cherchait `wireguard.exe` et `wg.exe` sans chemin. Ils sont maintenant localisés dans `C:\Program Files\WireGuard`. - **« Accès refusé » silencieux sous Windows** : installer ou retirer un tunnel exige les droits administrateur, qui n'étaient jamais demandés. Une invite UAC apparaît désormais au moment voulu, et l'annulation de cette invite est signalée clairement. - **Détection de WireGuard toujours négative sous Windows** : le test d'installation lançait `wireguard --help`, une option inexistante sur une application graphique. La présence du logiciel est maintenant vérifiée sur le disque. - **Échec annoncé sur un tunnel qui montait** : le service du tunnel démarre de façon asynchrone et l'état était vérifié trop tôt. L'application attend désormais son démarrage effectif. ### Ajouté - **Statistiques du tunnel sous Windows** : volumes envoyés/reçus, pair et dernier handshake, jusqu'ici affichés vides. ## [0.4.3] — 2026-08-31 ### Corrigé - **Fenêtres noires clignotantes sous Windows** : l'application interroge en continu l'état du tunnel et la latence du serveur, et chacune de ces vérifications ouvrait brièvement une fenêtre de commande. Des fenêtres DOS apparaissaient et disparaissaient en permanence pendant toute l'utilisation du logiciel. Ces appels s'exécutent désormais de façon totalement invisible. ## [0.4.2] — 2026-08-31 ### Corrigé - **Binaire Windows qui ne démarrait pas** : le paquetage PyInstaller sous Wine oubliait d'embarquer le plugin Qt nécessaire au rendu de l'interface graphique sous Windows, faisant échouer l'application dès le lancement avec l'erreur « no Qt platform plugin could be initialized ». Le plugin est désormais inclus systématiquement dans le binaire. ## [0.4.1] — 2026-08-31 ### Corrigé - **Plus d'accès internet après déconnexion du VPN** : `wg-quick down` refusait de s'exécuter quand l'interface avait disparu sans passage par lui (crash, arrêt brutal, veille) et ne retirait donc jamais l'entrée DNS posée par `wg-quick up` — la résolution de noms restait pointée vers un serveur devenu injoignable. Nettoyage DNS désormais garanti à la connexion, la déconnexion, la fermeture de l'application et au démarrage suivant. - **Détection de connexion fiabilisée** : `wg show` retourne un code de succès même en cas de refus de permission pour un utilisateur non administrateur — l'application se croyait déconnectée en permanence et ne démontait donc jamais le tunnel à la fermeture. Détection réécrite sans nécessiter de privilèges. - **Interface figée pendant la connexion/déconnexion** : les commandes réseau (souvent accompagnées d'une demande de mot de passe) tournaient sur le thread graphique et gelaient la fenêtre. Déportées en tâche de fond. - **Dialogues d'authentification répétés à chaque connexion** : la détection « sudo demande un mot de passe » ne fonctionnait pas en session non anglophone ni pour les comptes disposant de tous les droits sudo, et l'écriture de la configuration WireGuard n'était couverte par aucune règle sudo autorisée. Chaîne de privilèges revue de bout en bout. - Restauration garantie de l'état réseau à la fermeture de l'application, sous Linux comme sous Windows (fermeture normale, icône système, signal d'arrêt, plantage). ### Ajouté - Diagnostic des droits d'exécution (`make check-privileges` et bouton dans le panneau Admin) pour identifier précisément quelle commande déclenche un dialogue d'authentification. - Avertissement lorsqu'un tunnel WireGuard tourne en dehors de WGSecure (autre nom d'interface), cause fréquente de coupure DNS non détectée jusqu'ici. --- ## [0.2.0] — 2026-06-01 ### Ajouté - **Onglet "À propos"** dans le panneau admin : logo bouclier, version, branding JT-Tools by Johnny - **Icône bouclier vectorielle** générée par QPainter (7 résolutions : 16→256 px) - Vert connecté / Rouge déconnecté / Orange connexion en cours / Bleu app / Violet admin - **Icône barre des tâches** : installation automatique de `~/.local/share/icons/wgsecure.png` et `~/.local/share/applications/wgsecure.desktop` au premier démarrage - **Thème sombre uniforme** sur les 6 onglets du panneau admin (CSS partagé `_TAB_CSS`) - Fond `#1c2833`, texte blanc, champs semi-transparents - Bandeau coloré par onglet (bleu/navy/teal/bleu/rouge) - TabBar cohérente avec onglet actif mis en évidence - **Makefile** : compilation binaire Linux (`make linux`) et Windows (`make windows` via Wine) - **README** enrichi avec badges shields.io (version, Python, PyQt6, plateformes) et emojis ### Corrigé - **Bug MDP vide** : `set_admin_password("")` effaçait incorrectement — hashait la chaîne vide, forçant une demande de mot de passe vide après suppression - **Menu systray incomplet** : `QAction` en variables locales GC'd par Python avant affichage → toutes les actions passent désormais `self` comme parent Qt - **Section infos invisible** : `QWidget` sans `autoFillBackground` ne peignait pas son fond ; remplacé par `QFrame` avec `setAutoFillBackground(True)` et couleurs explicites - **Bouton agrandir persistant** : `setWindowFlag` seul ignoré par Mutter/XWayland → `setWindowFlags()` complet sans `WindowMaximizeButtonHint` ### Amélioré - Fenêtre principale agrandie 380×460 → 400×520 pour afficher les 6 lignes d'infos - Police des labels infos : 11 → 12 px, couleurs explicites `#2c3e50` - Panneau admin : largeur 620 → 700 px pour éviter le débordement des onglets - `app.setWindowIcon()` posé sur `QApplication` (multi-tailles) + `setDesktopFileName()` - Page About : icône 96 → 86 px (−10 %), texte en blanc sur fond sombre `#1c2833` --- ## [0.1.0] — 2026-06-01 ### Ajouté - Interface graphique PyQt6 avec icône systray (Linux & Windows) - **Mode User** (défaut) : connexion / déconnexion WireGuard en un clic, statut en temps réel - **Mode Admin** (`--admin` ou via le menu) protégé par mot de passe - Panneau Admin avec 5 onglets : - **WireGuard** : configuration serveur (adresse, port UDP, clé publique, DNS, IP client) - **Clés** : génération de paires Curve25519 (clé privée / publique), aperçu config exportable - **MFA** : génération de secret TOTP, QR Code compatible Google Authenticator / Aegis - **Test connexion** : vérification UDP du serveur avant tunnel - **Sécurité** : gestion du mot de passe administrateur (SHA-256 + salt) - Surcouche MFA : dialogue TOTP avec minuterie de validité (fenêtre glissante ±1) - Génération de clés WireGuard via `cryptography` (X25519, sans `wg` binaire) - Écriture automatique du fichier `.conf` WireGuard avec permissions `0600` - Connexion via `wg-quick` (Linux) ou `wireguard /installtunnel` (Windows) - Statut temps réel : trafic RX/TX, dernier handshake - Réduction dans le systray à la fermeture de la fenêtre principale - Configuration persistante JSON (`~/.wgsecure/config.json`) --- *Versions planifiées :* - `0.3.0` — Import/export de profils WireGuard (.conf), support multi-profils - `0.4.0` — MFA par clé matérielle (FIDO2/YubiKey) - `0.5.0` — Paquet installable (Windows .exe / Linux .deb)