Change password in database to new reset password

This commit is contained in:
Ephraim Atta-Duncan
2023-06-05 14:36:20 +00:00
parent 8dc9c9d72d
commit 6e2b05f835
5 changed files with 71 additions and 25 deletions

View File

@ -1,4 +1,5 @@
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router";
import { Button } from "@documenso/ui"; import { Button } from "@documenso/ui";
import Logo from "./logo"; import Logo from "./logo";
import { ArrowLeftIcon } from "@heroicons/react/24/outline"; import { ArrowLeftIcon } from "@heroicons/react/24/outline";
@ -11,14 +12,50 @@ interface IResetPassword {
} }
export default function ResetPassword(props: any) { export default function ResetPassword(props: any) {
const router = useRouter();
const { token } = router.query;
const methods = useForm<IResetPassword>(); const methods = useForm<IResetPassword>();
const { register, formState, watch } = methods; const { register, formState, watch } = methods;
const password = watch("password", ""); const password = watch("password", "");
const onSubmit = async (values: IResetPassword) => { const onSubmit = async (values: IResetPassword) => {
await toast.promise(
fetch(`/api/auth/reset-password`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ password: values.password, token }),
}),
{
loading: "Resetting...",
success: `Reset password successful`,
error: "Could not reset password :/",
}
);
console.log(values); console.log(values);
}; };
if (!token) {
return (
<div className="flex min-h-full items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
<div className="w-full max-w-md space-y-8">
<div>
<Logo className="mx-auto h-20 w-auto"></Logo>
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900">
Reset Password
</h2>
<p className="mt-2 text-center text-sm text-gray-600">
The token you provided is invalid. Please try again.
</p>
</div>
</div>
</div>
);
}
return ( return (
<> <>
<div className="flex min-h-full items-center justify-center py-12 px-4 sm:px-6 lg:px-8"> <div className="flex min-h-full items-center justify-center py-12 px-4 sm:px-6 lg:px-8">

View File

@ -24,7 +24,6 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) {
} }
const token = crypto.randomBytes(64).toString("hex"); const token = crypto.randomBytes(64).toString("hex");
const passwordResetToken = await prisma.passwordResetToken.create({ const passwordResetToken = await prisma.passwordResetToken.create({
data: { data: {
token, token,
@ -34,7 +33,7 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) {
await sendResetPassword(user, passwordResetToken.token); await sendResetPassword(user, passwordResetToken.token);
res.status(201).end(); res.status(200).json({ message: "Password reset email sent." });
} }
export default defaultHandler({ export default defaultHandler({

View File

@ -1,40 +1,53 @@
import { NextApiRequest, NextApiResponse } from "next"; import { NextApiRequest, NextApiResponse } from "next";
import { hashPassword } from "@documenso/lib/auth";
import { sendResetPassword } from "@documenso/lib/mail"; import { sendResetPassword } from "@documenso/lib/mail";
import { defaultHandler, defaultResponder } from "@documenso/lib/server"; import { defaultHandler, defaultResponder } from "@documenso/lib/server";
import prisma from "@documenso/prisma"; import prisma from "@documenso/prisma";
import crypto from "crypto";
async function postHandler(req: NextApiRequest, res: NextApiResponse) { async function postHandler(req: NextApiRequest, res: NextApiResponse) {
const { email } = req.body; const { token, password } = req.body;
const cleanEmail = email.toLowerCase();
if (!cleanEmail || !cleanEmail.includes("@")) { if (!token) {
res.status(422).json({ message: "Invalid email" }); res.status(422).json({ message: "Invalid token" });
return; return;
} }
const user = await prisma.user.findFirst({ const foundToken = await prisma.passwordResetToken.findUnique({
where: { where: {
email: cleanEmail, token,
},
include: {
User: true,
}, },
}); });
if (!user) { if (!foundToken) {
return res.status(400).json({ message: "No user found with this email." }); return res.status(400).json({ message: "Invalid token." });
} }
const token = crypto.randomBytes(64).toString("hex"); const hashedPassword = await hashPassword(password);
const passwordResetToken = await prisma.passwordResetToken.create({ const transaction = await prisma.$transaction([
data: { prisma.user.update({
token, where: {
userId: user.id, id: foundToken.userId,
}, },
}); data: {
password: hashedPassword,
},
}),
prisma.passwordResetToken.delete({
where: {
token,
},
}),
]);
await sendResetPassword(user, passwordResetToken.token); if (!transaction) {
return res.status(500).json({ message: "Error resetting password." });
}
res.status(201).end(); res.status(200).json({ message: "Password reset successful." });
} }
export default defaultHandler({ export default defaultHandler({

View File

@ -1,6 +1,6 @@
import Head from "next/head"; import Head from "next/head";
import { getUserFromToken } from "@documenso/lib/server"; import { getUserFromToken } from "@documenso/lib/server";
import ResetPassword from "../../components/reset-password"; import ResetPassword from "../../../components/reset-password";
export default function ResetPasswordPage(props: any) { export default function ResetPasswordPage(props: any) {
return ( return (

View File

@ -7,10 +7,7 @@ export const sendResetPassword = async (user: User, token: string) => {
await sendMail( await sendMail(
user.email, user.email,
"Forgot password?", "Forgot password?",
resetPasswordTemplate( resetPasswordTemplate(`${NEXT_PUBLIC_WEBAPP_URL}/auth/reset/${token}`, "Reset Your Password")
`${NEXT_PUBLIC_WEBAPP_URL}/api/auth/reset/${token}`,
"Reset Your Password"
)
).catch((err) => { ).catch((err) => {
throw err; throw err;
}); });