refactor: reorganizar openspec y planificacion con spec recaptcha
- renombrar openspec/ a _openspec/ (carpeta auxiliar) - mover specs de features a changes/ - crear specs base: arquitectura-limpia, estandares-codigo, nomenclatura - migrar _planificacion/ con design-system y roi-theme-template - agregar especificacion recaptcha anti-spam (proposal, tasks, spec) - corregir rutas y referencias en todas las specs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
111
_openspec/changes/recaptcha-anti-spam/proposal.md
Normal file
111
_openspec/changes/recaptcha-anti-spam/proposal.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# Proposal: reCAPTCHA v3 Anti-Spam Protection
|
||||
|
||||
## Problema
|
||||
|
||||
Los formularios del sitio (Newsletter Footer y Contact Form) carecen de protección CAPTCHA, haciéndolos vulnerables a spam automatizado. Actualmente solo cuentan con:
|
||||
- Nonce de WordPress
|
||||
- Rate limiting básico
|
||||
- Sanitización de inputs
|
||||
- Validación de email
|
||||
|
||||
## Solución Propuesta
|
||||
|
||||
Implementar **Google reCAPTCHA v3** como capa adicional de protección anti-spam.
|
||||
|
||||
### Por qué reCAPTCHA v3
|
||||
|
||||
| Característica | reCAPTCHA v2 | reCAPTCHA v3 |
|
||||
|----------------|--------------|--------------|
|
||||
| UX | Requiere interacción (checkbox/imágenes) | Invisible, sin fricción |
|
||||
| Detección | Binaria (humano/bot) | Score 0.0-1.0 |
|
||||
| Flexibilidad | Fija | Configurable por score |
|
||||
| Impacto en conversión | Negativo | Mínimo |
|
||||
|
||||
### Credenciales
|
||||
|
||||
```
|
||||
Site Key: 6LevZUQsAAAAAB6wcQ4iE6ckaTwgVR_ScBL3vqSj
|
||||
```
|
||||
|
||||
> **Nota**: El Secret Key debe almacenarse en wp-config.php o como opción encriptada en BD, NUNCA en código fuente.
|
||||
|
||||
## Arquitectura Propuesta
|
||||
|
||||
```
|
||||
Shared/
|
||||
├── Domain/
|
||||
│ └── Contracts/
|
||||
│ └── RecaptchaValidatorInterface.php
|
||||
├── Application/
|
||||
│ └── Services/
|
||||
│ └── RecaptchaValidationService.php
|
||||
└── Infrastructure/
|
||||
└── Services/
|
||||
└── GoogleRecaptchaValidator.php
|
||||
```
|
||||
|
||||
### Flujo de Validación
|
||||
|
||||
```
|
||||
1. Frontend: Usuario envía formulario
|
||||
2. Frontend: reCAPTCHA genera token automáticamente
|
||||
3. Backend: AjaxHandler recibe token con datos del form
|
||||
4. Backend: RecaptchaValidationService valida token con API de Google
|
||||
5. Backend: Si score < threshold → rechazar como spam
|
||||
6. Backend: Si score >= threshold → procesar formulario normalmente
|
||||
```
|
||||
|
||||
## Formularios Afectados
|
||||
|
||||
1. **Newsletter Footer** (`Public/Footer/Infrastructure/Api/WordPress/NewsletterAjaxHandler.php`)
|
||||
2. **Contact Form** (`Public/ContactForm/Infrastructure/Api/WordPress/ContactFormAjaxHandler.php`)
|
||||
|
||||
## Configuración Administrable
|
||||
|
||||
| Campo | Tipo | Default | Descripción |
|
||||
|-------|------|---------|-------------|
|
||||
| is_enabled | boolean | true | Habilitar/deshabilitar reCAPTCHA |
|
||||
| site_key | text | - | Clave pública de reCAPTCHA |
|
||||
| secret_key | text | - | Clave secreta (encriptada) |
|
||||
| score_threshold | select | 0.5 | Umbral mínimo (0.3, 0.5, 0.7, 0.9) |
|
||||
| action_newsletter | text | newsletter_submit | Acción para newsletter |
|
||||
| action_contact | text | contact_submit | Acción para contacto |
|
||||
|
||||
## Impacto
|
||||
|
||||
### Archivos a Crear
|
||||
- `Shared/Domain/Contracts/RecaptchaValidatorInterface.php`
|
||||
- `Shared/Domain/Entities/RecaptchaResult.php`
|
||||
- `Shared/Application/Services/RecaptchaValidationService.php`
|
||||
- `Shared/Infrastructure/Services/GoogleRecaptchaValidator.php`
|
||||
- `Schemas/recaptcha-settings.json`
|
||||
- `Admin/RecaptchaSettings/Infrastructure/Ui/RecaptchaSettingsFormBuilder.php`
|
||||
- `Admin/RecaptchaSettings/Infrastructure/FieldMapping/RecaptchaSettingsFieldMapper.php`
|
||||
|
||||
### Archivos a Modificar
|
||||
- `Public/Footer/Infrastructure/Api/WordPress/NewsletterAjaxHandler.php`
|
||||
- `Public/ContactForm/Infrastructure/Api/WordPress/ContactFormAjaxHandler.php`
|
||||
- `Public/Footer/Infrastructure/Ui/FooterRenderer.php` (agregar script reCAPTCHA)
|
||||
- `Public/ContactForm/Infrastructure/Ui/ContactFormRenderer.php` (agregar script reCAPTCHA)
|
||||
- `functions.php` (registrar servicios en contenedor DI)
|
||||
- `Admin/Infrastructure/Ui/AdminDashboardRenderer.php` (registrar tab de reCAPTCHA)
|
||||
|
||||
## Riesgos y Mitigaciones
|
||||
|
||||
| Riesgo | Probabilidad | Mitigación |
|
||||
|--------|--------------|------------|
|
||||
| API Google no disponible | Baja | Fallback: permitir envío (fail-open) |
|
||||
| Falsos positivos | Media | Score threshold configurable |
|
||||
| Latencia adicional | Baja | Validación asíncrona, timeout corto |
|
||||
|
||||
## Criterios de Aceptación
|
||||
|
||||
1. reCAPTCHA v3 integrado en ambos formularios
|
||||
2. Score threshold configurable desde admin
|
||||
3. Logging de intentos bloqueados
|
||||
4. Sin impacto visible en UX del usuario
|
||||
5. Fallback funcional si API falla
|
||||
|
||||
## Última actualización
|
||||
|
||||
2025-01-08
|
||||
325
_openspec/changes/recaptcha-anti-spam/spec.md
Normal file
325
_openspec/changes/recaptcha-anti-spam/spec.md
Normal file
@@ -0,0 +1,325 @@
|
||||
# Especificación: reCAPTCHA v3 Anti-Spam Protection
|
||||
|
||||
## Purpose
|
||||
|
||||
Define la integración de Google reCAPTCHA v3 para proteger los formularios del sitio (Newsletter y Contact Form) contra spam automatizado, siguiendo Clean Architecture.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Configuración de reCAPTCHA
|
||||
|
||||
El sistema DEBE permitir configurar reCAPTCHA v3 desde el panel de administración.
|
||||
|
||||
#### Scenario: Schema JSON para configuración
|
||||
- **WHEN** se crea el schema de configuración
|
||||
- **THEN** DEBE ubicarse en `Schemas/recaptcha-settings.json`
|
||||
- **AND** `component_name` DEBE ser `recaptcha-settings`
|
||||
- **AND** DEBE incluir grupo VISIBILITY con `is_enabled`
|
||||
- **AND** DEBE incluir grupo BEHAVIOR con `site_key`, `secret_key`, `score_threshold`
|
||||
|
||||
#### Scenario: Campos obligatorios del schema
|
||||
- **GIVEN** el schema `recaptcha-settings.json`
|
||||
- **WHEN** se define la estructura
|
||||
- **THEN** `is_enabled` DEBE ser tipo boolean con default true
|
||||
- **AND** `site_key` DEBE ser tipo text (clave pública)
|
||||
- **AND** `secret_key` DEBE ser tipo text (clave secreta, almacenada encriptada)
|
||||
- **AND** `score_threshold` DEBE ser tipo select con options: 0.3, 0.5, 0.7, 0.9
|
||||
|
||||
#### Scenario: Sincronización con BD
|
||||
- **WHEN** se sincroniza el schema
|
||||
- **THEN** ejecutar `wp roi-theme sync-component recaptcha-settings`
|
||||
- **AND** los datos DEBEN ir a `wp_roi_theme_component_settings`
|
||||
- **AND** `component_name` en BD DEBE ser `recaptcha-settings`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Contrato de Validación (Domain)
|
||||
|
||||
El Domain DEBE definir la interfaz de validación de reCAPTCHA.
|
||||
|
||||
#### Scenario: Ubicación de RecaptchaValidatorInterface
|
||||
- **WHEN** se crea la interfaz
|
||||
- **THEN** DEBE ubicarse en `Shared/Domain/Contracts/RecaptchaValidatorInterface.php`
|
||||
- **AND** namespace DEBE ser `ROITheme\Shared\Domain\Contracts`
|
||||
|
||||
#### Scenario: Firma del método validate
|
||||
- **WHEN** se define RecaptchaValidatorInterface
|
||||
- **THEN** DEBE tener método `validate(string $token, string $action): RecaptchaResult`
|
||||
- **AND** `$token` es el token generado por reCAPTCHA frontend
|
||||
- **AND** `$action` es el nombre de la acción (newsletter_submit, contact_submit)
|
||||
- **AND** retorna objeto `RecaptchaResult` con score y success
|
||||
|
||||
#### Scenario: Entidad RecaptchaResult
|
||||
- **WHEN** se define el resultado de validación
|
||||
- **THEN** DEBE existir `Shared/Domain/Entities/RecaptchaResult.php`
|
||||
- **AND** DEBE tener propiedades: `success` (bool), `score` (float), `action` (string), `errorCodes` (array)
|
||||
- **AND** DEBE tener método `isValid(float $threshold): bool`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Servicio de Aplicación
|
||||
|
||||
La capa Application DEBE orquestar la validación de reCAPTCHA.
|
||||
|
||||
#### Scenario: Ubicación del servicio
|
||||
- **WHEN** se crea el servicio de aplicación
|
||||
- **THEN** DEBE ubicarse en `Shared/Application/Services/RecaptchaValidationService.php`
|
||||
- **AND** namespace DEBE ser `ROITheme\Shared\Application\Services`
|
||||
|
||||
#### Scenario: Inyección de dependencias
|
||||
- **WHEN** se implementa RecaptchaValidationService
|
||||
- **THEN** DEBE inyectar `RecaptchaValidatorInterface` via constructor
|
||||
- **AND** DEBE inyectar `ComponentSettingsRepositoryInterface` para obtener configuración
|
||||
- **AND** NO DEBE instanciar servicios directamente con `new`
|
||||
|
||||
#### Scenario: Lógica de validación con threshold
|
||||
- **GIVEN** un token de reCAPTCHA y una acción
|
||||
- **WHEN** se llama a `validateSubmission(string $token, string $action): bool`
|
||||
- **THEN** DEBE obtener `score_threshold` de la configuración en BD
|
||||
- **AND** DEBE llamar a `RecaptchaValidatorInterface::validate()`
|
||||
- **AND** DEBE retornar `true` si `RecaptchaResult::isValid($threshold)` es true
|
||||
- **AND** DEBE retornar `false` si score está por debajo del threshold
|
||||
|
||||
#### Scenario: Bypass cuando está deshabilitado
|
||||
- **GIVEN** `is_enabled` es false en configuración
|
||||
- **WHEN** se llama a `validateSubmission()`
|
||||
- **THEN** DEBE retornar `true` sin llamar a la API de Google
|
||||
- **AND** NO DEBE generar errores
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Implementación de Infraestructura
|
||||
|
||||
La capa Infrastructure DEBE implementar la comunicación con API de Google.
|
||||
|
||||
#### Scenario: Ubicación del validador
|
||||
- **WHEN** se implementa el validador
|
||||
- **THEN** DEBE ubicarse en `Shared/Infrastructure/Services/GoogleRecaptchaValidator.php`
|
||||
- **AND** namespace DEBE ser `ROITheme\Shared\Infrastructure\Services`
|
||||
- **AND** DEBE implementar `RecaptchaValidatorInterface`
|
||||
|
||||
#### Scenario: Llamada a API de Google
|
||||
- **WHEN** se valida un token
|
||||
- **THEN** DEBE hacer POST a `https://www.google.com/recaptcha/api/siteverify`
|
||||
- **AND** DEBE enviar `secret` (secret key) y `response` (token)
|
||||
- **AND** DEBE usar `wp_remote_post()` de WordPress
|
||||
- **AND** timeout DEBE ser máximo 5 segundos
|
||||
|
||||
#### Scenario: Parseo de respuesta exitosa
|
||||
- **GIVEN** API de Google responde exitosamente
|
||||
- **WHEN** se parsea la respuesta
|
||||
- **THEN** DEBE extraer `success` (bool)
|
||||
- **AND** DEBE extraer `score` (float 0.0-1.0)
|
||||
- **AND** DEBE extraer `action` (string)
|
||||
- **AND** DEBE retornar `RecaptchaResult` con estos valores
|
||||
|
||||
#### Scenario: Manejo de errores de API
|
||||
- **GIVEN** API de Google no responde o responde con error
|
||||
- **WHEN** se procesa la respuesta
|
||||
- **THEN** DEBE retornar `RecaptchaResult` con `success = false`
|
||||
- **AND** DEBE incluir códigos de error en `errorCodes`
|
||||
- **AND** NO DEBE lanzar excepciones no controladas
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Integración Frontend
|
||||
|
||||
Los Renderers DEBEN incluir el script de reCAPTCHA y generar tokens.
|
||||
|
||||
#### Scenario: Script de reCAPTCHA en FooterRenderer
|
||||
- **WHEN** FooterRenderer genera HTML del newsletter
|
||||
- **AND** reCAPTCHA está habilitado
|
||||
- **THEN** DEBE incluir script: `<script src="https://www.google.com/recaptcha/api.js?render={site_key}"></script>`
|
||||
- **AND** DEBE agregar input hidden `recaptcha_token` al formulario
|
||||
- **AND** DEBE agregar JS para ejecutar `grecaptcha.execute()` al submit
|
||||
|
||||
#### Scenario: Script de reCAPTCHA en ContactFormRenderer
|
||||
- **WHEN** ContactFormRenderer genera HTML del formulario
|
||||
- **AND** reCAPTCHA está habilitado
|
||||
- **THEN** DEBE incluir script de reCAPTCHA con site_key
|
||||
- **AND** DEBE agregar input hidden `recaptcha_token`
|
||||
- **AND** DEBE agregar JS para ejecutar `grecaptcha.execute()` al submit
|
||||
|
||||
#### Scenario: JavaScript de ejecución de reCAPTCHA
|
||||
- **WHEN** usuario hace submit del formulario
|
||||
- **THEN** JS DEBE interceptar el submit
|
||||
- **AND** DEBE llamar `grecaptcha.execute(siteKey, {action: 'action_name'})`
|
||||
- **AND** DEBE esperar el token (Promise)
|
||||
- **AND** DEBE insertar token en input hidden
|
||||
- **AND** DEBE continuar con el submit del formulario
|
||||
|
||||
#### Scenario: No cargar script si está deshabilitado
|
||||
- **GIVEN** reCAPTCHA `is_enabled` es false
|
||||
- **WHEN** se renderiza el formulario
|
||||
- **THEN** NO DEBE incluir script de reCAPTCHA
|
||||
- **AND** NO DEBE agregar input hidden de token
|
||||
- **AND** formulario DEBE funcionar normalmente
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Integración Backend (AjaxHandlers)
|
||||
|
||||
Los AjaxHandlers DEBEN validar el token de reCAPTCHA antes de procesar.
|
||||
|
||||
#### Scenario: Validación en NewsletterAjaxHandler
|
||||
- **WHEN** se procesa suscripción de newsletter
|
||||
- **AND** reCAPTCHA está habilitado
|
||||
- **THEN** DEBE obtener `recaptcha_token` del POST
|
||||
- **AND** DEBE llamar a `RecaptchaValidationService::validateSubmission()`
|
||||
- **AND** si retorna false, DEBE responder con error JSON
|
||||
- **AND** si retorna true, DEBE continuar procesamiento normal
|
||||
|
||||
#### Scenario: Validación en ContactFormAjaxHandler
|
||||
- **WHEN** se procesa envío de formulario de contacto
|
||||
- **AND** reCAPTCHA está habilitado
|
||||
- **THEN** DEBE obtener `recaptcha_token` del POST
|
||||
- **AND** DEBE llamar a `RecaptchaValidationService::validateSubmission()`
|
||||
- **AND** si retorna false, DEBE responder con error JSON
|
||||
- **AND** si retorna true, DEBE continuar procesamiento normal
|
||||
|
||||
#### Scenario: Mensaje de error por reCAPTCHA fallido
|
||||
- **GIVEN** validación de reCAPTCHA falla
|
||||
- **WHEN** AjaxHandler responde
|
||||
- **THEN** DEBE retornar JSON con `success: false`
|
||||
- **AND** mensaje DEBE ser genérico: "No se pudo verificar que eres humano. Intenta de nuevo."
|
||||
- **AND** NO DEBE revelar detalles técnicos del score
|
||||
|
||||
#### Scenario: Inyección de dependencias en AjaxHandlers
|
||||
- **WHEN** se modifican los AjaxHandlers
|
||||
- **THEN** DEBEN inyectar `RecaptchaValidationService` via constructor
|
||||
- **AND** NO DEBE instanciar servicios directamente
|
||||
- **AND** DEBE seguir principio de Inversión de Dependencias
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Panel de Administración
|
||||
|
||||
DEBE existir un FormBuilder para configurar reCAPTCHA.
|
||||
|
||||
#### Scenario: Ubicación del FormBuilder
|
||||
- **WHEN** se crea el FormBuilder
|
||||
- **THEN** DEBE ubicarse en `Admin/RecaptchaSettings/Infrastructure/Ui/RecaptchaSettingsFormBuilder.php`
|
||||
- **AND** namespace DEBE ser `ROITheme\Admin\RecaptchaSettings\Infrastructure\Ui`
|
||||
|
||||
#### Scenario: Registro en getComponents
|
||||
- **WHEN** se registra el FormBuilder
|
||||
- **THEN** DEBE registrarse en `getComponents()` con ID `recaptcha-settings`
|
||||
- **AND** DEBE aparecer en el menú del admin dashboard
|
||||
|
||||
#### Scenario: Campos del formulario admin
|
||||
- **WHEN** se renderiza el formulario de configuración
|
||||
- **THEN** DEBE mostrar toggle para `is_enabled`
|
||||
- **AND** DEBE mostrar input text para `site_key`
|
||||
- **AND** DEBE mostrar input password para `secret_key`
|
||||
- **AND** DEBE mostrar select para `score_threshold` con opciones 0.3, 0.5, 0.7, 0.9
|
||||
- **AND** DEBE seguir Design System: gradiente #0E2337 → #1e3a5f, borde #FF8600
|
||||
|
||||
#### Scenario: FieldMapper para mapeo de campos
|
||||
- **WHEN** se crea el componente admin
|
||||
- **THEN** DEBE existir `Admin/RecaptchaSettings/Infrastructure/FieldMapping/RecaptchaSettingsFieldMapper.php`
|
||||
- **AND** DEBE implementar `FieldMapperInterface`
|
||||
- **AND** DEBE registrarse en `FieldMapperRegistry`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Seguridad
|
||||
|
||||
La implementación DEBE seguir mejores prácticas de seguridad.
|
||||
|
||||
#### Scenario: Almacenamiento de secret key
|
||||
- **WHEN** se guarda el secret key
|
||||
- **THEN** DEBE almacenarse encriptado en BD
|
||||
- **AND** NO DEBE aparecer en código fuente
|
||||
- **AND** NO DEBE exponerse en frontend
|
||||
|
||||
#### Scenario: Site key en frontend
|
||||
- **GIVEN** site key es público por diseño de Google
|
||||
- **WHEN** se incluye en frontend
|
||||
- **THEN** PUEDE incluirse en atributo de script
|
||||
- **AND** DEBE obtenerse de configuración en BD
|
||||
|
||||
#### Scenario: Validación de token en backend
|
||||
- **WHEN** se recibe token de reCAPTCHA
|
||||
- **THEN** DEBE sanitizarse con `sanitize_text_field()`
|
||||
- **AND** DEBE validarse que no esté vacío
|
||||
- **AND** DEBE enviarse a API de Google para verificación real
|
||||
|
||||
#### Scenario: No confiar solo en frontend
|
||||
- **GIVEN** tokens pueden ser fabricados
|
||||
- **WHEN** se valida reCAPTCHA
|
||||
- **THEN** SIEMPRE DEBE verificarse con API de Google en backend
|
||||
- **AND** NUNCA confiar en validación solo de frontend
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Logging y Monitoreo
|
||||
|
||||
El sistema DEBE registrar intentos de spam bloqueados.
|
||||
|
||||
#### Scenario: Log de intentos bloqueados
|
||||
- **WHEN** reCAPTCHA bloquea un intento
|
||||
- **THEN** DEBE registrar en log de WordPress
|
||||
- **AND** DEBE incluir: timestamp, IP, action, score obtenido, threshold configurado
|
||||
- **AND** NO DEBE incluir datos personales del usuario
|
||||
|
||||
#### Scenario: Log de errores de API
|
||||
- **WHEN** API de Google falla
|
||||
- **THEN** DEBE registrar error en log
|
||||
- **AND** DEBE incluir código de error y mensaje
|
||||
- **AND** DEBE permitir diagnóstico del problema
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Fallback y Resiliencia
|
||||
|
||||
El sistema DEBE manejar fallos graciosamente.
|
||||
|
||||
#### Scenario: Fail-open cuando API no responde
|
||||
- **GIVEN** API de Google no responde (timeout)
|
||||
- **WHEN** se intenta validar
|
||||
- **THEN** DEBE permitir el envío del formulario (fail-open)
|
||||
- **AND** DEBE registrar el evento en log
|
||||
- **AND** NO DEBE bloquear usuarios legítimos por falla de terceros
|
||||
|
||||
#### Scenario: Degradación cuando reCAPTCHA deshabilitado
|
||||
- **GIVEN** administrador deshabilita reCAPTCHA
|
||||
- **WHEN** se envía formulario
|
||||
- **THEN** DEBE procesarse normalmente
|
||||
- **AND** validaciones existentes (nonce, rate limit) DEBEN seguir activas
|
||||
- **AND** NO DEBE generar errores por ausencia de token
|
||||
|
||||
---
|
||||
|
||||
## Checklist de Implementación
|
||||
|
||||
### Archivos a Crear
|
||||
- [ ] `Schemas/recaptcha-settings.json`
|
||||
- [ ] `Shared/Domain/Contracts/RecaptchaValidatorInterface.php`
|
||||
- [ ] `Shared/Domain/Entities/RecaptchaResult.php`
|
||||
- [ ] `Shared/Application/Services/RecaptchaValidationService.php`
|
||||
- [ ] `Shared/Infrastructure/Services/GoogleRecaptchaValidator.php`
|
||||
- [ ] `Admin/RecaptchaSettings/Infrastructure/Ui/RecaptchaSettingsFormBuilder.php`
|
||||
- [ ] `Admin/RecaptchaSettings/Infrastructure/FieldMapping/RecaptchaSettingsFieldMapper.php`
|
||||
|
||||
### Archivos a Modificar
|
||||
- [ ] `Public/Footer/Infrastructure/Ui/FooterRenderer.php`
|
||||
- [ ] `Public/Footer/Infrastructure/Api/WordPress/NewsletterAjaxHandler.php`
|
||||
- [ ] `Public/ContactForm/Infrastructure/Ui/ContactFormRenderer.php`
|
||||
- [ ] `Public/ContactForm/Infrastructure/Api/WordPress/ContactFormAjaxHandler.php`
|
||||
- [ ] `functions.php` (registro DI)
|
||||
- [ ] `Admin/Infrastructure/Ui/AdminDashboardRenderer.php` (registrar componente)
|
||||
- [ ] `Admin/Shared/Infrastructure/FieldMapping/FieldMapperRegistry.php`
|
||||
|
||||
### Validaciones
|
||||
- [ ] Schema tiene campos de visibilidad
|
||||
- [ ] Domain no tiene dependencias de Infrastructure
|
||||
- [ ] Application solo depende de interfaces de Domain
|
||||
- [ ] Todos los servicios inyectados via constructor
|
||||
- [ ] CSS generado via CSSGeneratorService (si aplica)
|
||||
- [ ] Secret key nunca expuesto en frontend
|
||||
|
||||
---
|
||||
|
||||
## Última actualización
|
||||
|
||||
2025-01-08
|
||||
132
_openspec/changes/recaptcha-anti-spam/tasks.md
Normal file
132
_openspec/changes/recaptcha-anti-spam/tasks.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Tasks: reCAPTCHA v3 Anti-Spam Protection
|
||||
|
||||
## Fase 1: Especificación
|
||||
- [x] Crear proposal.md
|
||||
- [x] Crear tasks.md
|
||||
- [x] Crear spec.md con formato Gherkin
|
||||
- [ ] Obtener aprobación del usuario
|
||||
|
||||
## Fase 2: Implementación
|
||||
|
||||
### 2.1 Capa Domain (Contratos y Entidades)
|
||||
- [ ] Crear `Shared/Domain/Contracts/RecaptchaValidatorInterface.php`
|
||||
```php
|
||||
interface RecaptchaValidatorInterface {
|
||||
public function validate(string $token, string $action): RecaptchaResult;
|
||||
}
|
||||
```
|
||||
- [ ] Crear `Shared/Domain/Entities/RecaptchaResult.php`
|
||||
```php
|
||||
final class RecaptchaResult {
|
||||
public function __construct(
|
||||
private bool $success,
|
||||
private float $score,
|
||||
private string $action,
|
||||
private array $errorCodes = []
|
||||
) {}
|
||||
public function isValid(float $threshold): bool;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Capa Application (Servicios)
|
||||
- [ ] Crear `Shared/Application/Services/RecaptchaValidationService.php`
|
||||
- Orquestar validación
|
||||
- Aplicar threshold configurable
|
||||
- Logging de resultados
|
||||
|
||||
### 2.3 Capa Infrastructure (Implementación)
|
||||
- [ ] Crear `Shared/Infrastructure/Services/GoogleRecaptchaValidator.php`
|
||||
- Llamada HTTP a API de Google
|
||||
- Manejo de errores y timeout
|
||||
- Parseo de respuesta JSON
|
||||
|
||||
### 2.4 Schema y Admin UI
|
||||
- [ ] Crear `Schemas/recaptcha-settings.json`
|
||||
- Campos: is_enabled, site_key, secret_key, score_threshold, actions
|
||||
- [ ] Sincronizar schema con BD: `wp roi-theme sync-component recaptcha-settings`
|
||||
- [ ] Crear `Admin/RecaptchaSettings/Infrastructure/Ui/RecaptchaSettingsFormBuilder.php`
|
||||
- [ ] Crear `Admin/RecaptchaSettings/Infrastructure/FieldMapping/RecaptchaSettingsFieldMapper.php`
|
||||
- [ ] Registrar en `getComponents()` del AdminDashboardRenderer
|
||||
- [ ] Registrar FieldMapper en FieldMapperRegistry
|
||||
|
||||
### 2.5 Integración Frontend
|
||||
- [ ] Modificar `FooterRenderer.php`
|
||||
- Agregar script de reCAPTCHA con site key
|
||||
- Modificar form para incluir token hidden
|
||||
- [ ] Modificar `ContactFormRenderer.php`
|
||||
- Agregar script de reCAPTCHA con site key
|
||||
- Modificar form para incluir token hidden
|
||||
- [ ] Crear JS compartido para ejecutar reCAPTCHA y obtener token
|
||||
|
||||
### 2.6 Integración Backend
|
||||
- [ ] Modificar `NewsletterAjaxHandler.php`
|
||||
- Inyectar RecaptchaValidationService
|
||||
- Validar token antes de procesar
|
||||
- Retornar error si score bajo
|
||||
- [ ] Modificar `ContactFormAjaxHandler.php`
|
||||
- Inyectar RecaptchaValidationService
|
||||
- Validar token antes de procesar
|
||||
- Retornar error si score bajo
|
||||
|
||||
### 2.7 Registro DI
|
||||
- [ ] Modificar `functions.php`
|
||||
- Registrar RecaptchaValidatorInterface → GoogleRecaptchaValidator
|
||||
- Registrar RecaptchaValidationService
|
||||
|
||||
## Fase 3: Integración y Validación
|
||||
|
||||
### 3.1 Testing Manual
|
||||
- [ ] Probar Newsletter con reCAPTCHA habilitado
|
||||
- [ ] Probar Contact Form con reCAPTCHA habilitado
|
||||
- [ ] Probar con reCAPTCHA deshabilitado (fallback)
|
||||
- [ ] Probar cambio de threshold desde admin
|
||||
- [ ] Verificar logging de intentos
|
||||
|
||||
### 3.2 Validación de Arquitectura
|
||||
- [ ] Ejecutar `validate-architecture.php recaptcha-settings`
|
||||
- [ ] Verificar cumplimiento Clean Architecture
|
||||
- [ ] Verificar inyección de dependencias correcta
|
||||
|
||||
### 3.3 Documentación
|
||||
- [ ] Actualizar CLAUDE.md si es necesario
|
||||
- [ ] Documentar configuración en admin
|
||||
|
||||
## Dependencias
|
||||
|
||||
| Tarea | Depende de |
|
||||
|-------|------------|
|
||||
| Application Service | Domain Contract |
|
||||
| Infrastructure Service | Domain Contract |
|
||||
| Admin FormBuilder | Schema JSON sincronizado |
|
||||
| Frontend integration | Site Key configurado |
|
||||
| Backend integration | Application Service + Infrastructure |
|
||||
|
||||
## Estimación de Archivos
|
||||
|
||||
| Tipo | Cantidad |
|
||||
|------|----------|
|
||||
| Nuevos | 7 |
|
||||
| Modificados | 7 |
|
||||
| Total | 14 |
|
||||
|
||||
### Archivos Nuevos
|
||||
1. `Shared/Domain/Contracts/RecaptchaValidatorInterface.php`
|
||||
2. `Shared/Domain/Entities/RecaptchaResult.php`
|
||||
3. `Shared/Application/Services/RecaptchaValidationService.php`
|
||||
4. `Shared/Infrastructure/Services/GoogleRecaptchaValidator.php`
|
||||
5. `Schemas/recaptcha-settings.json`
|
||||
6. `Admin/RecaptchaSettings/Infrastructure/Ui/RecaptchaSettingsFormBuilder.php`
|
||||
7. `Admin/RecaptchaSettings/Infrastructure/FieldMapping/RecaptchaSettingsFieldMapper.php`
|
||||
|
||||
### Archivos a Modificar
|
||||
1. `Public/Footer/Infrastructure/Api/WordPress/NewsletterAjaxHandler.php`
|
||||
2. `Public/ContactForm/Infrastructure/Api/WordPress/ContactFormAjaxHandler.php`
|
||||
3. `Public/Footer/Infrastructure/Ui/FooterRenderer.php`
|
||||
4. `Public/ContactForm/Infrastructure/Ui/ContactFormRenderer.php`
|
||||
5. `functions.php`
|
||||
6. `Admin/Infrastructure/Ui/AdminDashboardRenderer.php`
|
||||
7. `Admin/Shared/Infrastructure/FieldMapping/FieldMapperRegistry.php`
|
||||
|
||||
## Última actualización
|
||||
|
||||
2025-01-08
|
||||
Reference in New Issue
Block a user