Completed
Pull Request — master (#79)
by ARCANEDEV
07:25
created

NoCaptchaV2::scriptWithCallback()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 2
dl 0
loc 17
rs 9.7
c 0
b 0
f 0
ccs 12
cts 12
cp 1
crap 3
1
<?php namespace Arcanedev\NoCaptcha;
2
3
use Arcanedev\NoCaptcha\Utilities\Attributes;
4
use Arcanedev\NoCaptcha\Utilities\ResponseV2;
5
use Illuminate\Support\Arr;
6
use Psr\Http\Message\ServerRequestInterface;
7
8
/**
9
 * Class     NoCaptchaV2
10
 *
11
 * @package  Arcanedev\NoCaptcha
12
 * @author   ARCANEDEV <[email protected]>
13
 */
14
class NoCaptchaV2 extends AbstractNoCaptcha
15
{
16
    /* -----------------------------------------------------------------
17
     |  Properties
18
     | -----------------------------------------------------------------
19
     */
20
21
    /**
22
     * Decides if we've already loaded the script file or not.
23
     *
24
     * @param bool
25
     */
26
    protected $scriptLoaded = false;
27
28
    /**
29
     * noCaptcha Attributes
30
     *
31
     * @var \Arcanedev\NoCaptcha\Utilities\Attributes
32
     */
33
    protected $attributes;
34
35
    /* -----------------------------------------------------------------
36
     |  Constructor
37
     | -----------------------------------------------------------------
38
     */
39
40
    /**
41
     * NoCaptcha constructor.
42
     *
43
     * @param  string       $secret
44
     * @param  string       $siteKey
45
     * @param  string|null  $lang
46
     * @param  array        $attributes
47
     */
48 128
    public function __construct($secret, $siteKey, $lang = null, array $attributes = [])
49
    {
50 128
        parent::__construct($secret, $siteKey, $lang);
51
52 128
        $this->setAttributes(new Attributes($attributes));
53 128
    }
54
55
    /* -----------------------------------------------------------------
56
     |  Getters & Setters
57
     | -----------------------------------------------------------------
58
     */
59
60
    /**
61
     * Get script source link.
62
     *
63
     * @param  string|null  $callbackName
64
     *
65
     * @return string
66
     */
67 20
    private function getScriptSrc($callbackName = null)
68
    {
69 20
        $queries = [];
70
71 20
        if ($this->hasLang())
72 8
            Arr::set($queries, 'hl', $this->lang);
73
74 20
        if ($this->hasCallbackName($callbackName)) {
75 4
            Arr::set($queries, 'onload', $callbackName);
76 4
            Arr::set($queries, 'render', 'explicit');
77
        }
78
79 20
        return static::CLIENT_URL . (count($queries) ? '?' . http_build_query($queries) : '');
80
    }
81
82
    /**
83
     * Set HTTP Request Client.
84
     *
85
     * @param  \Arcanedev\NoCaptcha\Contracts\Utilities\Request  $request
86
     *
87
     * @return self
88
     */
89 128
    public function setRequestClient(Contracts\Utilities\Request $request)
90
    {
91 128
        $this->request = $request;
92
93 128
        return $this;
94
    }
95
96
    /**
97
     * Set noCaptcha Attributes.
98
     *
99
     * @param  \Arcanedev\NoCaptcha\Utilities\Attributes  $attributes
100
     *
101
     * @return self
102
     */
103 128
    public function setAttributes(Attributes $attributes)
104
    {
105 128
        $this->attributes = $attributes;
106
107 128
        return $this;
108
    }
109
110
    /* -----------------------------------------------------------------
111
     |  Main Methods
112
     | -----------------------------------------------------------------
113
     */
114
115
    /**
116
     * Display Captcha.
117
     *
118
     * @param  string|null  $name
119
     * @param  array        $attributes
120
     *
121
     * @return \Illuminate\Support\HtmlString
122
     */
123 76
    public function display($name = null, array $attributes = [])
124
    {
125 76
        $attributes = $this->attributes->build($this->siteKey, array_merge(
126 76
            $this->attributes->prepareNameAttribute($name),
127 32
            $attributes
128
        ));
129
130 64
        return $this->toHtmlString("<div {$attributes}></div>");
131
    }
132
133
    /**
134
     * Display image Captcha.
135
     *
136
     * @param  string|null  $name
137
     * @param  array        $attributes
138
     *
139
     * @return \Illuminate\Support\HtmlString
140
     */
141 12
    public function image($name = null, array $attributes = [])
142
    {
143 12
        return $this->display(
144 12
            $name, array_merge($attributes, $this->attributes->getImageAttribute())
145
        );
146
    }
147
148
    /**
149
     * Display audio Captcha.
150
     *
151
     * @param  string|null  $name
152
     * @param  array        $attributes
153
     *
154
     * @return \Illuminate\Support\HtmlString
155
     */
156 12
    public function audio($name = null, array $attributes = [])
157
    {
158 12
        return $this->display(
159 12
            $name, array_merge($attributes, $this->attributes->getAudioAttribute())
160
        );
161
    }
162
    /**
163
     * Display an invisible Captcha (bind the challenge to a button).
164
     *
165
     * @param  string  $value
166
     * @param  array   $attributes
167
     *
168
     * @return \Illuminate\Support\HtmlString
169
     */
170 4
    public function button($value, array $attributes = [])
171
    {
172 4
        $attributes = $this->attributes->build($this->siteKey, array_merge([
173 4
            'data-callback' => 'onSubmit',
174 2
        ], $attributes));
175
176 4
        return $this->toHtmlString(
177 4
            "<button {$attributes}>{$value}</button>"
178
        );
179
    }
180
181
    /**
182
     * Calls the reCAPTCHA siteverify API to verify whether the user passes CAPTCHA
183
     * test using a PSR-7 ServerRequest object.
184
     *
185
     * @param  \Psr\Http\Message\ServerRequestInterface  $request
186
     *
187
     * @return bool
188
     */
189 4
    public function verifyRequest(ServerRequestInterface $request)
190
    {
191 4
        $body   = $request->getParsedBody();
192 4
        $server = $request->getServerParams();
193
194 4
        return $this->verify(
195 4
            $body[self::CAPTCHA_NAME] ?? '',
196 4
            $server['REMOTE_ADDR'] ?? null
197
        );
198
    }
199
200
    /**
201
     * Get script tag.
202
     *
203
     * @param  string|null  $callbackName
204
     *
205
     * @return \Illuminate\Support\HtmlString
206
     */
207 20
    public function script($callbackName = null)
208
    {
209 20
        $script = '';
210
211 20
        if ( ! $this->scriptLoaded) {
212 20
            $script = '<script src="'.$this->getScriptSrc($callbackName).'" async defer></script>';
213 20
            $this->scriptLoaded = true;
214
        }
215
216 20
        return $this->toHtmlString($script);
217
    }
218
219
    /**
220
     * Get the NoCaptcha API Script.
221
     *
222
     * @return \Illuminate\Support\HtmlString
223
     */
224 4
    public function getApiScript()
225
    {
226 4
        return $this->toHtmlString(
227 3
            "<script>
228
                window.noCaptcha = {
229
                    captchas: [],
230
                    reset: function(name) {
231
                        var captcha = window.noCaptcha.get(name);
232
        
233
                        if (captcha)
234
                            window.noCaptcha.resetById(captcha.id);
235
                    },
236
                    resetById: function(id) {
237
                        grecaptcha.reset(id);
238
                    },
239
                    get: function(name) {
240
                        return window.noCaptcha.find(function (captcha) {
241
                            return captcha.name === name;
242
                        });
243
                    },
244
                    getById: function(id) {
245
                        return window.noCaptcha.find(function (captcha) {
246
                            return captcha.id === id;
247
                        });
248
                    },
249
                    find: function(callback) {
250
                        return window.noCaptcha.captchas.find(callback);
251
                    },
252
                    render: function(name, sitekey) {
253
                        var captcha = {
254
                            id: grecaptcha.render(name, {'sitekey' : sitekey}),
255
                            name: name
256
                        };
257
                        
258
                        window.noCaptcha.captchas.push(captcha);
259
                        
260
                        return captcha;
261
                    }
262
                }
263 1
            </script>"
264
        );
265
    }
266
267
    /**
268
     * Get script tag with a callback function.
269
     *
270
     * @param  array   $captchas
271
     * @param  string  $callbackName
272
     *
273
     * @return \Illuminate\Support\HtmlString
274
     */
275 4
    public function scriptWithCallback(array $captchas, $callbackName = 'captchaRenderCallback')
276
    {
277 4
        $script = $this->script($callbackName)->toHtml();
278
279 4
        if ( ! empty($script) && ! empty($captchas)) {
280 4
            $script = implode(PHP_EOL, [implode(PHP_EOL, [
281 4
                $this->getApiScript()->toHtml(),
282 4
                '<script>',
283 4
                    "var $callbackName = function() {",
284 4
                        $this->renderCaptchas($captchas),
285 4
                    '};',
286 4
                '</script>'
287 4
            ]), $script]);
288
        }
289
290 4
        return $this->toHtmlString($script);
291
    }
292
293
    /**
294
     * Rendering captchas with callback function.
295
     *
296
     * @param  array  $captchas
297
     *
298
     * @return string
299
     */
300 4
    private function renderCaptchas(array $captchas)
301
    {
302
        return implode(PHP_EOL, array_map(function($captcha) {
303 4
            return "if (document.getElementById('{$captcha}')) { window.noCaptcha.render('{$captcha}', '{$this->siteKey}'); }";
304 4
        }, $captchas));
305
    }
306
307
    /* -----------------------------------------------------------------
308
     |  Check Methods
309
     | -----------------------------------------------------------------
310
     */
311
312
    /**
313
     * Check if callback is not empty.
314
     *
315
     * @param  string|null  $callbackName
316
     *
317
     * @return bool
318
     */
319 20
    private function hasCallbackName($callbackName)
320
    {
321 20
        return ! (is_null($callbackName) || trim($callbackName) === '');
322
    }
323
324
    /* -----------------------------------------------------------------
325
     |  Other Methods
326
     | -----------------------------------------------------------------
327
     */
328
329
    /**
330
     * Parse the response.
331
     *
332
     * @param  string  $json
333
     *
334
     * @return \Arcanedev\NoCaptcha\Utilities\AbstractResponse|mixed
335
     */
336 12
    protected function parseResponse($json)
337
    {
338 12
        return ResponseV2::fromJson($json);
339
    }
340
}
341