Schéma dédié `photobooth` (jamais exposé via PostgREST, accès exclusivement via fonctions SECURITY DEFINER dans public) avec RLS, policies Storage sur bucket privé event-photos, Edge Functions admin-gallery et expire-events, et job pg_cron d'expiration J+7. Le tout déployé et testé en conditions réelles sur le projet Supabase kevin-lecou-hub avant relecture sécurité (faille d'abus sur insert_public_photo corrigée en cours de route). Côté front : page upload invité (compression + HEIC + RGPD), galerie admin avec export ZIP, générateur de QR code autonome. Workflow n8n de purge Storage J+7 fourni (à activer manuellement côté n8n).
41 lines
1.6 KiB
TypeScript
41 lines
1.6 KiB
TypeScript
// Helpers CORS partagés entre les Edge Functions du projet photobooth-qr.
|
|
//
|
|
// `admin-gallery` est appelée directement depuis le navigateur (page galerie
|
|
// admin, cf. contrat fixé par le chef de projet) : elle a donc besoin de
|
|
// CORS. `expire-events` est appelée uniquement en serveur-à-serveur
|
|
// (cron/n8n), elle n'en a pas besoin mais ça ne coûte rien de partager le
|
|
// helper.
|
|
//
|
|
// APP_BASE_URL doit être configurée comme secret de l'Edge Function
|
|
// (`supabase secrets set APP_BASE_URL=...`), avec la même valeur que
|
|
// .env.example côté front : c'est l'unique origine autorisée à appeler ces
|
|
// fonctions en cross-origin. Volontairement PAS de fallback vers "*" : une
|
|
// route qui peut renvoyer des données nominatives (nom_invite, message) ne
|
|
// doit pas être appelable depuis n'importe quelle origine.
|
|
const APP_BASE_URL = Deno.env.get("APP_BASE_URL");
|
|
|
|
if (!APP_BASE_URL) {
|
|
console.warn(
|
|
"[_shared/cors] APP_BASE_URL n'est pas configurée : Access-Control-Allow-Origin sera 'null' " +
|
|
"(aucune origine navigateur ne pourra appeler cette fonction en cross-origin)."
|
|
);
|
|
}
|
|
|
|
export function corsHeaders(): HeadersInit {
|
|
return {
|
|
"Access-Control-Allow-Origin": APP_BASE_URL ?? "null",
|
|
"Access-Control-Allow-Headers":
|
|
"authorization, x-client-info, apikey, content-type",
|
|
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
Vary: "Origin",
|
|
};
|
|
}
|
|
|
|
/** Renvoie une réponse pour une requête OPTIONS (preflight), sinon null. */
|
|
export function handleCorsPreflight(req: Request): Response | null {
|
|
if (req.method === "OPTIONS") {
|
|
return new Response("ok", { headers: corsHeaders() });
|
|
}
|
|
return null;
|
|
}
|