src/app/api/auth/client/verifier-email/route.ts

route·app·2.6 KB · 64 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.

1 export

POST

Code source· typescript

import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma/client";
import { getSession } from "@/lib/auth/session";
import { createHash, randomUUID } from "crypto";
import { envoyerMagicLink } from "@/lib/email";

const TTL = parseInt(process.env.MAGIC_LINK_TTL_SECONDS || "900");
const BASE_URL = process.env.MAGIC_LINK_BASE_URL || "http://localhost:3000";

export async function POST(req: NextRequest) {
  try {
    const session = await getSession();
    if (!session || session.role !== "CLIENT") {
      return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
    }
    const { newEmail, tenantId } = await req.json();

    const client = await prisma.clientAccount.findUnique({
      where: { id: session.userId },
      select: { email: true, name: true, prenom: true },
    });
    if (!client) return NextResponse.json({ error: "Client introuvable" }, { status: 404 });

    const emailCible = newEmail ?? client.email;
    if (!emailCible) return NextResponse.json({ error: "Aucun email à vérifier" }, { status: 400 });

    // Vérifier que le nouvel email n'est pas déjà pris
    if (newEmail && newEmail !== client.email) {
      const existant = await prisma.clientAccount.findFirst({ where: { email: newEmail } });
      if (existant) return NextResponse.json({ error: "Cet email est déjà utilisé" }, { status: 409 });
    }

    const rawToken = randomUUID();
    const hashedToken = createHash("sha256").update(rawToken).digest("hex");
    const expiresAt = new Date(Date.now() + TTL * 1000);

    await prisma.magicToken.create({
      data: {
        token: hashedToken,
        clientId: session.userId,
        tenantId: tenantId ?? "wari",
        identifier: emailCible,
        identifierType: "email",
        expiresAt,
      },
    });

    const source = newEmail ? "change-email" : "verify-email";
    const newEmailParam = newEmail ? "&newEmail=" + encodeURIComponent(newEmail) : "";
    const tenantBaseUrl = !tenantId || tenantId === "wari" ? BASE_URL : BASE_URL.replace("https://", "https://" + tenantId + ".");
    const magicLink = tenantBaseUrl + "/auth/client/verify?token=" + rawToken + "&source=" + source + newEmailParam;

    const tenant = await prisma.tenant.findUnique({ where: { subdomain: tenantId ?? "" }, select: { nom: true } });
    const tenantNom = tenant?.nom ?? "wari.pro";

    await envoyerMagicLink({ identifier: emailCible, magicLink, tenantNom, expiresInMinutes: Math.round(TTL / 60) });

    return NextResponse.json({ success: true });
  } catch (error) {
    console.error("verifier-email error:", error);
    return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });
  }
}