using ColaFlow.Shared.Kernel.Common; using ColaFlow.Modules.Identity.Domain.Aggregates.Users; namespace ColaFlow.Modules.Identity.Domain.Entities; /// /// Password reset token entity with enhanced security. /// Lifetime: 1 hour (short expiration for security). /// Single-use only (cannot be reused). /// public sealed class PasswordResetToken : Entity { public UserId UserId { get; private set; } = null!; public string TokenHash { get; private set; } = string.Empty; public DateTime ExpiresAt { get; private set; } public DateTime? UsedAt { get; private set; } public string? IpAddress { get; private set; } public string? UserAgent { get; private set; } public DateTime CreatedAt { get; private set; } // Private constructor for EF Core private PasswordResetToken() : base() { } /// /// Factory method to create new password reset token. /// /// User ID requesting password reset /// SHA-256 hash of the reset token /// Expiration time (typically 1 hour from creation) /// IP address of the requester /// User agent of the requester /// New password reset token instance public static PasswordResetToken Create( UserId userId, string tokenHash, DateTime expiresAt, string? ipAddress = null, string? userAgent = null) { return new PasswordResetToken { Id = Guid.NewGuid(), UserId = userId, TokenHash = tokenHash, ExpiresAt = expiresAt, IpAddress = ipAddress, UserAgent = userAgent, CreatedAt = DateTime.UtcNow }; } /// /// Check if token has expired. /// public bool IsExpired => DateTime.UtcNow > ExpiresAt; /// /// Check if token has been used. /// public bool IsUsed => UsedAt.HasValue; /// /// Check if token is valid (not expired and not used). /// public bool IsValid => !IsExpired && !IsUsed; /// /// Mark the token as used. /// Can only be used once for security. /// /// Thrown if token is not valid public void MarkAsUsed() { if (!IsValid) throw new InvalidOperationException("Token is not valid for password reset"); UsedAt = DateTime.UtcNow; } }