// Connexion en un clic au compte de démonstration (accès aux deux cours). // Compte étudiant PARTAGÉ, prévu pour l'essai de la plateforme — désactivable // via DEMO_ACCOUNT_ENABLED=false. import { NextResponse } from "next/server"; import { randomBytes } from "node:crypto"; import { apiError } from "@/lib/api.ts"; import { hashPassword } from "@/lib/auth/password.ts"; import { rateLimit } from "@/lib/auth/rate-limit.ts"; import { SESSION_COOKIE, assertSameOrigin, createSession, logAuthEvent } from "@/lib/auth/session.ts"; import { get, run } from "@/lib/db/index.ts"; const DEMO_USERNAME = "demo.etudiant"; export async function POST(req: Request) { try { await assertSameOrigin(); if (process.env.DEMO_ACCOUNT_ENABLED === "false") { return NextResponse.json({ error: "Le compte de démonstration est désactivé." }, { status: 403 }); } const ip = req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || "local"; const rl = rateLimit(`demo:${ip}`, 10, 60 * 60 * 1000); if (!rl.ok) return NextResponse.json({ error: "Trop de connexions démo. Réessayez plus tard." }, { status: 429 }); let user = get<{ id: number; disabled: number }>("SELECT id, disabled FROM users WHERE username = ?", DEMO_USERNAME); if (!user) { // Mot de passe aléatoire jamais communiqué : ce compte ne se connecte que par ce bouton. const r = run( "INSERT INTO users (username, display_name, password_hash, role) VALUES (?, 'Étudiant·e démo', ?, 'student')", DEMO_USERNAME, hashPassword(randomBytes(24).toString("hex")) ); user = { id: Number(r.lastInsertRowid), disabled: 0 }; } if (user.disabled) return NextResponse.json({ error: "Le compte de démonstration est désactivé." }, { status: 403 }); run("INSERT OR IGNORE INTO enrollments (user_id, course_code) VALUES (?, 'IMM1003'), (?, 'IMM1033')", user.id, user.id); const { token, expiresAt } = createSession(user.id, ip, req.headers.get("user-agent") ?? undefined); logAuthEvent("demo-login", { userId: user.id, username: DEMO_USERNAME, ip }); const res = NextResponse.json({ ok: true }); res.cookies.set(SESSION_COOKIE, token, { httpOnly: true, sameSite: "lax", secure: process.env.NODE_ENV === "production" && (process.env.APP_URL ?? "").startsWith("https"), expires: expiresAt, path: "/", }); return res; } catch (e) { return apiError(e); } }