:drunk: No idea what did AI did
This commit is contained in:
81
DysonNetwork.Common/Models/AccountConnection.cs
Normal file
81
DysonNetwork.Common/Models/AccountConnection.cs
Normal file
@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Common.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a connection between an account and an authentication provider
|
||||
/// </summary>
|
||||
public class AccountConnection
|
||||
{
|
||||
/// <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>
|
||||
public string? AccountId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The authentication provider (e.g., "google", "github")
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
public string Provider { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The unique identifier for the user from the provider
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(256)]
|
||||
public string ProvidedIdentifier { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Display name for the connection
|
||||
/// </summary>
|
||||
[MaxLength(100)]
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OAuth access token from the provider
|
||||
/// </summary>
|
||||
public string? AccessToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OAuth refresh token from the provider (if available)
|
||||
/// </summary>
|
||||
public string? RefreshToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the access token expires (if available)
|
||||
/// </summary>
|
||||
public Instant? ExpiresAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the connection was first established
|
||||
/// </summary>
|
||||
public Instant CreatedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the connection was last used
|
||||
/// </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))]
|
||||
public virtual Account? Account { get; set; }
|
||||
}
|
@ -65,4 +65,26 @@ public class AuthChallenge : ModelBase
|
||||
if (StepRemain == 0 && BlacklistFactors.Count == 0) StepRemain = StepTotal;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AuthTokens
|
||||
{
|
||||
public string AccessToken { get; set; } = string.Empty;
|
||||
public string RefreshToken { get; set; } = string.Empty;
|
||||
public int ExpiresIn { get; set; }
|
||||
public string TokenType { get; set; } = "Bearer";
|
||||
public string? Scope { get; set; }
|
||||
public string? IdToken { get; set; }
|
||||
|
||||
public static AuthTokens Create(string accessToken, string refreshToken, int expiresIn, string? scope = null, string? idToken = null)
|
||||
{
|
||||
return new AuthTokens
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
RefreshToken = refreshToken,
|
||||
ExpiresIn = expiresIn,
|
||||
Scope = scope,
|
||||
IdToken = idToken
|
||||
};
|
||||
}
|
||||
}
|
74
DysonNetwork.Common/Models/Auth/Enums.cs
Normal file
74
DysonNetwork.Common/Models/Auth/Enums.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace DysonNetwork.Common.Models.Auth;
|
||||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public enum AuthChallengeType
|
||||
{
|
||||
// Authentication challenges
|
||||
Password = 0,
|
||||
EmailCode = 1,
|
||||
PhoneCode = 2,
|
||||
Totp = 3,
|
||||
WebAuthn = 4,
|
||||
RecoveryCode = 5,
|
||||
|
||||
// Authorization challenges
|
||||
Consent = 10,
|
||||
TwoFactor = 11,
|
||||
|
||||
// Account recovery challenges
|
||||
ResetPassword = 20,
|
||||
VerifyEmail = 21,
|
||||
VerifyPhone = 22,
|
||||
|
||||
// Security challenges
|
||||
Reauthentication = 30,
|
||||
DeviceVerification = 31,
|
||||
|
||||
// Custom challenges
|
||||
Custom = 100
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public enum AuthChallengePlatform
|
||||
{
|
||||
Web = 0,
|
||||
Ios = 1,
|
||||
Android = 2,
|
||||
Desktop = 3,
|
||||
Api = 4,
|
||||
Cli = 5,
|
||||
Sdk = 6,
|
||||
|
||||
// Special platforms
|
||||
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
|
||||
}
|
10
DysonNetwork.Common/Models/LastActiveInfo.cs
Normal file
10
DysonNetwork.Common/Models/LastActiveInfo.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Common.Models;
|
||||
|
||||
public class LastActiveInfo
|
||||
{
|
||||
public string SessionId { get; set; } = string.Empty;
|
||||
public string AccountId { get; set; } = string.Empty;
|
||||
public Instant SeenAt { get; set; }
|
||||
}
|
114
DysonNetwork.Common/Models/OidcUserInfo.cs
Normal file
114
DysonNetwork.Common/Models/OidcUserInfo.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DysonNetwork.Common.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents user information from an OIDC provider
|
||||
/// </summary>
|
||||
public class OidcUserInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique identifier for the user from the OIDC provider
|
||||
/// </summary>
|
||||
public string? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's email address
|
||||
/// </summary>
|
||||
public string? Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the user's email has been verified by the OIDC provider
|
||||
/// </summary>
|
||||
public bool EmailVerified { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's given name (first name)
|
||||
/// </summary>
|
||||
public string? GivenName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's family name (last name)
|
||||
/// </summary>
|
||||
public string? FamilyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's full name
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's preferred username
|
||||
/// </summary>
|
||||
public string? PreferredUsername { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// URL to the user's profile picture
|
||||
/// </summary>
|
||||
public string? Picture { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The OIDC provider name (e.g., "google", "github")
|
||||
/// </summary>
|
||||
public string? Provider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OAuth access token from the provider
|
||||
/// </summary>
|
||||
public string? AccessToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OAuth refresh token from the provider (if available)
|
||||
/// </summary>
|
||||
public string? RefreshToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the access token expires (if available)
|
||||
/// </summary>
|
||||
public DateTimeOffset? ExpiresAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional claims from the ID token or user info endpoint
|
||||
/// </summary>
|
||||
public Dictionary<string, object>? Claims { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Converts the user info to a metadata dictionary for storage
|
||||
/// </summary>
|
||||
public Dictionary<string, object> ToMetadata()
|
||||
{
|
||||
var metadata = new Dictionary<string, object>();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(UserId))
|
||||
metadata["user_id"] = UserId;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Email))
|
||||
metadata["email"] = Email;
|
||||
|
||||
metadata["email_verified"] = EmailVerified;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(GivenName))
|
||||
metadata["given_name"] = GivenName;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(FamilyName))
|
||||
metadata["family_name"] = FamilyName;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Name))
|
||||
metadata["name"] = Name;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(PreferredUsername))
|
||||
metadata["preferred_username"] = PreferredUsername;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Picture))
|
||||
metadata["picture"] = Picture;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Provider))
|
||||
metadata["provider"] = Provider;
|
||||
|
||||
if (ExpiresAt.HasValue)
|
||||
metadata["expires_at"] = ExpiresAt.Value;
|
||||
|
||||
return metadata;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user