Files
sign/packages/lib/server-only/user/reset-password.ts

82 lines
1.9 KiB
TypeScript
Raw Normal View History

2024-03-07 18:30:22 +11:00
import { compare, hash } from '@node-rs/bcrypt';
2025-01-02 15:33:37 +11:00
import { UserSecurityAuditLogType } from '@prisma/client';
2023-09-18 14:03:33 +00:00
import { prisma } from '@documenso/prisma';
import { SALT_ROUNDS } from '../../constants/auth';
2024-12-06 16:01:24 +09:00
import { AppError, AppErrorCode } from '../../errors/app-error';
2025-01-02 15:33:37 +11:00
import { jobsClient } from '../../jobs/client';
2024-01-30 17:31:27 +11:00
import type { RequestMetadata } from '../../universal/extract-request-metadata';
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) {
2024-12-06 16:01:24 +09:00
throw new AppError('INVALID_TOKEN');
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: {
2025-01-13 13:41:53 +11:00
user: true,
2023-09-18 14:03:33 +00:00
},
});
if (!foundToken) {
2024-12-06 16:01:24 +09:00
throw new AppError('INVALID_TOKEN');
2023-09-18 14:03:33 +00:00
}
const now = new Date();
if (now > foundToken.expiry) {
2024-12-06 16:01:24 +09:00
throw new AppError(AppErrorCode.EXPIRED_CODE);
2023-09-18 14:03:33 +00:00
}
2025-01-13 13:41:53 +11:00
const isSamePassword = await compare(password, foundToken.user.password || '');
2023-09-18 14:03:33 +00:00
if (isSamePassword) {
2024-12-06 16:01:24 +09:00
throw new AppError('SAME_PASSWORD');
2023-09-18 14:03:33 +00:00
}
const hashedPassword = await hash(password, SALT_ROUNDS);
2025-01-02 15:33:37 +11:00
await prisma.$transaction(async (tx) => {
await tx.user.update({
2023-09-18 14:03:33 +00:00
where: {
id: foundToken.userId,
},
data: {
password: hashedPassword,
},
2025-01-02 15:33:37 +11:00
});
await tx.passwordResetToken.deleteMany({
2023-09-18 14:03:33 +00:00
where: {
userId: foundToken.userId,
},
2025-01-02 15:33:37 +11:00
});
await tx.userSecurityAuditLog.create({
2024-01-30 17:31:27 +11:00
data: {
userId: foundToken.userId,
type: UserSecurityAuditLogType.PASSWORD_RESET,
userAgent: requestMetadata?.userAgent,
ipAddress: requestMetadata?.ipAddress,
},
2025-01-02 15:33:37 +11:00
});
2023-09-18 14:03:33 +00:00
2025-01-02 15:33:37 +11:00
await jobsClient.triggerJob({
name: 'send.password.reset.success.email',
payload: {
userId: foundToken.userId,
},
});
});
2023-09-18 14:03:33 +00:00
};