67 lines
1.7 KiB
TypeScript
67 lines
1.7 KiB
TypeScript
"use server";
|
|
|
|
import { createHash, randomBytes } from "crypto";
|
|
import { db } from "@/lib/db";
|
|
import { sendMail } from "@/lib/mail";
|
|
import { checkRateLimit } from "@/lib/rate-limit";
|
|
|
|
export type RecuperarSenhaState = {
|
|
ok: boolean;
|
|
message?: string;
|
|
};
|
|
|
|
function hashToken(token: string) {
|
|
return createHash("sha256").update(token).digest("hex");
|
|
}
|
|
|
|
export async function solicitarRecuperacao(
|
|
_state: RecuperarSenhaState,
|
|
formData: FormData
|
|
): Promise<RecuperarSenhaState> {
|
|
const email = formData.get("email")?.toString().trim().toLowerCase();
|
|
const genericMessage = "Se o e-mail estiver cadastrado, enviaremos as instrucoes de redefinicao.";
|
|
const limit = checkRateLimit(`recuperar-senha:${email ?? "sem-email"}`, 5, 60 * 60 * 1000);
|
|
|
|
if (!limit.allowed) {
|
|
return { ok: true, message: genericMessage };
|
|
}
|
|
|
|
if (!email) {
|
|
return { ok: true, message: genericMessage };
|
|
}
|
|
|
|
const user = await db.user.findUnique({
|
|
where: { email },
|
|
select: { id: true, email: true }
|
|
});
|
|
|
|
if (!user) {
|
|
return { ok: true, message: genericMessage };
|
|
}
|
|
|
|
const token = randomBytes(32).toString("base64url");
|
|
const tokenHash = hashToken(token);
|
|
const expiraEm = new Date(Date.now() + 60 * 60 * 1000);
|
|
|
|
await db.passwordResetToken.create({
|
|
data: {
|
|
userId: user.id,
|
|
tokenHash,
|
|
expiraEm
|
|
}
|
|
});
|
|
|
|
const baseUrl = process.env.APP_URL ?? "http://localhost:3000";
|
|
const resetUrl = `${baseUrl}/redefinir-senha?token=${token}`;
|
|
|
|
await sendMail({
|
|
to: user.email,
|
|
subject: "Redefinicao de senha - Briefing SeConectai",
|
|
text: `Use o link abaixo para redefinir sua senha. Ele expira em 1 hora.\n\n${resetUrl}`
|
|
});
|
|
|
|
return { ok: true, message: genericMessage };
|
|
}
|
|
|
|
export { hashToken };
|