Completed
Push — master ( 2a02ec...d090d0 )
by Michael
01:25
created

HCaptchaField::processCaptcha()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 43
rs 8.6097
c 0
b 0
f 0
cc 6
nc 4
nop 0
1
<?php
2
3
namespace X3dgoo\HCaptcha\Forms;
4
5
use Psr\Log\LoggerInterface;
6
use SilverStripe\Control\Controller;
7
use SilverStripe\Core\Injector\Injector;
8
use SilverStripe\Forms\FormField;
9
use SilverStripe\Forms\Validator;
10
use SilverStripe\ORM\FieldType\DBHTMLText;
11
use SilverStripe\View\Requirements;
12
13
class HCaptchaField extends FormField
14
{
15
    /**
16
     * HCaptcha Site Key
17
     * @config HCaptchaField.site_key
18
     */
19
    private static $site_key;
20
21
    /**
22
     * HCaptcha Secret Key
23
     * @config HCaptchaField.secret_key
24
     */
25
    private static $secret_key;
26
27
    /**
28
     * HCaptcha Site Key
29
     * Configurable via Injector config
30
     */
31
    protected $_siteKey;
32
33
    /**
34
     * HCaptcha Site Key
35
     * Configurable via Injector config
36
     */
37
    protected $_secretKey;
38
39
    /**
40
     * Creates a new HCaptcha field.
41
     * @param string $name The internal field name, passed to forms.
42
     * @param string $title The human-readable field label.
43
     * @param mixed $value The value of the field (unused)
44
     */
45
    public function __construct($name, $title = null, $value = null)
46
    {
47
        parent::__construct($name, $title, $value);
48
49
        $this->title = $title;
50
    }
51
52
    /**
53
     * Adds in the requirements for the field
54
     * @param array $properties Array of properties for the form element (not used)
55
     * @return DBHTMLText Rendered field template
56
     */
57
    public function Field($properties = [])
58
    {
59
        $siteKey = $this->getSiteKey();
60
        $secretKey = $this->getSecretKey();
61
62
        if (empty($siteKey) || empty($secretKey)) {
63
            user_error(
64
                'You must configure HCaptchaField.site_key and HCaptchaField.secret_key. ' .
65
                    'You can retrieve these at https://hcaptcha.com',
66
                E_USER_ERROR
67
            );
68
        }
69
70
        Requirements::javascript('https://hcaptcha.com/1/api.js');
71
72
        return parent::Field($properties);
73
    }
74
75
    /**
76
     * Validates the captcha against the hCaptcha API
77
     * @param Validator $validator Validator to send errors to
78
     * @return bool Returns boolean true if valid false if not
79
     */
80
    public function validate($validator)
81
    {
82
        $valid = $this->processCaptcha();
83
84
        if (!$valid) {
85
            $validator->validationError(
86
                $this->name,
87
                _t(
88
                    'X3dgoo\\HCaptcha\\Forms\\HCaptchaField.EMPTY',
89
                    'Please answer the captcha. If you do not see the captcha please enable Javascript'
90
                ),
91
                'validation'
92
            );
93
        }
94
95
        return $valid;
96
    }
97
98
99
    /**
100
     * Validates the captcha against the hCaptcha API
101
     * @return bool Returns boolean true if valid false if not
102
     */
103
    private function processCaptcha()
104
    {
105
        $hCaptchaResponse = Controller::curr()->getRequest()->requestVar('h-captcha-response');
106
107
        if (!isset($hCaptchaResponse) || !$hCaptchaResponse) {
108
            return false;
109
        }
110
111
        $secretKey = $this->getSecretKey();
112
113
        $client = new \GuzzleHttp\Client([
114
            'base_uri' => 'https://hcaptcha.com/',
115
        ]);
116
117
        $response = $client->request(
118
            'GET',
119
            'siteverify',
120
            [
121
                'query' => [
122
                    'secret' => $secretKey,
123
                    'response' => rawurlencode($hCaptchaResponse),
124
                    'remoteip' => rawurlencode($_SERVER['REMOTE_ADDR']),
125
                ],
126
            ]
127
        );
128
129
        $response = json_decode($response->getBody(), true);
130
131
        if (!is_array($response)) {
132
            $logger = Injector::inst()->get(LoggerInterface::class);
133
            $logger->error(
134
                'Captcha validation failed as request was not successful.'
135
            );
136
137
            return false;
138
        }
139
140
        if (array_key_exists('success', $response) && $response['success'] === false) {
141
            return false;
142
        }
143
144
        return true;
145
    }
146
147
    /**
148
     * Gets the site key configured via HCaptchaField.site_key this is used in the template
149
     * @return string
150
     */
151
    public function getSiteKey()
152
    {
153
        return $this->_siteKey ? $this->_siteKey : self::config()->site_key;
154
    }
155
156
    /**
157
     * Gets the secret key configured via HCaptchaField.secret_key
158
     * @return string
159
     */
160
    private function getSecretKey()
161
    {
162
        return $this->_secretKey ? $this->_secretKey : self::config()->secret_key;
163
    }
164
165
    /**
166
     * Setter for _siteKey to allow injector config to override the value
167
     * @param string $key
168
     */
169
    public function setSiteKey($key)
170
    {
171
        $this->_siteKey = $key;
172
    }
173
174
    /**
175
     * Setter for _secretKey to allow injector config to override the value
176
     * @param string $key
177
     */
178
    public function setSecretKey($key)
179
    {
180
        $this->_secretKey = $key;
181
    }
182
183
    /**
184
     * Gets the form's id
185
     * @return string
186
     */
187
    public function getFormID()
188
    {
189
        return ($this->form ? $this->getTemplateHelper()->generateFormID($this->form) : null);
190
    }
191
}
192