This commit was merged in pull request #26.
This commit is contained in:
@@ -8,6 +8,7 @@ depuis les variables d'environnement (préfixées par groupe) et le fichier
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
from datetime import date
|
||||
from typing import Literal
|
||||
from urllib.parse import urlparse
|
||||
@@ -18,6 +19,7 @@ from pydantic import (
|
||||
ValidationInfo,
|
||||
field_serializer,
|
||||
field_validator,
|
||||
model_validator,
|
||||
)
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
@@ -158,10 +160,16 @@ class XmppSettings(BaseSettings):
|
||||
Contraintes de champs : ``port`` est borné entre 1 et 65535 et ``timeout``
|
||||
doit être strictement positif.
|
||||
|
||||
Politique TLS : la désactivation de TLS (``use_tls`` à ``False``) n'est
|
||||
autorisée que sur un hôte de boucle locale (``localhost``, ``127.0.0.1``,
|
||||
``::1``). Dans tout autre cas, une erreur de validation est levée,
|
||||
indépendamment de l'état du champ ``enabled``.
|
||||
Politique TLS : le mode ``tls_mode`` détermine la négociation TLS
|
||||
(``direct``, ``starttls`` ou ``disabled``). Le mode ``disabled`` n'est
|
||||
autorisé que sur un hôte de boucle locale (``localhost``, ``127.0.0.1``,
|
||||
``::1``) ; ``starttls`` et ``direct`` sont permis pour tous les hôtes.
|
||||
|
||||
Compatibilité : le champ historique ``use_tls`` (booléen) est un alias
|
||||
obsolète ; ``use_tls=True`` mappe vers ``tls_mode="direct"`` et
|
||||
``use_tls=False`` vers ``tls_mode="starttls"``, avec un
|
||||
:pyexc:`DeprecationWarning`. La valeur brute fournie reste lisible via
|
||||
``use_tls`` (``None`` si non fournie).
|
||||
"""
|
||||
|
||||
model_config = SettingsConfigDict(
|
||||
@@ -178,33 +186,61 @@ class XmppSettings(BaseSettings):
|
||||
port: int = Field(default=5222, ge=1, le=65535)
|
||||
to: str | None = None
|
||||
resource: str = "pronote-sync"
|
||||
use_tls: bool = True
|
||||
timeout: int = Field(default=30, gt=0)
|
||||
tls_mode: Literal["direct", "starttls", "disabled"] = "starttls"
|
||||
use_tls: bool | None = Field(
|
||||
default=None,
|
||||
deprecated="Utiliser tls_mode à la place (XMPP_USE_TLS obsolète).",
|
||||
)
|
||||
timeout: float = Field(default=30, gt=0)
|
||||
connect_timeout: float = Field(default=15, gt=0)
|
||||
cleanup_timeout: float = Field(default=10, gt=0)
|
||||
|
||||
@field_validator("use_tls")
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def _validate_tls_policy(cls, v: bool, info: ValidationInfo) -> bool:
|
||||
"""Refuse la désactivation de TLS hors des hôtes de boucle locale.
|
||||
def _migrate_use_tls(cls, data: object) -> object:
|
||||
"""Mappe l'alias obsolète ``use_tls`` vers le mode canonique ``tls_mode``.
|
||||
|
||||
La règle s'applique quel que soit l'état du champ ``enabled``. Le
|
||||
message d'erreur ne contient aucune valeur sensible (``jid``,
|
||||
``use_tls=True`` devient ``tls_mode="direct"`` et ``use_tls=False``
|
||||
devient ``tls_mode="starttls"`` ; un :pyexc:`DeprecationWarning` est
|
||||
émis à chaque usage explicite de l'alias. ``tls_mode`` fourni
|
||||
explicitement prend le pas sur l'alias.
|
||||
|
||||
:param data: Données d'entrée du modèle (dict ou autre).
|
||||
:return: Données d'entrée avec ``tls_mode`` dérivé de ``use_tls``.
|
||||
:rtype: object
|
||||
"""
|
||||
if not isinstance(data, dict) or "use_tls" not in data:
|
||||
return data
|
||||
warnings.warn(
|
||||
"XMPP_USE_TLS est obsolète : utiliser XMPP_TLS_MODE "
|
||||
"('direct', 'starttls' ou 'disabled').",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
if data.get("tls_mode") is None:
|
||||
data["tls_mode"] = "direct" if data["use_tls"] else "starttls"
|
||||
return data
|
||||
|
||||
@model_validator(mode="after")
|
||||
def _validate_tls_policy(self) -> XmppSettings:
|
||||
"""Refuse le mode ``disabled`` hors des hôtes de boucle locale.
|
||||
|
||||
La règle s'applique quel que soit l'état du champ ``enabled``. Les
|
||||
modes ``starttls`` et ``direct`` sont autorisés pour tous les hôtes.
|
||||
Le message d'erreur ne contient aucune valeur sensible (``jid``,
|
||||
``password``, ``to``).
|
||||
|
||||
:param v: Valeur du champ ``use_tls`` à valider.
|
||||
:param info: Contexte de validation (accès aux autres champs).
|
||||
:return: La valeur validée inchangée.
|
||||
:rtype: bool
|
||||
:raises ValueError: Si ``use_tls`` est ``False`` et que ``host``
|
||||
:return: L'instance validée inchangée.
|
||||
:rtype: XmppSettings
|
||||
:raises ValueError: Si ``tls_mode`` est ``disabled`` et que ``host``
|
||||
n'est pas un hôte de boucle locale.
|
||||
"""
|
||||
if v is False:
|
||||
host = info.data.get("host", "")
|
||||
if host not in _XMPP_LOOPBACK_HOSTS:
|
||||
raise ValueError(
|
||||
"TLS désactivé n'est autorisé que sur les hôtes de loopback "
|
||||
"(localhost, 127.0.0.1, ::1)."
|
||||
) from None
|
||||
return v
|
||||
if self.tls_mode == "disabled" and self.host not in _XMPP_LOOPBACK_HOSTS:
|
||||
raise ValueError(
|
||||
"TLS désactivé n'est autorisé que sur les hôtes de loopback "
|
||||
"(localhost, 127.0.0.1, ::1)."
|
||||
) from None
|
||||
return self
|
||||
|
||||
|
||||
class AISettings(BaseSettings):
|
||||
|
||||
Reference in New Issue
Block a user