using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json; using System.Text.Json.Serialization; using DysonNetwork.Common.Models.Auth; using DysonNetwork.Pass.Models; using NetTopologySuite.Geometries; using NodaTime; namespace DysonNetwork.Pass.Features.Auth.Models; public class AuthChallenge : ModelBase { [Required] public Guid AccountId { get; set; } [ForeignKey(nameof(AccountId))] [JsonIgnore] public virtual Account Account { get; set; } = null!; [Required] [Column(TypeName = "varchar(50)")] public AuthChallengeType Type { get; set; } [Required] [Column(TypeName = "varchar(50)")] public AuthChallengePlatform Platform { get; set; } public Instant? ExpiredAt { get; set; } [Required] public int StepRemain { get; set; } = 1; [Required] public int StepTotal { get; set; } = 1; [Required] public int FailedAttempts { get; set; } = 0; [MaxLength(128)] public string? IpAddress { get; set; } [MaxLength(512)] public string? UserAgent { get; set; } [MaxLength(256)] public string? DeviceId { get; set; } [MaxLength(1024)] public string? Nonce { get; set; } [Column(TypeName = "jsonb")] public JsonDocument? BlacklistFactors { get; set; } [Column(TypeName = "jsonb")] public JsonDocument? Audiences { get; set; } [Column(TypeName = "jsonb")] public JsonDocument? Scopes { get; set; } [NotMapped] public Point? Location { get; set; } // Navigation property for AuthSession [JsonIgnore] public virtual ICollection Sessions { get; set; } = new List(); public bool IsExpired() => ExpiredAt != null && SystemClock.Instance.GetCurrentInstant() >= ExpiredAt.Value; public bool CanAttempt(int maxAttempts = 5) => !IsExpired() && FailedAttempts < maxAttempts; public void RecordAttempt() { if (IsExpired()) return; FailedAttempts++; } public void UpdateStep(int step, int totalSteps) { StepRemain = step; StepTotal = totalSteps; } public void UpdateExpiration(Instant? expiresAt) { ExpiredAt = expiresAt; } public void UpdateBlacklistFactors(IEnumerable factors) { BlacklistFactors = JsonSerializer.SerializeToDocument(factors); } public void UpdateAudiences(IEnumerable audiences) { Audiences = JsonSerializer.SerializeToDocument(audiences); } public void UpdateScopes(IEnumerable scopes) { Scopes = JsonSerializer.SerializeToDocument(scopes); } public void UpdateLocation(double? latitude, double? longitude) { if (latitude.HasValue && longitude.HasValue) { Location = new Point(longitude.Value, latitude.Value) { SRID = 4326 }; } } public void UpdateDeviceInfo(string? ipAddress, string? userAgent, string? deviceId = null) { IpAddress = ipAddress; UserAgent = userAgent; DeviceId = deviceId; } }