style reset password form
This commit is contained in:
parent
d8acd6c37c
commit
9d30930f96
@ -1,26 +1,32 @@
|
||||
import { resolver, generateToken, hash256 } from "blitz";
|
||||
|
||||
import db from "../../../db";
|
||||
import db, { User } from "../../../db";
|
||||
import { forgotPasswordMailer } from "../../../mailers/forgot-password-mailer";
|
||||
import { ForgotPassword } from "../validations";
|
||||
|
||||
const RESET_PASSWORD_TOKEN_EXPIRATION_IN_HOURS = 4;
|
||||
|
||||
export default resolver.pipe(resolver.zod(ForgotPassword), async ({ email }) => {
|
||||
// 1. Get the user
|
||||
const user = await db.user.findFirst({ where: { email: email.toLowerCase() } });
|
||||
|
||||
// 2. Generate the token and expiration date.
|
||||
// always wait the same amount of time so attackers can't tell the difference whether a user is found
|
||||
await Promise.all([updatePassword(user), new Promise((resolve) => setTimeout(resolve, 750))]);
|
||||
|
||||
// return the same result whether a password reset email was sent or not
|
||||
return;
|
||||
});
|
||||
|
||||
async function updatePassword(user: User | null) {
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
|
||||
const token = generateToken();
|
||||
const hashedToken = hash256(token);
|
||||
const expiresAt = new Date();
|
||||
expiresAt.setHours(expiresAt.getHours() + RESET_PASSWORD_TOKEN_EXPIRATION_IN_HOURS);
|
||||
|
||||
// 3. If user with this email was found
|
||||
if (user) {
|
||||
// 4. Delete any existing password reset tokens
|
||||
await db.token.deleteMany({ where: { type: "RESET_PASSWORD", userId: user.id } });
|
||||
// 5. Save this new token in the database.
|
||||
await db.token.create({
|
||||
data: {
|
||||
user: { connect: { id: user.id } },
|
||||
@ -30,13 +36,5 @@ export default resolver.pipe(resolver.zod(ForgotPassword), async ({ email }) =>
|
||||
sentTo: user.email,
|
||||
},
|
||||
});
|
||||
// 6. Send the email
|
||||
await forgotPasswordMailer({ to: user.email, token }).send();
|
||||
} else {
|
||||
// 7. If no user found wait the same time so attackers can't tell the difference
|
||||
await new Promise((resolve) => setTimeout(resolve, 750));
|
||||
}
|
||||
|
||||
// 8. Return the same result whether a password reset email was sent or not
|
||||
return;
|
||||
});
|
||||
}
|
||||
|
@ -2,30 +2,22 @@ import type { BlitzPage, GetServerSideProps } from "blitz";
|
||||
import { useRouterQuery, Link, useMutation, Routes } from "blitz";
|
||||
|
||||
import BaseLayout from "../../core/layouts/base-layout";
|
||||
import { LabeledTextField } from "../../core/components/labeled-text-field";
|
||||
import { Form, FORM_ERROR } from "../../core/components/form";
|
||||
import { AuthForm as Form, FORM_ERROR } from "../components/auth-form";
|
||||
import { LabeledTextField } from "../components/labeled-text-field";
|
||||
import { ResetPassword } from "../validations";
|
||||
import resetPassword from "../../auth/mutations/reset-password";
|
||||
|
||||
const ResetPasswordPage: BlitzPage = () => {
|
||||
const query = useRouterQuery();
|
||||
console.log("client query", query);
|
||||
const [resetPasswordMutation, { isSuccess }] = useMutation(resetPassword);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Set a New Password</h1>
|
||||
|
||||
{isSuccess ? (
|
||||
<div>
|
||||
<h2>Password Reset Successfully</h2>
|
||||
<p>
|
||||
Go to the <Link href={Routes.LandingPage()}>homepage</Link>
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<Form
|
||||
submitText="Reset Password"
|
||||
texts={{
|
||||
title: isSuccess ? "Password reset successfully" : "Set a new password",
|
||||
subtitle: "",
|
||||
submit: "Reset password",
|
||||
}}
|
||||
schema={ResetPassword}
|
||||
initialValues={{
|
||||
password: "",
|
||||
@ -48,11 +40,17 @@ const ResetPasswordPage: BlitzPage = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{isSuccess ? (
|
||||
<p>
|
||||
Go to the <Link href={Routes.LandingPage()}>homepage</Link>
|
||||
</p>
|
||||
) : (
|
||||
<>
|
||||
<LabeledTextField name="password" label="New Password" type="password" />
|
||||
<LabeledTextField name="passwordConfirmation" label="Confirm New Password" type="password" />
|
||||
</Form>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user