import httpStatus from 'http-status'; import tokenService from './token.service'; import userService from './user.service'; import ApiError from '../utils/ApiError'; import { TokenType, User } from '@prisma/client'; import prisma from '../client'; import { encryptPassword, isPasswordMatch } from '../utils/encryption'; import { AuthTokensResponse } from '../types/response'; import exclude from '../utils/exclude'; /** * Login with username and password * @param {string} email * @param {string} password * @returns {Promise>} */ const loginUserWithEmailAndPassword = async ( email: string, password: string ): Promise> => { const user = await userService.getUserByEmail(email, [ 'id', 'email', 'name', 'password', 'role', 'isEmailVerified', 'createdAt', 'updatedAt' ]); if (!user || !(await isPasswordMatch(password, user.password as string))) { throw new ApiError(httpStatus.UNAUTHORIZED, 'Incorrect email or password'); } return exclude(user, ['password']); }; /** * Logout * @param {string} refreshToken * @returns {Promise} */ const logout = async (refreshToken: string): Promise => { const refreshTokenData = await prisma.token.findFirst({ where: { token: refreshToken, type: TokenType.REFRESH, blacklisted: false } }); if (!refreshTokenData) { throw new ApiError(httpStatus.NOT_FOUND, 'Not found'); } await prisma.token.delete({ where: { id: refreshTokenData.id } }); }; /** * Refresh auth tokens * @param {string} refreshToken * @returns {Promise} */ const refreshAuth = async (refreshToken: string): Promise => { try { const refreshTokenData = await tokenService.verifyToken(refreshToken, TokenType.REFRESH); const { userId } = refreshTokenData; await prisma.token.delete({ where: { id: refreshTokenData.id } }); return tokenService.generateAuthTokens({ id: userId }); } catch (error) { throw new ApiError(httpStatus.UNAUTHORIZED, 'Please authenticate'); } }; /** * Reset password * @param {string} resetPasswordToken * @param {string} newPassword * @returns {Promise} */ const resetPassword = async (resetPasswordToken: string, newPassword: string): Promise => { try { const resetPasswordTokenData = await tokenService.verifyToken( resetPasswordToken, TokenType.RESET_PASSWORD ); const user = await userService.getUserById(resetPasswordTokenData.userId); if (!user) { throw new Error(); } const encryptedPassword = await encryptPassword(newPassword); await userService.updateUserById(user.id, { password: encryptedPassword }); await prisma.token.deleteMany({ where: { userId: user.id, type: TokenType.RESET_PASSWORD } }); } catch (error) { throw new ApiError(httpStatus.UNAUTHORIZED, 'Password reset failed'); } }; /** * Verify email * @param {string} verifyEmailToken * @returns {Promise} */ const verifyEmail = async (verifyEmailToken: string): Promise => { try { const verifyEmailTokenData = await tokenService.verifyToken( verifyEmailToken, TokenType.VERIFY_EMAIL ); await prisma.token.deleteMany({ where: { userId: verifyEmailTokenData.userId, type: TokenType.VERIFY_EMAIL } }); await userService.updateUserById(verifyEmailTokenData.userId, { isEmailVerified: true }); } catch (error) { throw new ApiError(httpStatus.UNAUTHORIZED, 'Email verification failed'); } }; export default { loginUserWithEmailAndPassword, isPasswordMatch, encryptPassword, logout, refreshAuth, resetPassword, verifyEmail };