using System.Collections; using System.Collections.Concurrent; using Femto.Modules.Auth.Models; using Microsoft.Extensions.Caching.Memory; namespace Femto.Modules.Auth.Infrastructure; internal class SessionStorage(TimeProvider timeProvider) { private readonly IMemoryCache _storage = new MemoryCache(new MemoryCacheOptions()); public async Task GetSession(string id) { var session = this._storage.Get($"session:{id}"); if (session is null) return null; var invalidUntil = this._storage.Get( $"user:invalid_until:{session.UserId}" ); if (invalidUntil is not null && invalidUntil > session.Expires) return null; return session; } public Task AddSession(Session session) { using var sessionEntry = this._storage.CreateEntry($"session:{session.Id}"); sessionEntry.Value = session; sessionEntry.SetAbsoluteExpiration(session.Expires); return Task.CompletedTask; } public Task DeleteSession(string id) { this._storage.Remove($"session:{id}"); return Task.CompletedTask; } public Task InvalidateUserSessions(Guid userId) { var invalidUntil = timeProvider.GetUtcNow() + Session.ValidityPeriod; // invalidate sessions who are currently valid // any sessions created after this will have a validity period that extends past invalid_until // this cache entry doesn't need to live longer than that point in time this._storage.Set($"user:invalid_until:{userId}", invalidUntil, invalidUntil); return Task.CompletedTask; } }