Passed
Push — master ( 8423de...61dfc6 )
by Dmitrii
03:05
created

Recaptcha3Validator::buildViolation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 5
c 0
b 0
f 0
nc 1
nop 3
dl 0
loc 7
ccs 0
cts 0
cp 0
crap 2
rs 10
1
<?php declare(strict_types=1);
2
3
namespace Karser\Recaptcha3Bundle\Validator\Constraints;
4
5
use Karser\Recaptcha3Bundle\Services\IpResolverInterface;
6
use ReCaptcha\ReCaptcha;
7
use Symfony\Component\Validator\Constraint;
8
use Symfony\Component\Validator\ConstraintValidator;
9
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
10
11
final class Recaptcha3Validator extends ConstraintValidator
12
{
13
    /** @var ReCaptcha */
14
    private $recaptcha;
15
    private $enabled;
16
    private $ipResolver;
17
18
    public function __construct($recaptcha, bool $enabled, IpResolverInterface $ipResolver)
19
    {
20
        $this->recaptcha = $recaptcha;
21
        $this->enabled = $enabled;
22 9
        $this->ipResolver = $ipResolver;
23
    }
24 9
25 9
    public function validate($value, Constraint $constraint): void
26 9
    {
27 9
        if ($value !== null && !is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) {
28
            throw new UnexpectedTypeException($value, 'string');
29 9
        }
30
        if (!$constraint instanceof Recaptcha3) {
31 9
            throw new UnexpectedTypeException($constraint, Recaptcha3::class);
32
        }
33
        if (!$this->enabled) {
34 9
            return;
35 2
        }
36
        $value = null !== $value ? (string) $value : '';
37 7
        $this->validateCaptcha($value, $constraint);
38 1
    }
39
40
    private function validateCaptcha(string $value, Recaptcha3 $constraint): void
41 6
    {
42 2
        if ($value === '') {
43
            $this->buildViolation($constraint->messageMissingValue, $value);
44
            return;
45 4
        }
46
        $ip = $this->ipResolver->resolveIp();
47 4
        $response = $this->recaptcha->verify($value, $ip);
48 4
        if (!$response->isSuccess()) {
49 2
            $errorCodes = implode('; ', array_map([$this, 'getErrorMessage'], $response->getErrorCodes()));
50 2
            $this->buildViolation($constraint->message, $value, $errorCodes);
51 2
        }
52 2
    }
53
54 4
    private function getErrorMessage(string $errorCode): string
55
    {
56
        $messages = [
57
            'missing-input-secret' => 'The secret parameter is missing',
58
            'invalid-input-secret' => 'The secret parameter is invalid or malformed',
59
            'missing-input-response' => 'The response parameter is missing',
60
            'invalid-input-response' => 'The response parameter is invalid or malformed',
61
            'bad-request' => 'The request is invalid or malformed',
62
            'timeout-or-duplicate' => 'The response is no longer valid: either is too old or has been used previously',
63
            'challenge-timeout' => 'Challenge timeout',
64
            'score-threshold-not-met' => 'Score threshold not met',
65
            'bad-response' => 'Did not receive a 200 from the service',
66
            'connection-failed' => 'Could not connect to service',
67
            'invalid-json' => 'Invalid JSON received',
68
            'unknown-error' => 'Not a success, but no error codes received',
69
            'hostname-mismatch' => 'Expected hostname did not match',
70
            'apk_package_name-mismatch' => 'Expected APK package name did not match',
71
            'action-mismatch' => 'Expected action did not match',
72
        ];
73
        return $messages[$errorCode] ?? $errorCode;
74
    }
75
76
    private function buildViolation(string $message, string $value, string $errorCodes = ''): void
77
    {
78
        $this->context->buildViolation($message)
79
            ->setParameter('{{ value }}', $this->formatValue($value))
80
            ->setParameter('{{ errorCodes }}', $this->formatValue($errorCodes))
81
            ->setCode(Recaptcha3::INVALID_FORMAT_ERROR)
82
            ->addViolation();
83
    }
84
}
85