Files
Swarm/DysonNetwork.Pass/Features/Auth/Services/SessionService.cs

109 lines
3.1 KiB
C#

using System.Security.Cryptography;
using System.Text;
using DysonNetwork.Common.Models;
using DysonNetwork.Pass.Data;
using DysonNetwork.Pass.Features.Auth.Interfaces;
using Microsoft.EntityFrameworkCore;
using NodaTime;
namespace DysonNetwork.Pass.Features.Auth.Services;
public class SessionService : ISessionService
{
private readonly PassDatabase _db;
private readonly IClock _clock;
public SessionService(PassDatabase db, IClock clock)
{
_db = db;
_clock = clock;
}
public async Task<AuthSession> CreateSessionAsync(Guid accountId, string ipAddress, string userAgent)
{
var now = _clock.GetCurrentInstant();
var session = new AuthSession
{
Id = Guid.NewGuid(),
AccountId = accountId,
Label = $"Session from {ipAddress} via {userAgent}",
LastGrantedAt = now,
ExpiredAt = now.Plus(Duration.FromDays(30))
};
await _db.AuthSessions.AddAsync(session);
await _db.SaveChangesAsync();
return session;
}
public async Task<AuthSession?> GetSessionAsync(Guid sessionId)
{
return await _db.AuthSessions
.Include(s => s.Account)
.FirstOrDefaultAsync(s => s.Id == sessionId && s.ExpiredAt > _clock.GetCurrentInstant());
}
public async Task<bool> ValidateSessionAsync(Guid sessionId)
{
var session = await GetSessionAsync(sessionId);
if (session == null)
return false;
var now = _clock.GetCurrentInstant();
if (session.ExpiredAt <= now)
return false;
session.LastGrantedAt = now;
await _db.SaveChangesAsync();
return true;
}
public async Task InvalidateSessionAsync(Guid sessionId)
{
var session = await GetSessionAsync(sessionId);
if (session != null)
{
session.ExpiredAt = _clock.GetCurrentInstant();
await _db.SaveChangesAsync();
}
}
public async Task InvalidateAllSessionsAsync(Guid accountId, Guid? excludeSessionId = null)
{
var now = _clock.GetCurrentInstant();
var sessions = await _db.AuthSessions
.Where(s => s.AccountId == accountId && s.ExpiredAt > now)
.ToListAsync();
foreach (var session in sessions)
{
if (excludeSessionId == null || session.Id != excludeSessionId.Value)
{
session.ExpiredAt = now;
}
}
await _db.SaveChangesAsync();
}
public async Task UpdateSessionActivityAsync(Guid sessionId)
{
var session = await GetSessionAsync(sessionId);
if (session != null)
{
session.LastGrantedAt = _clock.GetCurrentInstant();
await _db.SaveChangesAsync();
}
}
private static string GenerateRefreshToken()
{
var randomNumber = new byte[32];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomNumber);
return Convert.ToBase64String(randomNumber);
}
}