// Auteur : Simon-Pierre Boucher — contact@spboucher.ai // Profil serveur-à-serveur pour les plateformes du groupe : le hub est LA // source de vérité — Lou·Ka & cie affichent CE profil sur leurs pages // utilisateur. Authentification par HMAC du secret SSO partagé du client. // GET /api/sso/profile?client_id=lou-ka&ka_id=ka-…&ts=&sig= // sig = HMAC-SHA256(secret_client, `${client_id}.${ka_id}.${ts}`), ts ±5 min import { NextRequest, NextResponse } from "next/server"; import crypto from "crypto"; import { db, parseSocials, ageFromBirthDate, type UserRow } from "@/lib/db"; import { SSO_CLIENTS } from "@/lib/sso"; import { roleLabel } from "@/lib/roles"; export async function GET(req: NextRequest) { const q = req.nextUrl.searchParams; const clientId = q.get("client_id") ?? ""; const kaId = q.get("ka_id") ?? ""; const ts = q.get("ts") ?? ""; const sig = q.get("sig") ?? ""; const client = SSO_CLIENTS[clientId]; const secret = client ? process.env[client.secretEnv] : undefined; if (!client || !secret) return NextResponse.json({ error: "client inconnu" }, { status: 401 }); if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return NextResponse.json({ error: "horodatage expiré" }, { status: 401 }); const expected = crypto .createHmac("sha256", secret) .update(`${clientId}.${kaId}.${ts}`) .digest("hex"); const a = Buffer.from(sig, "hex"); const b = Buffer.from(expected, "hex"); if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) return NextResponse.json({ error: "signature invalide" }, { status: 401 }); const row = db .prepare("SELECT * FROM users WHERE ka_id = ?") .get(kaId) as UserRow | undefined; if (!row) return NextResponse.json({ error: "membre introuvable" }, { status: 404 }); return NextResponse.json({ ka_id: row.ka_id, name: row.name, email: row.email, picture: row.avatar_url, role: row.role, role_label: roleLabel(row.role), bio: row.bio ?? "", city: row.city ?? "", phone: row.phone ?? "", website: row.website ?? "", job_title: row.job_title ?? "", company: row.company ?? "", birth_date: row.birth_date ?? "", age: ageFromBirthDate(row.birth_date), socials: parseSocials(row.socials), public: !!row.public, public_url: row.public ? `https://www.groupe-ka.com/u/${row.ka_id}` : null, created_at: row.created_at, }); }