134 lines
4.4 KiB
C#

using API.DTO.Base;
using API.DTO.Base.Update;
using API.DTO.Login;
using API.Hashing.Interfaces;
using API.Services.Interfaces;
using DAL.Models;
namespace API.Services
{
public class UserManager : IUserManager
{
private readonly IHashingFactory _hashingFactory;
private readonly ILogger<UserManager> _logger;
private readonly HashingType _preferredHashingType;
private readonly UserService _userService;
public UserManager(UserService userService, IHashingFactory hashingFactory, ILogger<UserManager> logger, HashingType preferredHashingType)
{
_userService = userService;
_hashingFactory = hashingFactory;
_logger = logger;
_preferredHashingType = preferredHashingType;
}
public UserDTO? authenticateUser(UserLoginDTO loginDTO)
{
User? user = _userService.getNoAuthentication(x => x.phoneNumber.Equals(loginDTO.phoneNumber)).FirstOrDefault();
if (user == null)
return null;
IHashingAlgorithm? hashingAlgorithm = _hashingFactory.getAlgorithm(user.hashingType);
if (hashingAlgorithm == null)
{
_logger.Log(LogLevel.Warning, "User id '{id}' has a hashing type '{hashingType}' that isn't recognized by factory '{factory}'. Not logging in.", user.id, user.hashingType, nameof(_hashingFactory));
return null;
}
string hashedPassword = hashingAlgorithm.hash(loginDTO.password, user.salt);
if (!hashedPassword.Equals(user.password))
{
_logger.Log(LogLevel.Information, "Failed login attempt for user id '{id}.", user.id);
return null;
}
if (user.hashingType != _preferredHashingType)
{
// todo The user is logged in at this point. Their hashing type needs to be updated, we need to rehash & salt the password and save it now.
}
UserDTO dto = new UserDTO();
dto.adaptFromModel(user);
return dto;
}
public UserDTO? registerUser(UserRegisterDTO registerDTO, User? user = null, ulong? permissionId = null)
{
if (_userService.getNoAuthentication(x =>
x.phoneNumber.Equals(registerDTO.phoneNumber) ||
x.firstName.Equals(registerDTO.firstName) && x.lastName.Equals(registerDTO.lastName))
.Any())
{
return null;
}
IHashingAlgorithm? hashingAlgorithm = _hashingFactory.getAlgorithm(_preferredHashingType);
if (hashingAlgorithm == null)
{
_logger.Log(LogLevel.Error, "Preferred hashing type '{hashingType}' that isn't recognized by factory '{factory}'.", _preferredHashingType, nameof(_hashingFactory));
return null;
}
byte[] salt;
string hashedPassword = hashingAlgorithm.hash(registerDTO.password, out salt);
User? createdUser = _userService.add(registerDTO, hashedPassword, salt, user, permissionId);
if (createdUser == null)
return null;
UserDTO dto = new UserDTO();
dto.adaptFromModel(createdUser);
return dto;
}
public UserDTO? changePassword(UserPasswordUpdateDTO userPasswordUpdateDTO, User changingUser)
{
User? destUser = _userService.getNoAuthentication(x => x.phoneNumber.Equals(userPasswordUpdateDTO.phoneNumber)).FirstOrDefault();
if (destUser == null)
return null;
IHashingAlgorithm? hashingAlgorithm = _hashingFactory.getAlgorithm(_preferredHashingType);
if (hashingAlgorithm == null){
_logger.Log(LogLevel.Error, "Preferred hashing type '{hashingType}' that isn't recognized by factory '{factory}'.", _preferredHashingType, nameof(_hashingFactory));
return null;
}
byte[] newSalt;
string hashedNewPassword = hashingAlgorithm.hash(userPasswordUpdateDTO.newPassword, out newSalt);
bool oldPasswordMatchNew = false;
if (userPasswordUpdateDTO.oldPassword != null)
{
IHashingAlgorithm? userHashingAlgorithm = _hashingFactory.getAlgorithm(destUser.hashingType);
if (userHashingAlgorithm == null)
{
_logger.Log(LogLevel.Warning, "User id '{id}' has a hashing type '{hashingType}' that isn't recognized by factory '{factory}'. Not logging in.", destUser.id, destUser.hashingType, nameof(_hashingFactory));
return null;
}
string hashedOldPassword = userHashingAlgorithm.hash(userPasswordUpdateDTO.oldPassword, destUser.salt);
if (hashedOldPassword.Equals(destUser.password))
{
oldPasswordMatchNew = true;
}
}
User? updatedUser = _userService.changePassword(destUser, changingUser, hashedNewPassword, newSalt, oldPasswordMatchNew);
if (updatedUser == null)
return null;
UserDTO dto = new UserDTO();
dto.adaptFromModel(updatedUser);
return dto;
}
}
}