amati/apps/backend/src/routes/forgotPassword/route.ts
2024-08-22 15:54:34 +07:00

111 lines
2.5 KiB
TypeScript

import { zValidator } from "@hono/zod-validator";
import HonoEnv from "../../types/HonoEnv";
import { z } from "zod";
import { and, eq, isNull } from "drizzle-orm";
import { Hono } from "hono";
import db from "../../drizzle";
import { users } from "../../drizzle/schema/users";
import { notFound, unauthorized } from "../../errors/DashboardError";
import { generateResetPasswordToken, verifyResetPasswordToken } from "../../utils/authUtils";
import { sendResetPasswordEmail } from "../../utils/mailerUtils";
import { hashPassword } from "../../utils/passwordUtils";
const forgotPasswordRoutes = new Hono<HonoEnv>()
/**
* Forgot Password
*
* Checking emails in the database, generating tokens, and sending emails occurs.
*/
.post(
'/',
zValidator(
'json',
z.object({
email: z.string().email(),
})
),
async (c) => {
const { email } = c.req.valid('json');
const user = await db
.select()
.from(users)
.where(
and(
isNull(users.deletedAt),
eq(users.email, email)
)
);
if (!user.length) throw notFound();
// Generate reset password token
const resetPasswordToken = await generateResetPasswordToken({
uid: user[0].id,
});
await db
.update(users)
.set({
resetPasswordToken: resetPasswordToken
})
.where(eq(users.email, email));
// Send email with reset password token
await sendResetPasswordEmail(email, resetPasswordToken);
return c.json({
message: 'Email has been sent successfully',
});
}
)
/**
* Reset Password
*/
.patch(
'/verify',
zValidator(
'json',
z.object({
password: z.string(),
confirm_password: z.string()
})
),
async (c) => {
const formData = c.req.valid('json');
const token = c.req.query('token')
// Token validation
if (!token) {
return c.json({ message: 'Token is required' }, 400);
}
// Password validation
if (formData.password !== formData.confirm_password) {
return c.json({ message: 'Passwords do not match' }, 400);
}
const decoded = await verifyResetPasswordToken(token);
if (!decoded) {
return c.json({ message: 'Invalid or expired token' }, 401);
}
if (!decoded) throw unauthorized();
// Hash the password
const hashedPassword = await hashPassword(formData.password);
await db
.update(users)
.set({
password: hashedPassword,
updatedAt: new Date(),
})
.where(eq(users.id, decoded.uid));
return c.json({
message: 'Password has been reset successfully'
});
});
export default forgotPasswordRoutes;