src/app/api/auth/admin/reset-mdp/route.ts

route·app·3.5 KB · 91 lignes· Voir l'itinéraire
Annotation non disponible

Lance npm run annotate (nécessite ANTHROPIC_API_KEY dans .env.local) pour générer une annotation française par Claude Haiku 4.5.

2 exports

POSTPATCH

Code source· typescript

import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma/client";
import { Resend } from "resend";
import crypto from "crypto";

const resend = new Resend(process.env.RESEND_API_KEY);

// POST /api/auth/admin/reset-mdp — demande de reset
export async function POST(req: NextRequest) {
  try {
    const { email } = await req.json();
    if (!email) return NextResponse.json({ error: "Email requis" }, { status: 400 });

    const user = await prisma.user.findFirst({
      where: { email: email.toLowerCase().trim() },
      include: { tenant: { select: { nom: true, subdomain: true } } },
    });

    // Toujours répondre OK pour ne pas révéler si l'email existe
    if (!user) return NextResponse.json({ success: true });

    const token = crypto.randomBytes(32).toString("hex");
    const expiry = new Date(Date.now() + 1000 * 60 * 60); // 1h

    await prisma.user.update({
      where: { id: user.id },
      data: { resetToken: token, resetTokenExpiry: expiry },
    });

    const domain = process.env.DOMAIN || "wari.pro";
    const resetUrl = `https://${domain}/admin/reset-mdp?token=${token}`;
    const tenantNom = user.tenant?.nom ?? "wari.pro";

    await resend.emails.send({
      from: `${tenantNom} <noreply@wari.pro>`,
      to: user.email,
      subject: "Réinitialisation de votre mot de passe",
      html: `
        <div style="font-family:sans-serif;max-width:480px;margin:0 auto;padding:32px">
          <h2 style="font-size:18px;color:#111;margin-bottom:8px">Réinitialisation du mot de passe</h2>
          <p style="color:#555;font-size:14px;margin-bottom:24px">
            Vous avez demandé à réinitialiser votre mot de passe pour votre espace prestataire ${tenantNom}.
          </p>
          <a href="${resetUrl}" style="display:inline-block;background:#111;color:#fff;padding:12px 24px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:500">
            Réinitialiser mon mot de passe
          </a>
          <p style="color:#999;font-size:12px;margin-top:24px">
            Ce lien expire dans 1 heure. Si vous n'avez pas fait cette demande, ignorez cet email.
          </p>
        </div>
      `,
    });

    return NextResponse.json({ success: true });
  } catch (error) {
    console.error("reset-mdp admin POST error:", error);
    return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });
  }
}

// PATCH /api/auth/admin/reset-mdp — confirmer le nouveau mot de passe
export async function PATCH(req: NextRequest) {
  try {
    const { token, motDePasse } = await req.json();
    if (!token || !motDePasse) return NextResponse.json({ error: "Données manquantes" }, { status: 400 });
    if (motDePasse.length < 8) return NextResponse.json({ error: "Mot de passe trop court (8 caractères min)" }, { status: 400 });

    const user = await prisma.user.findFirst({
      where: {
        resetToken: token,
        resetTokenExpiry: { gt: new Date() },
      },
    });

    if (!user) return NextResponse.json({ error: "Lien invalide ou expiré" }, { status: 400 });

    const bcrypt = await import("bcryptjs");
    const hash = await bcrypt.hash(motDePasse, 10);

    await prisma.user.update({
      where: { id: user.id },
      data: { motDePasseHash: hash, resetToken: null, resetTokenExpiry: null },
    });

    return NextResponse.json({ success: true });
  } catch (error) {
    console.error("reset-mdp admin PATCH error:", error);
    return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });
  }
}