1. MIME spoofing (upload) — app/api/admin/upload/route.ts
- Ajout de la validation par magic bytes : lit les premiers octets du
fichier et vérifie la signature binaire réelle (JPEG FF D8 FF,
PNG 89 50 4E 47, GIF 47 49 46 38, WebP RIFF+WEBP, AVIF ftyp box)
- Extension dérivée exclusivement du MIME validé côté serveur
(MIME_TO_EXT), jamais du nom de fichier fourni par le client
- Un fichier .exe renommé en .jpg est désormais rejeté
2. Générateur de mot de passe non-cryptographique — stripe/webhook/route.ts
- Remplace Math.random() (non-déterministe mais prévisible) par
crypto.getRandomValues() (CSPRNG, conforme Web Crypto API)
3. Headers HTTP de sécurité manquants — middleware.ts (nouveau)
- X-Content-Type-Options: nosniff (anti MIME-sniffing navigateur)
- X-Frame-Options: SAMEORIGIN (anti clickjacking)
- Referrer-Policy: strict-origin-when-cross-origin
- Permissions-Policy: désactive camera, micro, geolocation
- Content-Security-Policy: whitelist stricte par type de ressource
(scripts, styles, images Unsplash/Supabase/Sanity, connect Supabase/Stripe,
frames Stripe uniquement, object-src none, form-action self)
https://claude.ai/code/session_01PzA98VhLMmsHpzs7gnLHGs
- app/macon/page.tsx + app/paysagiste/page.tsx : ajout de
export const revalidate = 60 pour activer l'ISR (les pages étaient
générées statiquement à la build, getSiteImages() n'était jamais
rappelé entre deux déploiements)
- app/api/admin/site-images/route.ts : appel de revalidatePath() après
chaque PUT réussi pour purger immédiatement le cache de la page
concernée (macon_, paysagiste_ → leur page démo, sinon → /)
Résultat : la page se met à jour dans la seconde qui suit la sauvegarde
dans l'admin, sans attendre le délai de 60s
https://claude.ai/code/session_01PzA98VhLMmsHpzs7gnLHGs
- Nouvelle route POST /api/admin/upload : upload multipart vers le bucket
private-gallery, validation MIME + taille (max 5 Mo), retourne storage:path
- lib/site-images.ts : détecte le préfixe "storage:" et génère une Signed
URL temporaire (60 min) côté serveur avant chaque rendu de page
- GET /api/admin/site-images : résout aussi les signed URLs pour les previews
admin (champ previewUrl distinct de url brute)
- PUT /api/admin/site-images : accepte désormais les chemins "storage:..."
en plus des URLs externes
- Page admin images : drag & drop + input file avec upload automatique +
sauvegarde en BDD, badge "bucket privé", instructions SQL pour créer
la table et la policy du bucket private-gallery
https://claude.ai/code/session_01PzA98VhLMmsHpzs7gnLHGs
- Redesign Hero section with new copy focused on the triptych offering
- Add Process component (replaces System) with zigzag layout for 3 pillars:
Google Maps reviews, managed Facebook, converting website
- Redesign AboutMe with orange background and stats row
- Add admin panel for managing site image URLs (replaces Sanity dependency)
- Create site_images API routes and Supabase-backed storage with defaults
- Update FAQ to reference built-in admin panel
- Add site_images table type to database types
- Pass images prop through homepage components
https://claude.ai/code/session_01V8YAjpqRQ3bfBYsABYsEgo
- Email sending now independent from Stripe payment link generation
- Professional dark-themed HTML email template matching HookLab branding
- Return emailSent/emailError/stripeError status in API response
- Admin UI shows detailed status after approve action
- Default to onboarding@resend.dev when no custom domain
https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
Allow sending emails without custom domain by defaulting to Resend's
free onboarding address. Set RESEND_FROM_EMAIL env var later when
hooklab.fr domain is purchased and verified.
https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
- Add /setup-admin page for first-time admin account creation
- Add /api/admin/setup route (only works when no admin exists)
- Update login to redirect admins to /admin instead of /dashboard
- Setup page creates auth user + profile with is_admin=true
https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
- /admin page with secret-key authentication
- List all candidatures with details (expandable cards)
- Approve: updates status + generates Stripe checkout URL + sends email
- Reject: updates status
- Checkout URL displayed on screen for manual copy if Resend not configured
- Protected by ADMIN_SECRET env var
https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y