♻️ Basically completed the separate of account service

This commit is contained in:
2025-07-12 11:40:18 +08:00
parent e76c80eead
commit ba49d1c7a7
69 changed files with 4245 additions and 225 deletions

View File

@@ -65,7 +65,7 @@ public class DysonTokenAuthHandler(
return AuthenticateResult.Fail("Invalid token.");
// Try to get session from cache first
var session = await cache.GetAsync<Session>($"{AuthCachePrefix}{sessionId}");
var session = await cache.GetAsync<AuthSession>($"{AuthCachePrefix}{sessionId}");
// If not in cache, load from database
if (session is null)

View File

@@ -27,7 +27,7 @@ public class AuthController(
}
[HttpPost("challenge")]
public async Task<ActionResult<Challenge>> StartChallenge([FromBody] ChallengeRequest request)
public async Task<ActionResult<AuthChallenge>> StartChallenge([FromBody] ChallengeRequest request)
{
var account = await accounts.LookupAccount(request.Account);
if (account is null) return NotFound("Account was not found.");
@@ -47,7 +47,7 @@ public class AuthController(
.FirstOrDefaultAsync();
if (existingChallenge is not null) return existingChallenge;
var challenge = new Challenge
var challenge = new AuthChallenge
{
ExpiredAt = Instant.FromDateTimeUtc(DateTime.UtcNow.AddHours(1)),
StepTotal = await auth.DetectChallengeRisk(Request, account),
@@ -72,7 +72,7 @@ public class AuthController(
}
[HttpGet("challenge/{id:guid}")]
public async Task<ActionResult<Challenge>> GetChallenge([FromRoute] Guid id)
public async Task<ActionResult<AuthChallenge>> GetChallenge([FromRoute] Guid id)
{
var challenge = await db.AuthChallenges
.Include(e => e.Account)
@@ -132,7 +132,7 @@ public class AuthController(
}
[HttpPatch("challenge/{id:guid}")]
public async Task<ActionResult<Challenge>> DoChallenge(
public async Task<ActionResult<AuthChallenge>> DoChallenge(
[FromRoute] Guid id,
[FromBody] PerformChallengeRequest request
)
@@ -236,7 +236,7 @@ public class AuthController(
if (session is not null)
return BadRequest("Session already exists for this challenge.");
session = new Session
session = new AuthSession
{
LastGrantedAt = Instant.FromDateTimeUtc(DateTime.UtcNow),
ExpiredAt = Instant.FromDateTimeUtc(DateTime.UtcNow.AddDays(30)),

View File

@@ -73,9 +73,9 @@ public class AuthService(
return totalRequiredSteps;
}
public async Task<Session> CreateSessionForOidcAsync(Account.Account account, Instant time, Guid? customAppId = null)
public async Task<AuthSession> CreateSessionForOidcAsync(Account.Account account, Instant time, Guid? customAppId = null)
{
var challenge = new Challenge
var challenge = new AuthChallenge
{
AccountId = account.Id,
IpAddress = HttpContext.Connection.RemoteIpAddress?.ToString(),
@@ -85,7 +85,7 @@ public class AuthService(
Type = customAppId is not null ? ChallengeType.OAuth : ChallengeType.Oidc
};
var session = new Session
var session = new AuthSession
{
AccountId = account.Id,
CreatedAt = time,
@@ -154,7 +154,7 @@ public class AuthService(
}
}
public string CreateToken(Session session)
public string CreateToken(AuthSession session)
{
// Load the private key for signing
var privateKeyPem = File.ReadAllText(config["AuthToken:PrivateKeyPath"]!);
@@ -183,7 +183,7 @@ public class AuthService(
return $"{payloadBase64}.{signatureBase64}";
}
public async Task<bool> ValidateSudoMode(Session session, string? pinCode)
public async Task<bool> ValidateSudoMode(AuthSession session, string? pinCode)
{
// Check if the session is already in sudo mode (cached)
var sudoModeKey = $"accounts:{session.Id}:sudo";

View File

@@ -7,7 +7,7 @@ public class CompactTokenService(IConfiguration config)
private readonly string _privateKeyPath = config["AuthToken:PrivateKeyPath"]
?? throw new InvalidOperationException("AuthToken:PrivateKeyPath configuration is missing");
public string CreateToken(Session session)
public string CreateToken(AuthSession session)
{
// Load the private key for signing
var privateKeyPem = File.ReadAllText(_privateKeyPath);

View File

@@ -114,7 +114,7 @@ public class OidcProviderController(
public async Task<IActionResult> GetUserInfo()
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser ||
HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized();
HttpContext.Items["CurrentSession"] is not AuthSession currentSession) return Unauthorized();
// Get requested scopes from the token
var scopes = currentSession.Challenge.Scopes;

View File

@@ -37,7 +37,7 @@ public class OidcProviderService(
.FirstOrDefaultAsync(c => c.Id == appId);
}
public async Task<Session?> FindValidSessionAsync(Guid accountId, Guid clientId)
public async Task<AuthSession?> FindValidSessionAsync(Guid accountId, Guid clientId)
{
var now = SystemClock.Instance.GetCurrentInstant();
@@ -76,7 +76,7 @@ public class OidcProviderService(
if (client == null)
throw new InvalidOperationException("Client not found");
Session session;
AuthSession session;
var clock = SystemClock.Instance;
var now = clock.GetCurrentInstant();
@@ -126,7 +126,7 @@ public class OidcProviderService(
private string GenerateJwtToken(
CustomApp client,
Session session,
AuthSession session,
Instant expiresAt,
IEnumerable<string>? scopes = null
)
@@ -199,7 +199,7 @@ public class OidcProviderService(
}
}
public async Task<Session?> FindSessionByIdAsync(Guid sessionId)
public async Task<AuthSession?> FindSessionByIdAsync(Guid sessionId)
{
return await db.AuthSessions
.Include(s => s.Account)
@@ -208,7 +208,7 @@ public class OidcProviderService(
.FirstOrDefaultAsync(s => s.Id == sessionId);
}
private static string GenerateRefreshToken(Session session)
private static string GenerateRefreshToken(AuthSession session)
{
return Convert.ToBase64String(session.Id.ToByteArray());
}
@@ -221,7 +221,7 @@ public class OidcProviderService(
}
public async Task<string> GenerateAuthorizationCodeForReuseSessionAsync(
Session session,
AuthSession session,
Guid clientId,
string redirectUri,
IEnumerable<string> scopes,

View File

@@ -68,7 +68,7 @@ public class OidcController(
/// Handles Apple authentication directly from mobile apps
/// </summary>
[HttpPost("apple/mobile")]
public async Task<ActionResult<Challenge>> AppleMobileLogin(
public async Task<ActionResult<AuthChallenge>> AppleMobileLogin(
[FromBody] AppleMobileSignInRequest request)
{
try

View File

@@ -187,7 +187,7 @@ public abstract class OidcService(
/// Creates a challenge and session for an authenticated user
/// Also creates or updates the account connection
/// </summary>
public async Task<Challenge> CreateChallengeForUserAsync(
public async Task<AuthChallenge> CreateChallengeForUserAsync(
OidcUserInfo userInfo,
Account.Account account,
HttpContext request,
@@ -217,7 +217,7 @@ public abstract class OidcService(
// Create a challenge that's already completed
var now = SystemClock.Instance.GetCurrentInstant();
var challenge = new Challenge
var challenge = new AuthChallenge
{
ExpiredAt = now.Plus(Duration.FromHours(1)),
StepTotal = await auth.DetectChallengeRisk(request.Request, account),

View File

@@ -2,12 +2,13 @@ using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
using DysonNetwork.Pass;
using DysonNetwork.Shared.Data;
using NodaTime;
using Point = NetTopologySuite.Geometries.Point;
namespace DysonNetwork.Pass.Auth;
public class Session : ModelBase
public class AuthSession : ModelBase
{
public Guid Id { get; set; } = Guid.NewGuid();
[MaxLength(1024)] public string? Label { get; set; }
@@ -17,7 +18,7 @@ public class Session : ModelBase
public Guid AccountId { get; set; }
[JsonIgnore] public Account.Account Account { get; set; } = null!;
public Guid ChallengeId { get; set; }
public Challenge Challenge { get; set; } = null!;
public AuthChallenge Challenge { get; set; } = null!;
public Guid? AppId { get; set; }
// public CustomApp? App { get; set; }
}
@@ -40,7 +41,7 @@ public enum ChallengePlatform
Linux
}
public class Challenge : ModelBase
public class AuthChallenge : ModelBase
{
public Guid Id { get; set; } = Guid.NewGuid();
public Instant? ExpiredAt { get; set; }
@@ -61,7 +62,7 @@ public class Challenge : ModelBase
public Guid AccountId { get; set; }
[JsonIgnore] public Account.Account Account { get; set; } = null!;
public Challenge Normalize()
public AuthChallenge Normalize()
{
if (StepRemain == 0 && BlacklistFactors.Count == 0) StepRemain = StepTotal;
return this;