96 lines
No EOL
3.1 KiB
TypeScript
96 lines
No EOL
3.1 KiB
TypeScript
import { NextResponse } from "next/server";
|
||
import { cookies } from "next/headers";
|
||
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
|
||
import { createClient } from "@supabase/supabase-js";
|
||
|
||
/**
|
||
* Applique les cookies persistants si rememberMe est activé
|
||
*/
|
||
function applyRememberMeCookies(response: NextResponse, rememberMe?: boolean) {
|
||
if (rememberMe) {
|
||
// Définir un cookie remember_me pour le middleware
|
||
response.cookies.set("remember_me", "true", {
|
||
maxAge: 60 * 60 * 24 * 30, // 30 jours
|
||
path: "/",
|
||
sameSite: "lax",
|
||
httpOnly: true,
|
||
secure: process.env.NODE_ENV === "production",
|
||
});
|
||
|
||
// Prolonger la durée des cookies Supabase
|
||
const cookieStore = cookies();
|
||
const allCookies = cookieStore.getAll();
|
||
|
||
allCookies.forEach((cookie) => {
|
||
if (cookie.name.startsWith("sb-")) {
|
||
response.cookies.set(cookie.name, cookie.value, {
|
||
maxAge: 60 * 60 * 24 * 30, // 30 jours
|
||
path: "/",
|
||
sameSite: "lax",
|
||
httpOnly: true,
|
||
secure: process.env.NODE_ENV === "production",
|
||
});
|
||
}
|
||
});
|
||
|
||
console.log("✅ [verify-code] Cookies persistants activés pour 30 jours");
|
||
} else {
|
||
// Supprimer le cookie remember_me s'il existe
|
||
response.cookies.set("remember_me", "", {
|
||
maxAge: 0,
|
||
path: "/",
|
||
});
|
||
console.log("ℹ️ [verify-code] Cookies de session (non persistants)");
|
||
}
|
||
}
|
||
|
||
export async function POST(req: Request) {
|
||
try {
|
||
const { email, code, rememberMe } = await req.json();
|
||
if (!email || !code) return new NextResponse("Email et code requis", { status: 400 });
|
||
|
||
const supabase = createRouteHandlerClient({ cookies });
|
||
const { data, error } = await supabase.auth.verifyOtp({ email, token: code, type: "email" });
|
||
if (error) return new NextResponse(error.message, { status: 400 });
|
||
|
||
const userId = (data?.user || data?.session?.user)?.id as string | undefined;
|
||
if (!userId) return new NextResponse("No user", { status: 400 });
|
||
|
||
const srv = createClient(
|
||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||
process.env.SUPABASE_SERVICE_ROLE_KEY!,
|
||
{ auth: { autoRefreshToken: false, persistSession: false } }
|
||
);
|
||
|
||
// 1) Si Staff → OK direct
|
||
const { data: su } = await srv
|
||
.from("staff_users")
|
||
.select("is_staff")
|
||
.eq("user_id", userId)
|
||
.maybeSingle();
|
||
|
||
if (su?.is_staff) {
|
||
const response = NextResponse.json({ ok: true });
|
||
applyRememberMeCookies(response, rememberMe);
|
||
return response;
|
||
}
|
||
|
||
// 2) Sinon, vérifier la révocation (user à une seule org)
|
||
const { data: mem } = await srv
|
||
.from("organization_members")
|
||
.select("revoked")
|
||
.eq("user_id", userId)
|
||
.maybeSingle();
|
||
|
||
if (!mem || mem.revoked) {
|
||
await supabase.auth.signOut();
|
||
return new NextResponse("revoked", { status: 403 });
|
||
}
|
||
|
||
const response = NextResponse.json({ ok: true });
|
||
applyRememberMeCookies(response, rememberMe);
|
||
return response;
|
||
} catch (e: any) {
|
||
return new NextResponse(e?.message || "Internal Server Error", { status: 500 });
|
||
}
|
||
} |