2024-03-07 18:30:22 +11:00
|
|
|
import { compare, hash } from '@node-rs/bcrypt';
|
2023-09-18 14:03:33 +00:00
|
|
|
|
|
|
|
|
import { prisma } from '@documenso/prisma';
|
2024-01-30 17:31:27 +11:00
|
|
|
import { UserSecurityAuditLogType } from '@documenso/prisma/client';
|
2023-09-18 14:03:33 +00:00
|
|
|
|
|
|
|
|
import { SALT_ROUNDS } from '../../constants/auth';
|
2024-01-30 17:31:27 +11:00
|
|
|
import type { RequestMetadata } from '../../universal/extract-request-metadata';
|
2023-09-18 14:31:04 +00:00
|
|
|
import { sendResetPassword } from '../auth/send-reset-password';
|
2023-09-18 14:03:33 +00:00
|
|
|
|
|
|
|
|
export type ResetPasswordOptions = {
|
|
|
|
|
token: string;
|
|
|
|
|
password: string;
|
2024-01-30 17:31:27 +11:00
|
|
|
requestMetadata?: RequestMetadata;
|
2023-09-18 14:03:33 +00:00
|
|
|
};
|
|
|
|
|
|
2024-01-30 17:31:27 +11:00
|
|
|
export const resetPassword = async ({ token, password, requestMetadata }: ResetPasswordOptions) => {
|
2023-09-18 14:03:33 +00:00
|
|
|
if (!token) {
|
2023-09-18 15:09:41 +00:00
|
|
|
throw new Error('Invalid token provided. Please try again.');
|
2023-09-18 14:03:33 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-19 13:34:54 +00:00
|
|
|
const foundToken = await prisma.passwordResetToken.findFirst({
|
2023-09-18 14:03:33 +00:00
|
|
|
where: {
|
|
|
|
|
token,
|
|
|
|
|
},
|
|
|
|
|
include: {
|
|
|
|
|
User: true,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!foundToken) {
|
2023-09-18 15:09:41 +00:00
|
|
|
throw new Error('Invalid token provided. Please try again.');
|
2023-09-18 14:03:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const now = new Date();
|
|
|
|
|
|
|
|
|
|
if (now > foundToken.expiry) {
|
2023-09-18 15:09:41 +00:00
|
|
|
throw new Error('Token has expired. Please try again.');
|
2023-09-18 14:03:33 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-19 13:34:54 +00:00
|
|
|
const isSamePassword = await compare(password, foundToken.User.password || '');
|
2023-09-18 14:03:33 +00:00
|
|
|
|
|
|
|
|
if (isSamePassword) {
|
|
|
|
|
throw new Error('Your new password cannot be the same as your old password.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const hashedPassword = await hash(password, SALT_ROUNDS);
|
|
|
|
|
|
2023-09-19 13:34:54 +00:00
|
|
|
await prisma.$transaction([
|
2023-09-18 14:03:33 +00:00
|
|
|
prisma.user.update({
|
|
|
|
|
where: {
|
|
|
|
|
id: foundToken.userId,
|
|
|
|
|
},
|
|
|
|
|
data: {
|
|
|
|
|
password: hashedPassword,
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
prisma.passwordResetToken.deleteMany({
|
|
|
|
|
where: {
|
|
|
|
|
userId: foundToken.userId,
|
|
|
|
|
},
|
|
|
|
|
}),
|
2024-01-30 17:31:27 +11:00
|
|
|
prisma.userSecurityAuditLog.create({
|
|
|
|
|
data: {
|
|
|
|
|
userId: foundToken.userId,
|
|
|
|
|
type: UserSecurityAuditLogType.PASSWORD_RESET,
|
|
|
|
|
userAgent: requestMetadata?.userAgent,
|
|
|
|
|
ipAddress: requestMetadata?.ipAddress,
|
|
|
|
|
},
|
|
|
|
|
}),
|
2023-09-18 14:03:33 +00:00
|
|
|
]);
|
|
|
|
|
|
2023-09-18 14:31:04 +00:00
|
|
|
await sendResetPassword({ userId: foundToken.userId });
|
2023-09-18 14:03:33 +00:00
|
|
|
};
|