188 lines
4.9 KiB
C#
188 lines
4.9 KiB
C#
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<string>? 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 VerifyPasswordAgainstHash(string providedPassword, IPasswordHasher passwordHasher)
|
|
{
|
|
return passwordHasher.VerifyHashedPassword(this, PasswordHash, providedPassword);
|
|
}
|
|
|
|
|
|
public static (bool IsValid, IEnumerable<string>? Errors) IsValidPassword(string password)
|
|
{
|
|
var Errors = new List<string>();
|
|
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<string>? 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<string> { "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<string>? 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<string>? Errors) IsValidUsername(string username)
|
|
{
|
|
var Errors = new List<string>();
|
|
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;
|
|
}
|
|
}
|