fix(ui): le bouton de saisie du code reparaît à l'expiration de l'accès (v0.8.5)
L'autorisation obtenue auprès du serveur a un terme, mais le client n'en tenait aucun compte : `access_until`, pourtant renvoyé à chaque validation, ne servait qu'à composer une ligne de journal. L'accès était marqué ouvert jusqu'à la chute du tunnel, si bien qu'une fois le délai écoulé l'interface affichait « Ouvert ✓ » et masquait le bouton comme l'entrée de systray — laissant l'utilisateur devant un réseau muet, sans issue visible, dans la situation même que ce bouton existe pour couvrir depuis la v0.8.2. L'échéance remonte désormais jusqu'à la fenêtre principale, qui la relit sans jamais la calculer : sa durée est un réglage serveur, que le poste n'a pas à deviner. Un serveur qui n'en annonce pas laisse l'accès ouvert jusqu'à la déconnexion, plutôt que de se voir imposer un terme inventé ici. Corrige au passage l'heure de fin, annoncée en UTC mais présentée comme locale — deux heures d'avance en été. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@ secret stocké sur le poste : elle ne verrouillait alors que sa propre
|
||||
interface. Ici le code part au serveur, seul détenteur du secret et seul
|
||||
point où l'accès est réellement ouvert ou refusé.
|
||||
|
||||
La requête part dans un `TaskWorker` : elle peut attendre jusqu'à dix
|
||||
La requête part dans un `ValueWorker` : elle peut attendre jusqu'à dix
|
||||
secondes si le serveur ne répond pas, et une fenêtre modale figée pendant
|
||||
ce temps donnerait l'impression d'une application plantée.
|
||||
"""
|
||||
@@ -24,7 +24,7 @@ from PyQt6.QtGui import QFont
|
||||
from app.core import vpn_session
|
||||
from app.core.config import Config
|
||||
from app.ui import theme
|
||||
from app.ui.worker import TaskWorker
|
||||
from app.ui.worker import ValueWorker
|
||||
|
||||
_TOTP_PERIOD = 30
|
||||
|
||||
@@ -34,13 +34,17 @@ class AccessCodeDialog(QDialog):
|
||||
|
||||
`message()` porte la réponse du serveur — succès comme refus — pour que
|
||||
l'appelant la journalise telle quelle plutôt qu'un message générique.
|
||||
`access_until()` porte l'échéance de l'autorisation obtenue : sans elle,
|
||||
l'appelant croirait l'accès ouvert indéfiniment et masquerait le moyen
|
||||
d'en redemander un une fois le délai écoulé.
|
||||
"""
|
||||
|
||||
def __init__(self, cfg: Config, parent=None):
|
||||
super().__init__(parent)
|
||||
self._cfg = cfg
|
||||
self._worker: TaskWorker | None = None
|
||||
self._worker: ValueWorker | None = None
|
||||
self._message = ""
|
||||
self._access_until = None
|
||||
self._username = ""
|
||||
self.setWindowTitle("WGSecure — Code d'accès")
|
||||
self.setFixedWidth(360)
|
||||
@@ -194,16 +198,22 @@ class AccessCodeDialog(QDialog):
|
||||
|
||||
self._error_label.setText("")
|
||||
self._set_busy(True)
|
||||
self._worker = TaskWorker(vpn_session.authenticate, self._cfg, raw,
|
||||
self._username, tag="auth", parent=self)
|
||||
self._worker = ValueWorker(vpn_session.authenticate, self._cfg, raw,
|
||||
self._username, parent=self)
|
||||
self._worker.done.connect(self._on_reply)
|
||||
self._worker.finished.connect(self._worker.deleteLater)
|
||||
self._worker.start()
|
||||
|
||||
def _on_reply(self, ok: bool, message: str, _tag: str):
|
||||
def _on_reply(self, result):
|
||||
self._worker = None
|
||||
self._message = message
|
||||
if ok:
|
||||
if result is None:
|
||||
# `ValueWorker` absorbe une exception imprévue en rendant None :
|
||||
# dire alors que l'échec vient d'ici, et non d'un refus serveur.
|
||||
result = vpn_session.AuthResult(
|
||||
False, "Échec inattendu de l'authentification.")
|
||||
self._message = result.message
|
||||
self._access_until = result.access_until
|
||||
if result.ok:
|
||||
# Enregistré seulement maintenant : un identifiant que le serveur
|
||||
# a refusé n'a rien à faire dans la configuration.
|
||||
if self._username:
|
||||
@@ -212,7 +222,7 @@ class AccessCodeDialog(QDialog):
|
||||
self.accept()
|
||||
return
|
||||
self._set_busy(False)
|
||||
self._fail(message)
|
||||
self._fail(result.message)
|
||||
self._code_input.clear()
|
||||
|
||||
def _fail(self, message: str):
|
||||
@@ -227,6 +237,10 @@ class AccessCodeDialog(QDialog):
|
||||
def message(self) -> str:
|
||||
return self._message
|
||||
|
||||
def access_until(self):
|
||||
"""Échéance annoncée par le serveur, ou None s'il n'en annonce pas."""
|
||||
return self._access_until
|
||||
|
||||
def closeEvent(self, event):
|
||||
self._timer.stop()
|
||||
super().closeEvent(event)
|
||||
|
||||
Reference in New Issue
Block a user