using System.Collections.Concurrent; using System.Collections.Immutable; using System.Security.Cryptography; using Phantom.Common.Data.Web.Users; namespace Phantom.Controller.Services.Users; sealed class UserLoginManager { private const int SessionIdBytes = 20; private readonly ConcurrentDictionary<string, List<ImmutableArray<byte>>> sessionTokensByUsername = new (); private readonly UserManager userManager; private readonly PermissionManager permissionManager; public UserLoginManager(UserManager userManager, PermissionManager permissionManager) { this.userManager = userManager; this.permissionManager = permissionManager; } public async Task<LogInSuccess?> LogIn(string username, string password) { var user = await userManager.GetAuthenticated(username, password); if (user == null) { return null; } var token = ImmutableArray.Create(RandomNumberGenerator.GetBytes(SessionIdBytes)); var sessionTokens = sessionTokensByUsername.GetOrAdd(username, static _ => new List<ImmutableArray<byte>>()); lock (sessionTokens) { sessionTokens.Add(token); } return new LogInSuccess(user.UserGuid, await permissionManager.FetchPermissionsForUserId(user.UserGuid), token); } }