import type { RouteHandler } from 'fastify' import { Type, type Static } from '@fastify/type-provider-typebox' import config from '../../../config.ts' import knex from '../../../lib/knex.ts' import sendMail from '../../../lib/send_mail.ts' import StatusError from '../../../lib/status_error.ts' import { StatusErrorSchema } from '../../../schemas/status_error.ts' import { generateToken } from '../helpers.ts' import forgotPasswordTemplate from '../../../templates/emails/forgot_password.ts' const { errors } = config.auth const BodySchema = Type.Object({ email: Type.String({ format: 'email' }), }) const ResponseSchema = { 204: {}, '4XX': StatusErrorSchema, } const forgotPassword: RouteHandler<{ Body: Static }> = async function (request, reply) { const { email } = request.body try { const user = await knex('user').first('id').where({ email }) if (!user) throw new StatusError(...errors.noUserFound) const token = generateToken() await knex('password_token').insert({ userId: user.id, token }) const link = `${new URL('/admin/change-password', config.site.url)}?email=${encodeURI(email)}&token=${token}` await sendMail({ to: email, subject: `Reset password to ${config.site.title}!`, html: await forgotPasswordTemplate({ link, site: config.site }).text(), }) return reply.status(204).send() } catch (err) { this.log.error(err) if (err instanceof StatusError) return reply.status(err.status).send(err.toJSON()) else throw err } } export default { handler: forgotPassword, schema: { body: BodySchema, response: ResponseSchema, }, }