diff --git a/assets/js/contact-form.js b/assets/js/contact-form.js index 8d2071c..8c8834c 100644 --- a/assets/js/contact-form.js +++ b/assets/js/contact-form.js @@ -294,7 +294,38 @@ class ContactFormPersistence { } } +const RecaptchaService = { + siteKey: null, + + init() { + this.siteKey = window.RECAPTCHA_SITE_KEY || null; + }, + + isAvailable() { + return this.siteKey && typeof grecaptcha !== 'undefined'; + }, + + async getToken(action = 'contact') { + if (!this.isAvailable()) { + console.warn('reCAPTCHA non disponible, envoi sans protection'); + return ''; + } + + return new Promise((resolve) => { + grecaptcha.ready(() => { + grecaptcha.execute(this.siteKey, { action }) + .then((token) => resolve(token)) + .catch((error) => { + console.error('Erreur reCAPTCHA:', error); + resolve(''); + }); + }); + }); + } +}; + document.addEventListener('DOMContentLoaded', () => { + RecaptchaService.init(); window.contactFormValidator = new FormValidator('contact-form'); window.contactFormPersistence = new ContactFormPersistence('contact-form'); }); diff --git a/docs/stories/5.4.integration-recaptcha.md b/docs/stories/5.4.integration-recaptcha.md index 8b4ac3e..1a5c556 100644 --- a/docs/stories/5.4.integration-recaptcha.md +++ b/docs/stories/5.4.integration-recaptcha.md @@ -2,7 +2,7 @@ ## Status -Ready for Dev +review ## Story @@ -21,29 +21,29 @@ Ready for Dev ## Tasks / Subtasks -- [] **Task 1 : Configurer les clés reCAPTCHA** (AC: 5) - - [] Ajouter RECAPTCHA_SITE_KEY dans .env - - [] Ajouter RECAPTCHA_SECRET_KEY dans .env - - [] Créer includes/config.php pour charger .env et définir les constantes +- [x] **Task 1 : Configurer les clés reCAPTCHA** (AC: 5) + - [x] Ajouter RECAPTCHA_SITE_KEY dans .env + - [x] Ajouter RECAPTCHA_SECRET_KEY dans .env + - [x] Créer includes/config.php pour charger .env et définir les constantes -- [] **Task 2 : Charger le script Google** (AC: 2) - - [] Ajouter le script dans templates/footer.php - - [] Charger de manière asynchrone (async defer) - - [] Exposer la site key via window.RECAPTCHA_SITE_KEY +- [x] **Task 2 : Charger le script Google** (AC: 2) + - [x] Ajouter le script dans templates/footer.php + - [x] Charger de manière asynchrone (async defer) + - [x] Exposer la site key via window.RECAPTCHA_SITE_KEY -- [] **Task 3 : Générer le token** (AC: 3) - - [] Créer RecaptchaService dans contact-form.js - - [] Méthode getToken() avec grecaptcha.execute() - - [] Retourne une Promise avec le token +- [x] **Task 3 : Générer le token** (AC: 3) + - [x] Créer RecaptchaService dans contact-form.js + - [x] Méthode getToken() avec grecaptcha.execute() + - [x] Retourne une Promise avec le token -- [] **Task 4 : Envoyer le token au backend** (AC: 4) - - [] RecaptchaService.getToken() prêt à être utilisé - - [] Intégration avec AJAX dans Story 5.5/5.6 +- [x] **Task 4 : Envoyer le token au backend** (AC: 4) + - [x] RecaptchaService.getToken() prêt à être utilisé + - [x] Intégration avec AJAX dans Story 5.5/5.6 -- [] **Task 5 : Dégradation gracieuse** (AC: 6) - - [] isAvailable() vérifie si grecaptcha est défini - - [] Retourne chaîne vide si indisponible - - [] console.warn si non disponible +- [x] **Task 5 : Dégradation gracieuse** (AC: 6) + - [x] isAvailable() vérifie si grecaptcha est défini + - [x] Retourne chaîne vide si indisponible + - [x] console.warn si non disponible ## Dev Notes @@ -223,7 +223,11 @@ Si reCAPTCHA échoue : ## Dev Agent Record ### Agent Model Used -Claude Opus 4.5 (claude-opus-4-5-20251101) +GPT-5 Codex + +### Implementation Plan +- Implémenter les tâches 1 à 5 dans l’ordre avec tests à chaque étape. +- Ajouter config .env + chargement côté PHP, puis service JS reCAPTCHA. ### File List | File | Action | Description | @@ -233,15 +237,14 @@ Claude Opus 4.5 (claude-opus-4-5-20251101) | `index.php` | Modified | Ajout require config.php | | `templates/footer.php` | Modified | Script reCAPTCHA + window.RECAPTCHA_SITE_KEY | | `assets/js/contact-form.js` | Modified | Ajout RecaptchaService | +| `tests/recaptcha.test.php` | Added | Tests recaptcha (config + scripts) | +| `tests/run.ps1` | Modified | Ajout du test recaptcha | ### Completion Notes -- Système de chargement .env avec loadEnv() dans config.php -- Constantes PHP : RECAPTCHA_SITE_KEY, RECAPTCHA_SECRET_KEY, APP_ENV, etc. -- Script Google chargé en async/defer dans footer.php -- RecaptchaService avec méthodes init(), isAvailable(), getToken() -- Dégradation gracieuse : retourne '' si reCAPTCHA indisponible -- Clés de test Google utilisées en développement (score toujours 0.9) -- La vérification côté serveur sera implémentée dans Story 5.5 +- Chargement .env + constantes RECAPTCHA_* via config.php +- Script Google async/defer + window.RECAPTCHA_SITE_KEY +- RecaptchaService init/isAvailable/getToken + dégradation gracieuse +- Tests : `powershell -ExecutionPolicy Bypass -File tests/run.ps1` ### Debug Log References Aucun problème rencontré. @@ -252,3 +255,4 @@ Aucun problème rencontré. |------|---------|-------------|--------| | 2026-01-22 | 0.1 | Création initiale | Sarah (PO) | | 2026-01-24 | 1.0 | Implémentation complète | James (Dev) | +| 2026-02-04 | 1.1 | Intégration reCAPTCHA v3 | Amelia (Dev) | diff --git a/includes/config.php b/includes/config.php new file mode 100644 index 0000000..e05b89c --- /dev/null +++ b/includes/config.php @@ -0,0 +1,46 @@ +add('/a-propos', 'pages/about.php') ->add('/contact', 'pages/contact.php'); -$router->dispatch(); \ No newline at end of file +$router->dispatch(); diff --git a/templates/footer.php b/templates/footer.php index 29e4b9b..071c0bd 100644 --- a/templates/footer.php +++ b/templates/footer.php @@ -15,5 +15,11 @@ $currentYear = date('Y'); + + + + - \ No newline at end of file + diff --git a/tests/recaptcha.test.php b/tests/recaptcha.test.php new file mode 100644 index 0000000..73ea6d4 --- /dev/null +++ b/tests/recaptcha.test.php @@ -0,0 +1,34 @@ +