import { UserRepository } from "../repositories/UserRepository.js"; import { encrypt } from "../utils/encryptionUtils.js"; import { ValidationError, UnauthorizedError } from "../api/errors/httpErrors.js"; import { UserDtoEntityMapper } from "../mappers/UserDtoEntityMapper.js"; import { LoginResponse } from "../api/dtos/LoginResponse.js"; import { LoginRequest } from "../api/dtos/LoginRequest.js"; /** * Controller responsible for authentication, e.g., login or issueing a token with extended * lifetime */ export class AuthHandler { constructor( private userRepository: UserRepository, private mapper: UserDtoEntityMapper ) {} /** * Login: Check user and password and generate token * @param loginRequest LoginRequest containing userName and password for login * @returns LoginResponse containing token and user data for the user who just logged in */ async login(loginRequest : LoginRequest): Promise { const userName :string|undefined = loginRequest.userName; const password :string|undefined = loginRequest.password; console.log("user", userName, " is trying to log in") if (!userName || !password) { throw new ValidationError("Username and password are required"); } // Find user by userName const user = await this.userRepository.findByUserName(userName); // check user before trying to access password! if(!user){ throw new UnauthorizedError("Invalid username or password"); } // ensure user has an id - required to generate token const userId = user.id; if(user.id == undefined){ throw new UnauthorizedError("Invalid username or password"); } // Compare password const passwordMatches = encrypt.comparepassword(password, user.password); if (!passwordMatches) { throw new UnauthorizedError("Invalid username or password"); } // Create JWT const tokenInfo = encrypt.generateToken({ id: userId!, // ! to indicate that we've definitely checked for userId being defined role: user.role }); const responseDto = new LoginResponse(); responseDto.userData = this.mapper.toDto(user); responseDto.token = tokenInfo.token; responseDto.expiryDate = tokenInfo.expiryDate; return responseDto; } }