namespace CSR.Domain.Entities; using System.Net.Mail; using CSR.Domain.Interfaces; public class User { public int Id { get; private set; } public string Username { get; private set; } public string Email { get; private set; } public string PasswordHash { get; private set; } public int RoleId { get; private set; } public Role Role { get; private set; } private User(int id, string username, string email, string passwordHash, int roleId, Role role) { Id = id; Username = username; Email = email; PasswordHash = passwordHash; RoleId = roleId; Role = role; } // This role is used when a new user is created public static readonly Role DefaultRole = Role.User; internal static User LoadExisting(int id, string username, string email, string passwordHash, int roleId, Role role) { return new User(id, username, email, passwordHash, roleId, role); } public static User CreateNew(string username, string email, string password, IPasswordHasher passwordHasher) { if (!IsValidUsername(username).IsValid) { throw new ArgumentException("Invalid username."); } if (!IsValidEmail(email)) { throw new ArgumentException("Invalid email."); } if (!IsValidPassword(password).IsValid) { throw new ArgumentException("Invalid password."); } var user = new User(0, username, email, password, DefaultRole.Id, DefaultRole); user.PasswordHash = passwordHasher.HashPassword(user, password); return user; } public (bool Success, IEnumerable? Errors) UpdatePassword(string password, IPasswordHasher passwordHasher, User requestingUser) { if (requestingUser.Id != Id || requestingUser.Role.Name != "Admin") { throw new UnauthorizedAccessException("Only admins or the same user can update passwords."); } var validityCheck = IsValidPassword(password); if (validityCheck.IsValid) { PasswordHash = passwordHasher.HashPassword(this, password); } return validityCheck; } public bool VerifyPassword(string providedPassword, IPasswordHasher passwordHasher) { return passwordHasher.VerifyHashedPassword(this, PasswordHash, providedPassword); } public static (bool IsValid, IEnumerable? Errors) IsValidPassword(string password) { var Errors = new List(); if (password.Length < 8 || password.Length > 32) { Errors.Add("Password must be between 8 and 32 characters long."); } if (!password.Any(char.IsUpper)) { Errors.Add("Password must contain at least one uppercase letter."); } if (!password.Any(char.IsLower)) { Errors.Add("Password must contain at least one lowercase letter."); } if (!password.Any(char.IsDigit)) { Errors.Add("Password must contain at least one digit."); } if (Errors.Count > 0) { return (false, Errors); } return (true, null); } public (bool Success, IEnumerable? Errors) UpdateEmail(string email, User requestingUser) { if (requestingUser.Id != Id || requestingUser.Role.Name != "Admin") { throw new UnauthorizedAccessException("Only admins or the same user can update email."); } if (IsValidEmail(email)) { Email = email; return (true, null); } return (false, new List { "Invalid email format." }); } public static bool IsValidEmail(string email) { try { var mailAddress = new MailAddress(email); return true; } catch (FormatException) { return false; } } public (bool Success, IEnumerable? Errors) UpdateUsername(string username, User requestingUser) { if (requestingUser.Role.Name != "Admin") { throw new UnauthorizedAccessException("Only admins can update username."); } var validityCheck = IsValidUsername(username); if (validityCheck.IsValid) { Username = username; } return validityCheck; } public static (bool IsValid, IEnumerable? Errors) IsValidUsername(string username) { var Errors = new List(); if (!username.All(char.IsLetterOrDigit)) { Errors.Add("Username must be alphanumeric."); } if (string.IsNullOrWhiteSpace(username) || username.Length < 3) { Errors.Add("Username must be at least 3 characters long."); } if (username.Length > 32) { Errors.Add("Username must be less than 32 characters long."); } if (Errors.Count > 0) { return (false, Errors); } return (true, null); } public void UpdateRole(Role role, User requestingUser) { if (requestingUser.Role.Name != "Admin") { throw new UnauthorizedAccessException("Only admins can assign roles."); } Role = role; RoleId = role.Id; } }