- Add RecaptchaValidatorInterface and RecaptchaResult entity in Domain - Create RecaptchaValidationService in Application layer - Implement GoogleRecaptchaValidator for API integration - Add recaptcha-settings schema and admin FormBuilder - Integrate reCAPTCHA validation in NewsletterAjaxHandler - Integrate reCAPTCHA validation in ContactFormAjaxHandler - Update FooterRenderer and ContactFormRenderer with reCAPTCHA scripts - Configure DIContainer with RecaptchaValidationService injection Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
135 lines
3.4 KiB
PHP
135 lines
3.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace ROITheme\Shared\Domain\Entities;
|
|
|
|
/**
|
|
* RecaptchaResult - Entidad que representa el resultado de validacion reCAPTCHA
|
|
*
|
|
* RESPONSABILIDAD: Encapsular el resultado de la validacion de reCAPTCHA v3
|
|
* incluyendo el score, estado de exito y posibles codigos de error.
|
|
*
|
|
* INMUTABILIDAD: Esta entidad es inmutable - una vez creada no puede modificarse.
|
|
*
|
|
* SCORE reCAPTCHA v3:
|
|
* - 1.0: Muy probablemente humano
|
|
* - 0.9: Probablemente humano
|
|
* - 0.5: Indeterminado
|
|
* - 0.1: Probablemente bot
|
|
* - 0.0: Muy probablemente bot
|
|
*
|
|
* @package ROITheme\Shared\Domain\Entities
|
|
*/
|
|
final class RecaptchaResult
|
|
{
|
|
/**
|
|
* @param bool $success Si la validacion fue exitosa (token valido)
|
|
* @param float $score Score de 0.0 (bot) a 1.0 (humano)
|
|
* @param string $action Accion verificada
|
|
* @param array<string> $errorCodes Codigos de error de la API
|
|
* @param string $hostname Hostname donde se genero el token
|
|
* @param string $challengeTs Timestamp del challenge
|
|
*/
|
|
public function __construct(
|
|
private bool $success,
|
|
private float $score,
|
|
private string $action,
|
|
private array $errorCodes = [],
|
|
private string $hostname = '',
|
|
private string $challengeTs = ''
|
|
) {}
|
|
|
|
/**
|
|
* Verificar si el resultado es valido segun un threshold
|
|
*
|
|
* @param float $threshold Score minimo requerido (ej: 0.5)
|
|
* @return bool True si success=true Y score >= threshold
|
|
*/
|
|
public function isValid(float $threshold): bool
|
|
{
|
|
return $this->success && $this->score >= $threshold;
|
|
}
|
|
|
|
/**
|
|
* Verificar si la accion coincide con la esperada
|
|
*
|
|
* @param string $expectedAction Accion esperada
|
|
* @return bool True si la accion coincide
|
|
*/
|
|
public function hasValidAction(string $expectedAction): bool
|
|
{
|
|
return $this->action === $expectedAction;
|
|
}
|
|
|
|
public function isSuccess(): bool
|
|
{
|
|
return $this->success;
|
|
}
|
|
|
|
public function getScore(): float
|
|
{
|
|
return $this->score;
|
|
}
|
|
|
|
public function getAction(): string
|
|
{
|
|
return $this->action;
|
|
}
|
|
|
|
/**
|
|
* @return array<string>
|
|
*/
|
|
public function getErrorCodes(): array
|
|
{
|
|
return $this->errorCodes;
|
|
}
|
|
|
|
public function hasErrors(): bool
|
|
{
|
|
return !empty($this->errorCodes);
|
|
}
|
|
|
|
public function getHostname(): string
|
|
{
|
|
return $this->hostname;
|
|
}
|
|
|
|
public function getChallengeTs(): string
|
|
{
|
|
return $this->challengeTs;
|
|
}
|
|
|
|
/**
|
|
* Crear resultado de fallo (para errores de red, timeout, etc.)
|
|
*
|
|
* @param array<string> $errorCodes Codigos de error
|
|
* @return self
|
|
*/
|
|
public static function failure(array $errorCodes = ['unknown-error']): self
|
|
{
|
|
return new self(
|
|
success: false,
|
|
score: 0.0,
|
|
action: '',
|
|
errorCodes: $errorCodes
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Convertir a array para logging
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function toArray(): array
|
|
{
|
|
return [
|
|
'success' => $this->success,
|
|
'score' => $this->score,
|
|
'action' => $this->action,
|
|
'error_codes' => $this->errorCodes,
|
|
'hostname' => $this->hostname,
|
|
'challenge_ts' => $this->challengeTs,
|
|
];
|
|
}
|
|
}
|