diff --git a/src/services/passwordResetTokenService.ts b/src/services/passwordResetTokenService.ts new file mode 100644 index 0000000..03e1927 --- /dev/null +++ b/src/services/passwordResetTokenService.ts @@ -0,0 +1,32 @@ +import prisma from '../utilities/prisma' +import passwordResetTokenRepository from '../repositories/passwordResetTokenRepository' +import { appLogger } from '../utilities/logger' + +class PasswordResetTokenService { + /** + * Delete token + * @param token + */ + public async delete(token: string): Promise { + + try { + const tokenData = await passwordResetTokenRepository.getByToken(token) + if (!tokenData) { + return false + } + + prisma.passwordResetToken.delete({ + where: { + token + } + }) + + return true + } catch (error: any) { + appLogger.error(`Error deleting password reset token: ${error instanceof Error ? error.message : String(error)}`) + return false + } + } +} + +export default PasswordResetTokenService diff --git a/src/services/userService.ts b/src/services/userService.ts index b9c811b..a3e1027 100644 --- a/src/services/userService.ts +++ b/src/services/userService.ts @@ -6,6 +6,7 @@ import { User } from '@prisma/client' import config from '../utilities/config' import NodeMailer from 'nodemailer' import { httpLogger } from '../utilities/logger' +import PasswordResetTokenService from './passwordResetTokenService' /** * User service @@ -76,44 +77,44 @@ class UserService { * @param email */ async requestPasswordReset(email: string): Promise { - const user = await UserRepository.getByEmail(email) - if (!user) return false + try { + const user = await UserRepository.getByEmail(email) + if (!user) return false - const token = await bcrypt.hash(new Date().getTime().toString(), 10) - const latestToken = await PasswordResetTokenRepository.getByUserId(user.id) + const token = await bcrypt.hash(new Date().getTime().toString(), 10) + const latestToken = await PasswordResetTokenRepository.getByUserId(user.id) - //Check if password reset has been requested recently - if (latestToken) { - const tokenExpiryDate = new Date(Date.now() - 24 * 60 * 60 * 1000) - const isTokenExpired = latestToken.createdAt < tokenExpiryDate + // Check if password reset has been requested recently + if (latestToken) { + const tokenExpiryDate = new Date(Date.now() - 24 * 60 * 60 * 1000) // 24 hours + const isTokenExpired = latestToken.createdAt < tokenExpiryDate - if (!isTokenExpired) return false + if (!isTokenExpired) return false - await prisma.passwordResetToken.delete({ - where: { - id: latestToken.id + await prisma.passwordResetToken.delete({ + where: { + id: latestToken.id + } + }) + } + + await prisma.passwordResetToken.create({ + data: { + userId: user.id, + token: token } }) - } - await prisma.passwordResetToken.create({ - data: { - userId: user.id, - token: token - } - }) + const transporter = NodeMailer.createTransport({ + host: config.SMTP_HOST, + port: config.SMTP_PORT, + secure: false, + auth: { + user: config.SMTP_USER, + pass: config.SMTP_PASSWORD + } + }) - const transporter = NodeMailer.createTransport({ - host: config.SMTP_HOST, - port: config.SMTP_PORT, - secure: false, - auth: { - user: config.SMTP_USER, - pass: config.SMTP_PASSWORD - } - }) - - try { await transporter.sendMail({ from: config.SMTP_USER, to: email, @@ -134,7 +135,7 @@ class UserService { * @param urlToken * @param password */ - async resetPassword(urlToken: string, password: string): Promise { + async resetPassword(urlToken: string, password: string): Promise { try { const tokenData = await PasswordResetTokenRepository.getByToken(urlToken) if (!tokenData) { @@ -142,12 +143,18 @@ class UserService { } const hashedPassword = await bcrypt.hash(password, 10) - return prisma.user.update({ + prisma.user.update({ where: { id: tokenData.userId }, data: { password: hashedPassword } }) + + // Delete the token + const passwordResetTokenService = new PasswordResetTokenService() + await passwordResetTokenService.delete(urlToken) + + return true } catch (error: any) { httpLogger.error(`Error setting new password: ${error instanceof Error ? error.message : String(error)}`) return false diff --git a/src/utilities/http.ts b/src/utilities/http.ts index b6d4d9d..bb85684 100644 --- a/src/utilities/http.ts +++ b/src/utilities/http.ts @@ -82,7 +82,7 @@ async function addHttpRoutes(app: Application) { return res.status(200).json({ message: 'Email has been sent' }) } - return res.status(400).json({ message: 'Failed to send password reset request' }) + return res.status(400).json({ message: 'Failed to send password reset request. Perhaps one has already been sent recently, check your spam folder.' }) }) /**