Passed
Push — master ( 279881...b4f44a )
by Divine Niiquaye
10:48
created

CaptchaAuthenticator::supports()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Biurad opensource projects.
7
 *
8
 * PHP version 7.4 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 Biurad Group (https://biurad.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 *
17
 */
18
19
namespace Biurad\Security\Handler;
20
21
use Biurad\Security\Interfaces\AuthenticatorInterface;
22
use Psr\Http\Message\ServerRequestInterface;
23
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
24
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
25
26
/**
27
 * ReCaptcha/HCaptcha validation authenticator.
28
 *
29
 * @author Divine Niiquaye Ibok <[email protected]>
30
 */
31
class CaptchaAuthenticator implements AuthenticatorInterface
32
{
33
    private ?string $reCaptchaSecret;
34
    private ?string $hCaptchaSecret;
35
36
    public function __construct(string $reCaptchaSecret = null, string $hCaptchaSecret = null)
37
    {
38
        if (!$reCaptchaSecret || !$hCaptchaSecret) {
39
            throw new \InvalidArgumentException('You must provide a reCaptcha secret and/or a hCaptcha secret.');
40
        }
41
42
        $this->reCaptchaSecret = $reCaptchaSecret;
43
        $this->hCaptchaSecret = $hCaptchaSecret;
44
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49
    public function supports(ServerRequestInterface $request): bool
50
    {
51
        return 'POST' === $request->getMethod();
52
    }
53
54
    /**
55
     * {@inheritdoc}
56
     */
57
    public function authenticate(ServerRequestInterface $request, array $credentials, string $firewallName): ?TokenInterface
58
    {
59
        if (isset($credentials['g-recaptcha-response'])) {
60
            if (empty($captcha = $credentials['g-recaptcha-response'])) {
61
                throw new BadCredentialsException('The presented captcha cannot be empty.');
62
            }
63
64
            if (empty($secret = $this->reCaptchaSecret)) {
65
                throw new BadCredentialsException('You must provide a reCaptcha secret.');
66
            }
67
68
            $url = 'https://www.google.com/recaptcha/api/siteverify?secret=' . \urlencode($secret) . '&response=' . \urlencode($captcha);
69
            $response = \json_decode(\file_get_contents($url), true);
70
        } elseif (isset($credentials['h-captcha-response'])) {
71
            if (empty($captcha = $credentials['h-captcha-response'])) {
72
                throw new BadCredentialsException('The presented captcha cannot be empty.');
73
            }
74
75
            if (empty($secret = $this->hCaptchaSecret)) {
76
                throw new BadCredentialsException('You must provide a hCaptcha secret.');
77
            }
78
79
            $url = 'https://hcaptcha.com/siteverify?secret=' . \urlencode($secret) . '&response=' . \urlencode($captcha) . '&remoteip=';
80
            $response = \json_decode(\file_get_contents($url . ($request->getServerParams()['REMOTE_ADDR'] ?? '')), true);
81
        }
82
83
        if (isset($response) && $response['success'] ?? false) {
84
            throw new BadCredentialsException('The presented captcha is invalid.');
85
        }
86
87
        return null;
88
    }
89
}
90