fix(auth): corriger les retours de revue du PIN Pronote

This commit is contained in:
2026-09-12 22:20:09 +02:00
31 changed files with 2422 additions and 634 deletions
+36 -7
View File
@@ -339,6 +339,7 @@ class PronoteClient:
if self._auth_state is not None:
creds = self._auth_state.load()
if creds is not None:
rotation_error: PronoteAuthRotationError | None = None
try:
account_pin = (
self._settings.account_pin.get_secret_value()
@@ -364,12 +365,16 @@ class PronoteClient:
redact_exception(exc, extra_secrets=_collect_auth_secrets(self)),
)
# Token expiré/invalide — pas de repli vers l'enrôlement QR
raise PronoteAuthRotationError(
rotation_error = PronoteAuthRotationError(
"Le token d'authentification Pronote est expiré ou invalide. "
"Action requise : supprimez le fichier .pronote_auth_state.json "
"et relancez avec un nouveau QR code (PRONOTE_QR_CODE_FILE + "
"PRONOTE_QR_PIN)."
) from None
)
if rotation_error is not None:
# Lever hors du bloc ``except`` évite de conserver l'erreur
# externe dans ``__context__``.
raise rotation_error from None
# Enrôlement : premier login via QR code (aucun credential persisté)
client = self._enroll_qr_code(client_class)
@@ -404,6 +409,7 @@ class PronoteClient:
) from None
# Read and validate QR code JSON
read_error: PronoteAuthRotationError | None = None
try:
qr_path = Path(qr_file)
qr_data: Any = json.loads(qr_path.read_text(encoding="utf-8"))
@@ -413,10 +419,14 @@ class PronoteClient:
redact_secrets(qr_file, extra_secrets=_collect_auth_secrets(self)),
redact_exception(exc, extra_secrets=_collect_auth_secrets(self)),
)
raise PronoteAuthRotationError(
read_error = PronoteAuthRotationError(
"Impossible de lire le fichier QR code : "
f"{redact_secrets(qr_file, extra_secrets=_collect_auth_secrets(self))}"
) from None
)
if read_error is not None:
# Lever hors du bloc ``except`` évite de conserver l'erreur
# externe dans ``__context__``.
raise read_error from None
# Validate required keys
for key in ("login", "jeton", "url"):
@@ -428,6 +438,7 @@ class PronoteClient:
pin_value = qr_pin.get_secret_value()
app_uuid = f"pronote-sync-{uuid4().hex}"
enrollment_error: PronoteAuthRotationError | None = None
try:
account_pin = (
self._settings.account_pin.get_secret_value()
@@ -445,11 +456,15 @@ class PronoteClient:
"Échec de l'enrôlement QR : %s",
redact_exception(exc, extra_secrets=_collect_auth_secrets(self)),
)
raise PronoteAuthRotationError(
enrollment_error = PronoteAuthRotationError(
"Échec de l'enrôlement par QR code : PIN invalide ou QR code expiré. "
"Générez un nouveau QR code dans l'application Pronote et mettez à "
"jour PRONOTE_QR_CODE_FILE."
) from None
)
if enrollment_error is not None:
# Lever hors du bloc ``except`` évite de conserver l'erreur
# externe dans ``__context__``.
raise enrollment_error from None
return client
@@ -502,9 +517,23 @@ class PronoteClient:
Chaque entrée est mappée sur un modèle :class:`Message` de type
``SURVEY`` si c'est un sondage, ``INFORMATION`` sinon.
:return: Liste des informations et sondages ; vide en cas d'erreur.
En mode ``qr_token``, la récupération est ignorée sans connexion ni
appel réseau : l'endpoint ``PageActualites`` renvoie une erreur
pronotepy 20 sur les instances HubEduConnect testées, provoquant un
refresh redondant du token. La méthode retourne alors immédiatement
une liste vide et journalise un message INFO unique ; ce comportement
n'est pas configurable.
:return: Liste des informations et sondages ; vide en cas d'erreur ou
en mode ``qr_token``.
:rtype: list[Message]
"""
if self._settings.auth_mode == "qr_token":
logger.info(
"Récupération des informations Pronote ignorée : endpoint "
"PageActualites indisponible en mode d'authentification qr_token."
)
return []
with self._qr_token_operation_lock():
try:
client = self._connect()