========================== Identity — OTP / 2FA ========================== Le module OTP implémente l'authentification multi-facteurs avec trois canaux : email, TOTP (RFC 6238), et codes de récupération statiques. Module : ``src.module.identity.domain.otp_service`` .. module:: src.module.identity.domain.otp_service :synopsis: Pipeline OTP complet (email, TOTP, codes statiques) OTP par Email ============= .. function:: generate_email_otp(user, device) -> str Génère un code OTP à 6 chiffres et l'envoie par email. 1. Crée un ``OTPChallenge`` avec TTL configurable (``OTP_EMAIL_TOKEN_VALIDITY_SECONDS``) 2. Envoie l'email avec le code 3. Retourne le code (pour les tests) :param user: Utilisateur cible :param device: OTPDevice de type ``"email"`` :returns: Code OTP généré .. function:: verify_email_otp(device, code: str) -> bool Vérifie un code OTP email. - Cherche un ``OTPChallenge`` non utilisé et non expiré - Marque le challenge comme utilisé - Retourne ``True`` si le code est valide :param device: OTPDevice de type ``"email"`` :param code: Code à vérifier :returns: ``True`` si valide TOTP (Time-based One-Time Password) ===================================== Implémentation conforme à la `RFC 6238 `_ utilisant HMAC-SHA1 avec des pas de 30 secondes. .. function:: setup_totp(user) -> tuple[OTPDevice, str] Initialise un dispositif TOTP. 1. Génère un secret aléatoire base32 2. Crée un ``OTPDevice`` non confirmé 3. Retourne le dispositif et l'URI ``otpauth://`` pour les QR codes :returns: Tuple ``(device, provisioning_uri)`` .. code-block:: python device, uri = setup_totp(user) # uri = "otpauth://totp/updo:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=updo" # Afficher comme QR code pour Google Authenticator / Authy .. function:: confirm_totp(device, code: str) -> bool Confirme un dispositif TOTP en vérifiant le premier code. - Vérifie le code TOTP contre le secret stocké - Si valide, marque le dispositif comme ``is_confirmed=True`` - Émet ``OTPDeviceConfirmed`` :param device: OTPDevice TOTP non confirmé :param code: Code TOTP à 6 chiffres :returns: ``True`` si confirmé avec succès .. function:: verify_totp(device, code: str) -> bool Vérifie un code TOTP. Accepte le code courant et les codes des fenêtres adjacentes (±1 pas) pour compenser le décalage d'horloge. :param device: OTPDevice TOTP confirmé :param code: Code TOTP à 6 chiffres :returns: ``True`` si valide Codes de récupération statiques ================================ .. function:: generate_static_codes(user, count: int = 10) -> list[str] Génère un ensemble de codes de récupération à usage unique. :param user: Utilisateur cible :param count: Nombre de codes (défaut: ``OTP_STATIC_TOKEN_COUNT``) :returns: Liste de codes alphanumériques .. code-block:: python codes = generate_static_codes(user) # ['ABC12345', 'DEF67890', 'GHI24680', ...] # L'utilisateur doit les sauvegarder en lieu sûr .. function:: verify_static_code(device, code: str) -> bool Vérifie et consomme un code de récupération. - Cherche le code dans la liste stockée - Le supprime de la liste (usage unique) - Retourne ``True`` si trouvé :param device: OTPDevice de type ``"static"`` :param code: Code de récupération :returns: ``True`` si valide et consommé Fonction unifiée ================ .. function:: verify_otp(user, code: str, device_type: str | None = None) -> bool Point d'entrée unifié pour la vérification OTP. Essaie les dispositifs actifs dans l'ordre : 1. TOTP (si ``device_type`` est ``None`` ou ``"totp"``) 2. Email (si ``device_type`` est ``None`` ou ``"email"``) 3. Static (si ``device_type`` est ``None`` ou ``"static"``) :param user: Utilisateur :param code: Code OTP :param device_type: Type spécifique à vérifier (optionnel) :returns: ``True`` si un dispositif valide le code Endpoints API ============= .. code-block:: text POST /api/v1/auth/otp/totp/setup/ → Initialise TOTP, retourne URI + secret POST /api/v1/auth/otp/totp/confirm/ → Confirme le dispositif TOTP POST /api/v1/auth/otp/email/send/ → Envoie un code OTP par email POST /api/v1/auth/otp/static/generate/ → Génère des codes de récupération POST /api/v1/auth/otp/verify/ → Vérifie un code OTP (tous types) GET /api/v1/auth/otp/devices/ → Liste les dispositifs OTP DELETE /api/v1/auth/otp/devices// → Supprime un dispositif Configuration ============= .. code-block:: python MULTITENANT = { 'OTP_ENABLED': True, 'OTP_EMAIL_ENABLED': True, 'OTP_TOTP_ENABLED': True, 'OTP_STATIC_ENABLED': True, 'OTP_EMAIL_TOKEN_VALIDITY_SECONDS': 300, # 5 minutes 'OTP_TOTP_ISSUER_NAME': 'updo', 'OTP_STATIC_TOKEN_COUNT': 10, 'OTP_REQUIRED_FOR_LOGIN': False, }