diff --git a/src/DI/ReCaptchaExtension.php b/src/DI/ReCaptchaExtension.php index 12bb4cb..258bf39 100644 --- a/src/DI/ReCaptchaExtension.php +++ b/src/DI/ReCaptchaExtension.php @@ -18,6 +18,7 @@ public function getConfigSchema(): Schema return Expect::structure([ 'siteKey' => Expect::string()->required(), 'secretKey' => Expect::string()->required(), + 'minimalScore' => Expect::anyOf(Expect::float()->min(0)->max(1), Expect::int()->min(0)->max(1))->default(0), ]); } @@ -30,7 +31,7 @@ public function loadConfiguration(): void $builder = $this->getContainerBuilder(); $builder->addDefinition($this->prefix('provider')) - ->setFactory(ReCaptchaProvider::class, [$config['siteKey'], $config['secretKey']]); + ->setFactory(ReCaptchaProvider::class, [$config['siteKey'], $config['secretKey'], $config['minimalScore']]); } /** diff --git a/src/Forms/InvisibleReCaptchaField.php b/src/Forms/InvisibleReCaptchaField.php index f3812ac..66d1652 100644 --- a/src/Forms/InvisibleReCaptchaField.php +++ b/src/Forms/InvisibleReCaptchaField.php @@ -2,6 +2,7 @@ namespace Contributte\ReCaptcha\Forms; +use Contributte\ReCaptcha\Exceptions\InvalidScoreException; use Contributte\ReCaptcha\ReCaptchaProvider; use Nette\Forms\Controls\HiddenField; use Nette\Forms\Form; @@ -46,6 +47,17 @@ public function setMessage(string $message): self return $this; } + public function setMinimalScore(float $score): self + { + if ($score < 0 || $score > 1) { + throw new \LogicException('Minimal score expects to be in range 0..1 (1.0 is very likely a good interaction, 0.0 is very likely a bot).'); + } + + $this->provider->setMinimalScore($score); + + return $this; + } + public function validate(): void { $this->configureValidation(); diff --git a/src/ReCaptchaProvider.php b/src/ReCaptchaProvider.php index 18b83a2..fc9c973 100644 --- a/src/ReCaptchaProvider.php +++ b/src/ReCaptchaProvider.php @@ -28,10 +28,14 @@ class ReCaptchaProvider private string $secretKey; - public function __construct(string $siteKey, string $secretKey) + // Range 0..1 (1.0 is very likely a good interaction, 0.0 is very likely a bot) + private float $minimalScore; + + public function __construct(string $siteKey, string $secretKey, float $minimalScore) { $this->siteKey = $siteKey; $this->secretKey = $secretKey; + $this->setMinimalScore($minimalScore); } public function getSiteKey(): string @@ -57,7 +61,7 @@ public function validate(string $response): ?ReCaptchaResponse $answer = json_decode($response, true); // Return response - return $answer['success'] === true ? new ReCaptchaResponse(true) : new ReCaptchaResponse(false, $answer['error-codes'] ?? null); + return $answer['success'] === true && $answer['score'] >= $this->minimalScore ? new ReCaptchaResponse(true) : new ReCaptchaResponse(false, $answer['error-codes'] ?? null); } public function validateControl(BaseControl $control): bool @@ -77,6 +81,11 @@ public function validateControl(BaseControl $control): bool return false; } + public function setMinimalScore(float $score): void + { + $this->minimalScore = $score; + } + protected function makeRequest(?string $response, ?string $remoteIp = null): string|null { if ($response === null || $response === '') {