You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
42 lines
1.5 KiB
42 lines
1.5 KiB
import { generateToken, hash256 } from "@blitzjs/auth" |
|
import { resolver } from "@blitzjs/rpc" |
|
import db from "db" |
|
import { forgotPasswordMailer } from "mailers/forgotPasswordMailer" |
|
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. |
|
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 } }, |
|
type: "RESET_PASSWORD", |
|
expiresAt, |
|
hashedToken, |
|
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 |
|
})
|
|
|