:drunk: AI trying to fix bugs
This commit is contained in:
@ -7,6 +7,15 @@ using OtpNet;
|
||||
|
||||
namespace DysonNetwork.Common.Models;
|
||||
|
||||
public enum AccountStatus
|
||||
{
|
||||
PendingActivation,
|
||||
Active,
|
||||
Suspended,
|
||||
Banned,
|
||||
Deleted
|
||||
}
|
||||
|
||||
[Index(nameof(Name), IsUnique = true)]
|
||||
public class Account : ModelBase
|
||||
{
|
||||
@ -30,6 +39,47 @@ public class Account : ModelBase
|
||||
[JsonIgnore] public ICollection<Relationship> IncomingRelationships { get; set; } = new List<Relationship>();
|
||||
|
||||
[JsonIgnore] public ICollection<Subscription> Subscriptions { get; set; } = new List<Subscription>();
|
||||
|
||||
public AccountStatus Status { get; set; } = AccountStatus.PendingActivation;
|
||||
|
||||
[NotMapped]
|
||||
public string? Email => GetPrimaryEmail();
|
||||
|
||||
public string? GetPrimaryEmail()
|
||||
{
|
||||
return Contacts
|
||||
.FirstOrDefault(c => c.Type == AccountContactType.Email && c.IsPrimary)
|
||||
?.Content;
|
||||
}
|
||||
|
||||
public void SetPrimaryEmail(string email)
|
||||
{
|
||||
// Remove primary flag from existing primary email if any
|
||||
foreach (var contact in Contacts.Where(c => c.Type == AccountContactType.Email && c.IsPrimary))
|
||||
{
|
||||
contact.IsPrimary = false;
|
||||
}
|
||||
|
||||
// Find or create the email contact
|
||||
var emailContact = Contacts.FirstOrDefault(c =>
|
||||
c.Type == AccountContactType.Email &&
|
||||
string.Equals(c.Content, email, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (emailContact == null)
|
||||
{
|
||||
emailContact = new AccountContact
|
||||
{
|
||||
Type = AccountContactType.Email,
|
||||
Content = email,
|
||||
IsPrimary = true
|
||||
};
|
||||
Contacts.Add(emailContact);
|
||||
}
|
||||
else
|
||||
{
|
||||
emailContact.IsPrimary = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Leveling
|
||||
@ -128,11 +178,28 @@ public class AccountAuthFactor : ModelBase
|
||||
/// </summary>
|
||||
public int Trustworthy { get; set; } = 1;
|
||||
|
||||
[MaxLength(100)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(500)]
|
||||
public string? Description { get; set; }
|
||||
|
||||
public bool IsDefault { get; set; }
|
||||
public bool IsBackup { get; set; }
|
||||
public Instant? LastUsedAt { get; set; }
|
||||
public Instant? EnabledAt { get; set; }
|
||||
public Instant? ExpiredAt { get; set; }
|
||||
public Instant? DisabledAt { get; set; }
|
||||
|
||||
[Column(TypeName = "jsonb")]
|
||||
public Dictionary<string, object>? Metadata { get; set; }
|
||||
|
||||
public Guid AccountId { get; set; }
|
||||
[JsonIgnore] public Account Account { get; set; } = null!;
|
||||
|
||||
// Navigation property for related AuthSessions
|
||||
[JsonIgnore]
|
||||
public virtual ICollection<AuthSession>? Sessions { get; set; }
|
||||
|
||||
public AccountAuthFactor HashSecret(int cost = 12)
|
||||
{
|
||||
@ -174,20 +241,5 @@ public enum AccountAuthFactorType
|
||||
EmailCode,
|
||||
InAppCode,
|
||||
TimedCode,
|
||||
PinCode,
|
||||
}
|
||||
|
||||
public class AccountConnection : ModelBase
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
[MaxLength(4096)] public string Provider { get; set; } = null!;
|
||||
[MaxLength(8192)] public string ProvidedIdentifier { get; set; } = null!;
|
||||
[Column(TypeName = "jsonb")] public Dictionary<string, object>? Meta { get; set; } = new();
|
||||
|
||||
[JsonIgnore] [MaxLength(4096)] public string? AccessToken { get; set; }
|
||||
[JsonIgnore] [MaxLength(4096)] public string? RefreshToken { get; set; }
|
||||
public Instant? LastUsedAt { get; set; }
|
||||
|
||||
public Guid AccountId { get; set; }
|
||||
public Account Account { get; set; } = null!;
|
||||
PinCode
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Common.Models;
|
||||
@ -8,15 +10,8 @@ namespace DysonNetwork.Common.Models;
|
||||
/// <summary>
|
||||
/// Represents a connection between an account and an authentication provider
|
||||
/// </summary>
|
||||
public class AccountConnection
|
||||
public class AccountConnection : ModelBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique identifier for the connection
|
||||
/// </summary>
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public string Id { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The account ID this connection is associated with
|
||||
/// </summary>
|
||||
@ -36,6 +31,16 @@ public class AccountConnection
|
||||
[MaxLength(256)]
|
||||
public string ProvidedIdentifier { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Alias for ProvidedIdentifier for backward compatibility
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public string ProviderId
|
||||
{
|
||||
get => ProvidedIdentifier;
|
||||
set => ProvidedIdentifier = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display name for the connection
|
||||
/// </summary>
|
||||
@ -57,6 +62,27 @@ public class AccountConnection
|
||||
/// </summary>
|
||||
public Instant? ExpiresAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Raw profile data from the provider
|
||||
/// </summary>
|
||||
[Column(TypeName = "jsonb")]
|
||||
public JsonDocument? ProfileData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the connection was first established
|
||||
/// </summary>
|
||||
public Instant ConnectedAt { get; set; } = SystemClock.Instance.GetCurrentInstant();
|
||||
|
||||
/// <summary>
|
||||
/// Additional metadata about the connection
|
||||
/// </summary>
|
||||
[Column(TypeName = "jsonb")]
|
||||
public JsonDocument? Metadata { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the connection is currently active
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
/// <summary>
|
||||
/// When the connection was first established
|
||||
/// </summary>
|
||||
@ -67,15 +93,33 @@ public class AccountConnection
|
||||
/// </summary>
|
||||
public Instant? LastUsedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional metadata about the connection
|
||||
/// </summary>
|
||||
[Column(TypeName = "jsonb")]
|
||||
public Dictionary<string, object>? Meta { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Navigation property for the associated account
|
||||
/// </summary>
|
||||
[ForeignKey(nameof(AccountId))]
|
||||
[JsonIgnore]
|
||||
public virtual Account? Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates the connection's tokens and related metadata
|
||||
/// </summary>
|
||||
/// <param name="accessToken">The new access token</param>
|
||||
/// <param name="refreshToken">The new refresh token, if any</param>
|
||||
/// <param name="expiresAt">When the access token expires, if any</param>
|
||||
public void UpdateTokens(string? accessToken, string? refreshToken, Instant? expiresAt)
|
||||
{
|
||||
AccessToken = accessToken;
|
||||
|
||||
if (!string.IsNullOrEmpty(refreshToken))
|
||||
{
|
||||
RefreshToken = refreshToken;
|
||||
}
|
||||
|
||||
if (expiresAt.HasValue)
|
||||
{
|
||||
ExpiresAt = expiresAt;
|
||||
}
|
||||
|
||||
LastUsedAt = SystemClock.Instance.GetCurrentInstant();
|
||||
}
|
||||
}
|
||||
|
47
DysonNetwork.Common/Models/Auth/AuthFactorType.cs
Normal file
47
DysonNetwork.Common/Models/Auth/AuthFactorType.cs
Normal file
@ -0,0 +1,47 @@
|
||||
namespace DysonNetwork.Common.Models.Auth;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the different types of authentication factors that can be used for multi-factor authentication.
|
||||
/// </summary>
|
||||
public enum AuthFactorType
|
||||
{
|
||||
/// <summary>
|
||||
/// Password-based authentication factor.
|
||||
/// </summary>
|
||||
Password = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Time-based One-Time Password (TOTP) authentication factor.
|
||||
/// </summary>
|
||||
Totp = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Email-based authentication factor.
|
||||
/// </summary>
|
||||
Email = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Phone/SMS-based authentication factor.
|
||||
/// </summary>
|
||||
Phone = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Security key (FIDO2/WebAuthn) authentication factor.
|
||||
/// </summary>
|
||||
SecurityKey = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Recovery code authentication factor.
|
||||
/// </summary>
|
||||
RecoveryCode = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Backup code authentication factor.
|
||||
/// </summary>
|
||||
BackupCode = 6,
|
||||
|
||||
/// <summary>
|
||||
/// OpenID Connect (OIDC) authentication factor.
|
||||
/// </summary>
|
||||
Oidc = 7
|
||||
}
|
@ -45,30 +45,3 @@ public enum AuthChallengePlatform
|
||||
System = 100,
|
||||
Unknown = 999
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public enum AuthFactorType
|
||||
{
|
||||
Password = 0,
|
||||
EmailCode = 1,
|
||||
PhoneCode = 2,
|
||||
Totp = 3,
|
||||
WebAuthn = 4,
|
||||
RecoveryCode = 5,
|
||||
|
||||
// Social and federation
|
||||
Google = 10,
|
||||
Apple = 11,
|
||||
Microsoft = 12,
|
||||
Facebook = 13,
|
||||
Twitter = 14,
|
||||
Github = 15,
|
||||
|
||||
// Enterprise
|
||||
Saml = 50,
|
||||
Oidc = 51,
|
||||
Ldap = 52,
|
||||
|
||||
// Custom factor types
|
||||
Custom = 100
|
||||
}
|
||||
|
@ -1,10 +1,33 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Common.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all entity models in the system.
|
||||
/// Provides common properties and functionality for tracking entity lifecycle.
|
||||
/// </summary>
|
||||
public abstract class ModelBase
|
||||
{
|
||||
public Instant CreatedAt { get; set; }
|
||||
public Instant UpdatedAt { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the unique identifier for the entity.
|
||||
/// </summary>
|
||||
[Key]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date and time when the entity was created, in UTC.
|
||||
/// </summary>
|
||||
public Instant CreatedAt { get; set; } = SystemClock.Instance.GetCurrentInstant();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date and time when the entity was last updated, in UTC.
|
||||
/// </summary>
|
||||
public Instant UpdatedAt { get; set; } = SystemClock.Instance.GetCurrentInstant();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date and time when the entity was soft-deleted, in UTC.
|
||||
/// Null if the entity has not been deleted.
|
||||
/// </summary>
|
||||
public Instant? DeletedAt { get; set; }
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace DysonNetwork.Common.Models;
|
||||
|
||||
|
Reference in New Issue
Block a user