Files
tribunal-app/src/lib/supabase/middleware.ts
T
Valentin ROBIN 86756c41da Corrige les comptes invités qui restaient bloqués sans mot de passe
Le pseudo temporaire fixe "Nouveau membre" entrait en collision (contrainte
unique) dès qu'une 2e personne était invitée avant que la 1re ait fini son
inscription ; il inclut maintenant un suffixe d'uuid. Le token d'invitation
pouvait aussi s'établir sur n'importe quelle page (pas seulement /signup),
laissant certains comptes connectés sans jamais voir le formulaire de mot
de passe — /signup affiche désormais un état de chargement au lieu d'un
écran vide, et le proxy renvoie systématiquement vers /signup tant que le
compte n'est pas finalisé.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 22:12:31 +02:00

86 lines
2.6 KiB
TypeScript

import { createServerClient } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";
const PROTECTED_PATHS = [
"/leaderboard",
"/profile",
"/admin",
"/journal",
"/calendrier",
"/icare",
"/char",
"/mur",
"/urne",
];
// /signup n'est PAS dans AUTH_PATHS : un compte fraîchement invité a déjà une
// session (établie par le lien d'invitation) mais doit pouvoir rester sur
// /signup pour finaliser mot de passe/pseudo/photo sans être renvoyé au
// leaderboard par ce redirect avant d'avoir terminé.
const AUTH_PATHS = ["/login"];
export async function updateSession(request: NextRequest) {
let response = NextResponse.next({ request });
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll();
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value));
response = NextResponse.next({ request });
cookiesToSet.forEach(({ name, value, options }) =>
response.cookies.set(name, value, options),
);
},
},
},
);
const {
data: { user },
} = await supabase.auth.getUser();
const { pathname } = request.nextUrl;
const isProtected = PROTECTED_PATHS.some((path) => pathname.startsWith(path));
const isAuthPath = AUTH_PATHS.some((path) => pathname.startsWith(path));
const isSignup = pathname.startsWith("/signup");
if (!user && isProtected) {
const url = request.nextUrl.clone();
url.pathname = "/login";
return NextResponse.redirect(url);
}
// Le token d'un lien d'invitation Supabase s'établit dès qu'il touche le
// navigateur (detectSessionInUrl du SDK), sur N'IMPORTE QUELLE page, pas
// seulement /signup. Si le compte n'a pas encore fini son inscription
// (pseudo toujours au placeholder du trigger handle_new_user), on le
// renvoie systématiquement vers /signup pour ne jamais le laisser bloqué
// connecté mais sans mot de passe choisi.
if (user && !isSignup) {
const { data: profile } = await supabase
.from("profiles")
.select("pseudo")
.eq("id", user.id)
.single();
if (profile?.pseudo.startsWith("Nouveau membre")) {
const url = request.nextUrl.clone();
url.pathname = "/signup";
return NextResponse.redirect(url);
}
}
if (user && isAuthPath) {
const url = request.nextUrl.clone();
url.pathname = "/leaderboard";
return NextResponse.redirect(url);
}
return response;
}