namespace SharepointToolbox.Web.Core.Models; public class AppUser { public string Id { get; set; } = Guid.NewGuid().ToString(); public string Email { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; public UserRole Role { get; set; } = UserRole.TechN0; /// Identity source. Entra = OIDC-provisioned, Local = password-based account. public AuthProvider Provider { get; set; } = AuthProvider.Entra; /// PasswordHasher output. Only set for users. public string? PasswordHash { get; set; } public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; public DateTimeOffset? LastLogin { get; set; } // ── Local-account brute-force lockout ─────────────────────────────────────── // Consecutive failed password attempts and, once the threshold is hit, the UTC // instant the account unlocks again. Only meaningful for AuthProvider.Local. // A per-account counter (not just an IP rate limiter) is the control that holds // up here: forwarded headers are trusted from any source, so an attacker who can // rotate X-Forwarded-For would evade IP-based throttling but not this. /// Consecutive failed local-login attempts since the last success. public int FailedLoginCount { get; set; } /// UTC instant the account unlocks; null when not locked. public DateTimeOffset? LockoutEndUtc { get; set; } }