-
Notifications
You must be signed in to change notification settings - Fork 86
/
eicaptcha.php
563 lines (504 loc) · 16.6 KB
/
eicaptcha.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file docs/licenses/LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* @author Hervé HENNES <[email protected]> and contributors / https://github.com/nenes25/eicaptcha
* @copyright since 2013 Hervé HENNES
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License ("AFL") v. 3.0
*/
if (!defined('_PS_VERSION_')) {
exit;
}
require_once dirname(__FILE__) . '/vendor/autoload.php';
use Eicaptcha\Module\ConfigForm;
use Eicaptcha\Module\Debugger;
use Eicaptcha\Module\Installer;
use ReCaptcha\ReCaptcha;
class EiCaptcha extends Module
{
/** @var string */
private $_html = '';
/** @var array */
protected $themes = [];
/**
* @var Debugger
*/
protected $debugger;
/**
* @var Installer
*/
protected $installer;
/**
* @var string (2 or 3 digits Language ISO code) Captcha language (default: en)
*/
protected $captchaLang = 'en';
public function __construct()
{
$this->author = 'hhennes';
$this->name = 'eicaptcha';
$this->tab = 'front_office_features';
$this->version = '2.5.0';
$this->need_instance = 1;
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('Ei Captcha');
$this->description = $this->l('Add a captcha to your website form');
if (
$this->active
&& (!Configuration::get('CAPTCHA_PUBLIC_KEY') || !Configuration::get('CAPTCHA_PRIVATE_KEY'))
) {
$this->warning = $this->l('Captcha Module need to be configurated');
}
$this->themes = [0 => 'light', 1 => 'dark'];
$this->dependencies = ['contactform'];
$this->ps_versions_compliancy = ['min' => '1.7.0.0', 'max' => _PS_VERSION_];
$this->debugger = new Debugger($this);
$this->captchaLang = $this->context->language->iso_code;
$forceLang = Configuration::get('CAPTCHA_FORCE_LANG');
if (!empty($forceLang) && Validate::isLanguageIsoCode($forceLang)) {
$this->captchaLang = $forceLang;
}
}
/**
* Install Module
*
* @return bool
*/
public function install()
{
if (!parent::install()
|| !$this->_getInstaller()->install()
) {
return false;
}
return true;
}
/**
* Uninstall Module
*
* @return bool
*/
public function uninstall()
{
if (!parent::uninstall()
|| !$this->_getInstaller()->uninstall()
) {
return false;
}
return true;
}
/**
* @return Installer
*/
protected function _getInstaller()
{
if (null === $this->installer) {
$this->installer = new Installer($this);
}
return $this->installer;
}
/**
* @return Debugger
*/
public function getDebugger()
{
return $this->debugger;
}
/**
* @return Context
*/
public function getContext()
{
return $this->context;
}
/**
* Module Configuration in Back Office
*
* @return string
*/
public function getContent()
{
$configForm = new ConfigForm($this);
$this->_html .= $this->debugger->checkComposer();
$this->_html .= $configForm->postProcess();
$this->_html .= $configForm->renderForm();
return $this->_html;
}
/**
* Hook Header
*
* @param array $params
*
* @return string|void
*/
public function hookHeader(array $params)
{
if (!$this->shouldDisplayToCustomer()) {
return;
}
$captchaVersion = Configuration::get('CAPTCHA_VERSION');
//Add Content box to contact form page in order to display captcha
if ($this->context->controller instanceof ContactController
&& Configuration::get('CAPTCHA_ENABLE_CONTACT') == 1
) {
$this->context->controller->registerJavascript(
'modules-eicaptcha-contact-form',
'modules/' . $this->name . '/views/js/eicaptcha-contact-form-v' . $captchaVersion . '.js'
);
}
if ($captchaVersion == 2) {
return $this->renderHeaderV2();
} else {
return $this->renderHeaderV3();
}
}
/**
* Return content for (re)captcha v2
*
* @return string|void
*/
protected function renderHeaderV2()
{
if ((
(
$this->context->controller instanceof AuthController
|| $this->context->controller instanceof RegistrationController
)
&& Configuration::get('CAPTCHA_ENABLE_ACCOUNT') == 1
)
||
($this->context->controller instanceof ContactController
&& Configuration::get('CAPTCHA_ENABLE_CONTACT') == 1
)
|| Configuration::get('CAPTCHA_LOAD_EVERYWHERE') == 1
) {
$this->context->controller->registerStylesheet(
'module-eicaptcha',
'modules/' . $this->name . '/views/css/eicaptcha.css'
);
//Dynamic insertion of the content
$js = '<script type="text/javascript">
//Recaptcha CallBack Function
var onloadCallback = function() {
//Fix captcha box issue in ps 1.7.7
if ( ! document.getElementById("captcha-box")){
var container = document.createElement("div");
container.setAttribute("id","captcha-box");
if ( null !== document.querySelector(".form-fields") ){
document.querySelector(".form-fields").appendChild(container);
}
}
if ( document.getElementById("captcha-box")){
grecaptcha.render("captcha-box", {"theme" : "' . $this->themes[Configuration::get('CAPTCHA_THEME')] . '", "sitekey" : "' . Configuration::get('CAPTCHA_PUBLIC_KEY') . '"});
} else {
console.warn("eicaptcha: unable to add captcha-box placeholder to display captcha ( not an error when form is submited sucessfully )");
}
};
</script>';
if (($this->context->controller instanceof ContactController && Configuration::get('CAPTCHA_ENABLE_CONTACT') == 1)) {
$js .= '<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit&hl=' . $this->captchaLang . '" async defer></script>';
}
return $js;
}
}
/**
* Return content for recaptcha v3
*
* @return string|void
*/
public function renderHeaderV3()
{
if (
($this->context->controller instanceof ContactController
&& Configuration::get('CAPTCHA_ENABLE_CONTACT') == 1
)
|| Configuration::get('CAPTCHA_LOAD_EVERYWHERE') == 1
) {
$publicKey = Configuration::get('CAPTCHA_PUBLIC_KEY');
$js = '
<script src="https://www.google.com/recaptcha/api.js?render=' . $publicKey . '"></script>
<script>
grecaptcha.ready(function () {
grecaptcha.execute("' . $publicKey . '", {action: "contact"}).then(function (token) {
var recaptchaResponse = document.getElementById("captcha-box");
recaptchaResponse.value = token;
});
});
</script>';
return $js;
}
}
/**
* Add Captcha on the Customer Registration Form
*
* @param array $params
*
* @return string|void
*/
public function hookDisplayCustomerAccountForm(array $params)
{
if ($this->context->controller->php_self != 'identity'
&& Configuration::get('CAPTCHA_ENABLE_ACCOUNT') == 1
) {
$this->context->smarty->assign([
'captchaVersion' => Configuration::get('CAPTCHA_VERSION'),
'publicKey' => Configuration::get('CAPTCHA_PUBLIC_KEY'),
'captchalang' => $this->captchaLang,
'captchatheme' => $this->themes[Configuration::get('CAPTCHA_THEME')],
]);
return $this->display(__FILE__, 'views/templates/hook/hookDisplayCustomerAccountForm.tpl');
}
}
/**
* Check captcha before submit account
* Custom hook
*
* @param array $params
*
* @return bool|void
*
* @deprecated since 2.4.0
*/
public function hookActionContactFormSubmitCaptcha(array $params)
{
if (Configuration::get('CAPTCHA_ENABLE_ACCOUNT') == 1) {
$this->debugger->log('check customer registration by method ' . __METHOD__);
return $this->_validateCaptcha();
}
}
/**
* Check captcha before submit account
* Prestashop native hook
*
* @param array $params
*
* @return bool
*
* @since 2.5.0
*/
public function hookActionSubmitAccountBefore(array $params)
{
if (Configuration::get('CAPTCHA_ENABLE_ACCOUNT') == 1
&& Configuration::get('CAPTCHA_USE_AUTHCONTROLLER_OVERRIDE') == 0) {
$this->debugger->log('check customer registration by method ' . __METHOD__);
return $this->_validateCaptcha();
}
return true;
}
/**
* Check captcha before submit account
* Custom hook
*
* @param array $params
*
* @return bool|void
*
* @since 2.4.0
*/
public function hookActionCustomerRegisterSubmitCaptcha(array $params)
{
if (Configuration::get('CAPTCHA_ENABLE_ACCOUNT') == 1) {
$this->debugger->log('check customer registration by method ' . __METHOD__);
return $this->_validateCaptcha();
}
}
/**
* Check captcha before submit contact form
* new custom hook
*
* @return bool|void
*/
public function hookActionContactFormSubmitBefore()
{
if (Configuration::get('CAPTCHA_ENABLE_CONTACT') == 1) {
return $this->_validateCaptcha();
}
}
/**
* Register media in back office
*
* @param array $params
*
* @return void
*
* @since 2.1.0
*/
public function hookActionAdminControllerSetMedia(array $params)
{
if (
$this->context->controller instanceof AdminModulesController
&& Tools::getValue('configure') == $this->name
&& Tools::getValue('display_debug') == 1
) {
$this->context->controller->addJS(
$this->_path . 'views/js/admin.js'
);
}
}
/**
* New hook to display content for newsletter registration
* ( Need to override theme template for themes/classic/modules/ps_emailsubscription/views/templates/hook/ps_emailsubscription.tpl )
*
* @param array $params
*
* @return string|void
*
* @since 2.1.0
*/
public function hookDisplayNewsletterRegistration(array $params)
{
if (
Configuration::get('CAPTCHA_ENABLE_NEWSLETTER') == 1
&& $this->canUseCaptchaOnNewsletter()
&& $this->shouldDisplayToCustomer()
) {
$this->context->smarty->assign([
'captchaVersion' => Configuration::get('CAPTCHA_VERSION'),
'publicKey' => Configuration::get('CAPTCHA_PUBLIC_KEY'),
'captchalang' => $this->captchaLang,
'captchatheme' => $this->themes[Configuration::get('CAPTCHA_THEME')],
]);
return $this->display(__FILE__, 'views/templates/hook/hookDisplayNewsletterRegistration.tpl');
}
}
/**
* New Hook to validate newsletter registration
*
* @param array $params
*
* @return void
*
* @since 2.1.0
*/
public function hookActionNewsletterRegistrationBefore(array $params)
{
if (Configuration::get('CAPTCHA_ENABLE_NEWSLETTER') == 1
&& $this->canUseCaptchaOnNewsletter()
&& $this->shouldDisplayToCustomer()
) {
if (!$this->_validateCaptcha()) {
$params['hookError'] = $this->l('Please validate the captcha field before submitting your request');
}
}
}
/**
* Validate Captcha
*
* @return bool
*/
protected function _validateCaptcha()
{
if (!$this->shouldDisplayToCustomer()) {
return true;
}
$context = Context::getContext();
//Fix issue if allow_url_open is set to 0
if (function_exists('ini_get') && !ini_get('allow_url_fopen')) {
$recaptchaMethod = new \ReCaptcha\RequestMethod\CurlPost();
} else {
$recaptchaMethod = null;
}
$captcha = new ReCaptcha(Configuration::get('CAPTCHA_PRIVATE_KEY'), $recaptchaMethod);
$result = $captcha->verify(
Tools::getValue('g-recaptcha-response'),
Tools::getRemoteAddr()
);
if (!$result->isSuccess()) {
$errorMessage = $this->l('Please validate the captcha field before submitting your request');
$this->debugger->log($errorMessage);
$this->debugger->log(sprintf($this->l('Recaptcha response %s'), print_r($result->getErrorCodes(), true)));
$context->controller->errors[] = $errorMessage;
return false;
}
$this->debugger->log($this->l('Captcha submited with success'));
return true;
}
/**
* Custom hook where you can get all the eicaptcha configuration to use the captcha in another module
* And display with your own template
* Or in a custom controller
*
* @param array $params
*
* @return array The eicaptcha configuration
*/
public function hookActionGetEicaptchaParams(array $params)
{
return [
'displayCaptcha' => $this->shouldDisplayToCustomer(),
'captchaVersion' => Configuration::get('CAPTCHA_VERSION'),
'publicKey' => Configuration::get('CAPTCHA_PUBLIC_KEY'),
'captchaforcelang' => Configuration::get('CAPTCHA_FORCE_LANG'),
'captchatheme' => $this->themes[Configuration::get('CAPTCHA_THEME')],
];
}
/**
* Custom hook used to render the captcha form with the default template
*
* @param array $params
*
* @return string the rendered template for displaying the captcha ( if needed)
*/
public function hookDisplayEicaptchaVerification(array $params)
{
$this->context->smarty->assign([
'displayCaptcha' => $this->shouldDisplayToCustomer(),
'captchaVersion' => Configuration::get('CAPTCHA_VERSION'),
'publicKey' => Configuration::get('CAPTCHA_PUBLIC_KEY'),
'captchalang' => $this->captchaLang,
'captchatheme' => $this->themes[Configuration::get('CAPTCHA_THEME')],
]);
return $this->display(__FILE__, 'views/templates/hook/hookDisplayEicaptchaVerification.tpl');
}
/**
* Custom hook used to validate captcha response
*
* @param array $params
*
* @return bool
*/
public function hookActionValidateCaptcha(array $params = [])
{
return $this->_validateCaptcha();
}
/**
* Define if captcha can be use on newsletter form
* Needs a recent version of ps_emailsubscription which implements new required hooks
*
* @return bool
*/
public function canUseCaptchaOnNewsletter()
{
if (Module::isInstalled('ps_emailsubscription')) {
$emailSubcription = Module::getInstanceByName('ps_emailsubscription');
if (version_compare('2.6.0', $emailSubcription->version) <= 0) {
return true;
}
}
return false;
}
/**
* Define if the captcha should be displayed to the customer
*
* @return bool
*/
protected function shouldDisplayToCustomer()
{
if (
Configuration::get('CAPTCHA_ENABLE_LOGGED_CUSTOMERS') == 0
&& $this->context->customer->id > 0
&& $this->context->customer->email != null
) {
return false;
}
return true;
}
}