using System.Security.Claims; using Azaion.Common; using Azaion.Common.Configs; using Azaion.Common.Database; using Azaion.Common.Entities; using Azaion.Common.Requests; using LinqToDB; using Microsoft.AspNetCore.Http; namespace Azaion.Services; public interface IUserService { User? CurrentUser { get; } Task RegisterUser(RegisterUserRequest request, CancellationToken cancellationToken = default); Task ValidateUser(string username, string password, string? hardwareId = null, CancellationToken cancellationToken = default); Task UpdateHardwareId(string username, string hardwareId, CancellationToken cancellationToken = default); } public class UserService(IDbFactory dbFactory, IHttpContextAccessor httpContextAccessor) : IUserService { public User? CurrentUser { get { var claims = httpContextAccessor.HttpContext?.User.Claims.ToDictionary(x => x.Type); if (claims == null) return null; Enum.TryParse(claims[ClaimTypes.Role].Value, out RoleEnum role); return new User { Id = claims[ClaimTypes.NameIdentifier].Value, Email = claims[ClaimTypes.Name].Value, Role = role, HardwareId = claims[Constants.HARDWARE_ID].Value, }; } } public async Task RegisterUser(RegisterUserRequest request, CancellationToken cancellationToken = default) { await dbFactory.Run(async db => { var existingUser = await db.Users.FirstOrDefaultAsync(u => u.Email == request.Email, token: cancellationToken); if (existingUser != null) throw new BusinessException(ExceptionEnum.UserExists, "User already exists"); await db.InsertAsync(new User { Email = request.Email, PasswordHash = request.Password.ToHash(), Role = request.Role }, token: cancellationToken); }); } public async Task ValidateUser(string username, string password, string? hardwareId = null, CancellationToken cancellationToken = default) => await dbFactory.Run(async db => { var user = await db.Users.FirstOrDefaultAsync(x => x.Email == username, token: cancellationToken); if (user == null) throw new BusinessException(ExceptionEnum.NoUserFound, "No user found"); if (password.ToHash() != user.PasswordHash) throw new BusinessException(ExceptionEnum.PasswordIncorrect, "Passwords do not match"); if (user.Role == RoleEnum.ApiAdmin) return user; // For Non-API admins hardwareId should match if it was already set if (user.HardwareId != null && user.HardwareId != hardwareId) throw new BusinessException(ExceptionEnum.HardwareIdMismatch, "Hardware id mismatch"); return user; }); public async Task UpdateHardwareId(string username, string hardwareId, CancellationToken cancellationToken = default) => await dbFactory.Run(async db => await db.Users.UpdateAsync(x => x.Email == username, u => new User { HardwareId = hardwareId}, token: cancellationToken)); }