This repository has been archived on 2024-10-29. You can view files and clone it, but cannot push or open issues or pull requests.
2022-03-20 11:49:27 +01:00

101 lines
3.1 KiB
TypeScript

import { randomUUID } from 'node:crypto'
import { Static, Type } from '@sinclair/typebox'
import { FastifyPluginAsync, FastifySchema } from 'fastify'
import ms from 'ms'
import prisma from '../../../tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js'
import { userSchema } from '../../../models/User.js'
import { sendEmail } from '../../../tools/email/sendEmail.js'
import { Language, Theme } from '../../../models/UserSettings.js'
const queryPostResetPasswordSchema = Type.Object({
redirectURI: Type.String({ format: 'uri-reference' })
})
type QueryPostResetPasswordSchemaType = Static<
typeof queryPostResetPasswordSchema
>
const bodyPostResetPasswordSchema = Type.Object({
email: userSchema.email
})
type BodyPostResetPasswordSchemaType = Static<
typeof bodyPostResetPasswordSchema
>
const postResetPasswordSchema: FastifySchema = {
description: 'Request a password-reset change',
tags: ['users'] as string[],
body: bodyPostResetPasswordSchema,
querystring: queryPostResetPasswordSchema,
response: {
200: Type.String(),
400: fastifyErrors[400],
500: fastifyErrors[500]
}
} as const
export const postResetPasswordUser: FastifyPluginAsync = async (fastify) => {
await fastify.route<{
Body: BodyPostResetPasswordSchemaType
Querystring: QueryPostResetPasswordSchemaType
}>({
method: 'POST',
url: '/users/reset-password',
schema: postResetPasswordSchema,
handler: async (request, reply) => {
const { email } = request.body
const { redirectURI } = request.query
const user = await prisma.user.findUnique({
where: {
email
}
})
if (user == null) {
throw fastify.httpErrors.badRequest("Email address doesn't exist")
}
if (!user.isConfirmed) {
throw fastify.httpErrors.badRequest(
'You should have a confirmed account, please check your email and follow the instructions to verify your account'
)
}
const isValidTemporaryToken =
user.temporaryExpirationToken != null &&
user.temporaryExpirationToken.getTime() > Date.now()
if (user.temporaryToken != null && isValidTemporaryToken) {
throw fastify.httpErrors.badRequest(
'A request to reset-password is already in progress'
)
}
const userSettings = await prisma.userSetting.findFirst({
where: { userId: user.id }
})
if (userSettings == null) {
throw fastify.httpErrors.badRequest()
}
const temporaryToken = randomUUID()
await prisma.user.update({
where: {
id: user.id
},
data: {
temporaryExpirationToken: new Date(Date.now() + ms('1 hour')),
temporaryToken
}
})
await sendEmail({
type: 'reset-password',
email,
url: `${redirectURI}?temporaryToken=${temporaryToken}`,
language: userSettings.language as Language,
theme: userSettings.theme as Theme
})
reply.statusCode = 200
return 'Password-reset request successful, please check your emails!'
}
})
}