"""Security models: Token and AuthEvent.""" from typing import Optional from pydantic import BaseModel, Field, ConfigDict from modules.shared.attributeUtils import register_model_labels, ModelMixin from modules.shared.timezoneUtils import get_utc_timestamp from .datamodelUam import AuthAuthority from enum import Enum import uuid class TokenStatus(str, Enum): ACTIVE = "active" REVOKED = "revoked" class Token(BaseModel, ModelMixin): id: Optional[str] = None userId: str authority: AuthAuthority connectionId: Optional[str] = Field( None, description="ID of the connection this token belongs to" ) tokenAccess: str tokenType: str = "bearer" expiresAt: float = Field( description="When the token expires (UTC timestamp in seconds)" ) tokenRefresh: Optional[str] = None createdAt: Optional[float] = Field( None, description="When the token was created (UTC timestamp in seconds)" ) status: TokenStatus = Field( default=TokenStatus.ACTIVE, description="Token status: active/revoked" ) revokedAt: Optional[float] = Field( None, description="When the token was revoked (UTC timestamp in seconds)" ) revokedBy: Optional[str] = Field( None, description="User ID who revoked the token (admin/self)" ) reason: Optional[str] = Field(None, description="Optional revocation reason") sessionId: Optional[str] = Field( None, description="Logical session grouping for logout revocation" ) mandateId: Optional[str] = Field( None, description="Mandate ID for tenant scoping of the token" ) model_config = ConfigDict(use_enum_values=True) register_model_labels( "Token", {"en": "Token", "fr": "Jeton"}, { "id": {"en": "ID", "fr": "ID"}, "userId": {"en": "User ID", "fr": "ID utilisateur"}, "authority": {"en": "Authority", "fr": "Autorité"}, "connectionId": {"en": "Connection ID", "fr": "ID de connexion"}, "tokenAccess": {"en": "Access Token", "fr": "Jeton d'accès"}, "tokenType": {"en": "Token Type", "fr": "Type de jeton"}, "expiresAt": {"en": "Expires At", "fr": "Expire le"}, "tokenRefresh": {"en": "Refresh Token", "fr": "Jeton de rafraîchissement"}, "createdAt": {"en": "Created At", "fr": "Créé le"}, "status": {"en": "Status", "fr": "Statut"}, "revokedAt": {"en": "Revoked At", "fr": "Révoqué le"}, "revokedBy": {"en": "Revoked By", "fr": "Révoqué par"}, "reason": {"en": "Reason", "fr": "Raison"}, "sessionId": {"en": "Session ID", "fr": "ID de session"}, "mandateId": {"en": "Mandate ID", "fr": "ID de mandat"}, }, ) class AuthEvent(BaseModel, ModelMixin): id: str = Field( default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the auth event", frontend_type="text", frontend_readonly=True, frontend_required=False, ) userId: str = Field( description="ID of the user this event belongs to", frontend_type="text", frontend_readonly=True, frontend_required=True, ) eventType: str = Field( description="Type of authentication event (e.g., 'login', 'logout', 'token_refresh')", frontend_type="text", frontend_readonly=True, frontend_required=True, ) timestamp: float = Field( default_factory=get_utc_timestamp, description="Unix timestamp when the event occurred", frontend_type="datetime", frontend_readonly=True, frontend_required=True, ) ipAddress: Optional[str] = Field( default=None, description="IP address from which the event originated", frontend_type="text", frontend_readonly=True, frontend_required=False, ) userAgent: Optional[str] = Field( default=None, description="User agent string from the request", frontend_type="text", frontend_readonly=True, frontend_required=False, ) success: bool = Field( default=True, description="Whether the authentication event was successful", frontend_type="boolean", frontend_readonly=True, frontend_required=True, ) details: Optional[str] = Field( default=None, description="Additional details about the event", frontend_type="text", frontend_readonly=True, frontend_required=False, ) register_model_labels( "AuthEvent", {"en": "Authentication Event", "fr": "Événement d'authentification"}, { "id": {"en": "ID", "fr": "ID"}, "userId": {"en": "User ID", "fr": "ID utilisateur"}, "eventType": {"en": "Event Type", "fr": "Type d'événement"}, "timestamp": {"en": "Timestamp", "fr": "Horodatage"}, "ipAddress": {"en": "IP Address", "fr": "Adresse IP"}, "userAgent": {"en": "User Agent", "fr": "Agent utilisateur"}, "success": {"en": "Success", "fr": "Succès"}, "details": {"en": "Details", "fr": "Détails"}, }, )