shellphone.app/app/auth/mutations/reset-password.ts

49 lines
1.4 KiB
TypeScript
Raw Normal View History

import { resolver, SecurePassword, hash256 } from "blitz";
2021-07-31 14:33:18 +00:00
import db from "../../../db";
import { ResetPassword } from "../validations";
import login from "./login";
2021-07-31 14:33:18 +00:00
export class ResetPasswordError extends Error {
name = "ResetPasswordError";
message = "Reset password link is invalid or it has expired.";
2021-07-31 14:33:18 +00:00
}
export default resolver.pipe(resolver.zod(ResetPassword), async ({ password, token }, ctx) => {
// 1. Try to find this token in the database
const hashedToken = hash256(token);
2021-07-31 14:33:18 +00:00
const possibleToken = await db.token.findFirst({
where: { hashedToken, type: "RESET_PASSWORD" },
include: { user: true },
});
2021-07-31 14:33:18 +00:00
// 2. If token not found, error
if (!possibleToken) {
throw new ResetPasswordError();
2021-07-31 14:33:18 +00:00
}
const savedToken = possibleToken;
2021-07-31 14:33:18 +00:00
// 3. Delete token so it can't be used again
await db.token.delete({ where: { id: savedToken.id } });
2021-07-31 14:33:18 +00:00
// 4. If token has expired, error
if (savedToken.expiresAt < new Date()) {
throw new ResetPasswordError();
2021-07-31 14:33:18 +00:00
}
// 5. Since token is valid, now we can update the user's password
const hashedPassword = await SecurePassword.hash(password.trim());
2021-07-31 14:33:18 +00:00
const user = await db.user.update({
where: { id: savedToken.userId },
data: { hashedPassword },
});
2021-07-31 14:33:18 +00:00
// 6. Revoke all existing login sessions for this user
await db.session.deleteMany({ where: { userId: user.id } });
2021-07-31 14:33:18 +00:00
// 7. Now log the user in with the new credentials
await login({ email: user.email, password }, ctx);
2021-07-31 14:33:18 +00:00
return true;
});