* @copyright 2013-2021 Hennes Hervé * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) * http://www.h-hennes.fr/blog/ */ 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; public function __construct() { $this->author = 'hhennes'; $this->name = 'eicaptcha'; $this->tab = 'front_office_features'; $this->version = '2.3.1'; $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); } /** * 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($params) { $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 && Configuration::get('CAPTCHA_ENABLE_ACCOUNT') == 1) || ($this->context->controller instanceof ContactController && Configuration::get('CAPTCHA_ENABLE_CONTACT') == 1) ) { $this->context->controller->registerStylesheet( 'module-eicaptcha', 'modules/' . $this->name . '/views/css/eicaptcha.css' ); //Dynamic insertion of the content $js = ''; if (($this->context->controller instanceof ContactController && Configuration::get('CAPTCHA_ENABLE_CONTACT') == 1)) { $js .= ''; } 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 ) { $publicKey = Configuration::get('CAPTCHA_PUBLIC_KEY'); $js = ' '; return $js; } } /** * Add Captcha on the Customer Registration Form * * @param array $params * * @return string|void */ public function hookDisplayCustomerAccountForm($params) { if (Configuration::get('CAPTCHA_ENABLE_ACCOUNT') == 1) { $this->context->smarty->assign([ 'captchaVersion' => Configuration::get('CAPTCHA_VERSION'), 'publicKey' => Configuration::get('CAPTCHA_PUBLIC_KEY'), 'captchaforcelang' => Configuration::get('CAPTCHA_FORCE_LANG'), '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 */ public function hookActionContactFormSubmitCaptcha($params) { if (Configuration::get('CAPTCHA_ENABLE_ACCOUNT') == 1) { 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($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($params) { if (Configuration::get('CAPTCHA_ENABLE_NEWSLETTER') == 1 && $this->canUseCaptchaOnNewsletter()) { $this->context->smarty->assign([ 'captchaVersion' => Configuration::get('CAPTCHA_VERSION'), 'publicKey' => Configuration::get('CAPTCHA_PUBLIC_KEY'), 'captchaforcelang' => Configuration::get('CAPTCHA_FORCE_LANG'), '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($params) { if (Configuration::get('CAPTCHA_ENABLE_NEWSLETTER') == 1 && $this->canUseCaptchaOnNewsletter()) { if (!$this->_validateCaptcha()) { $params['hookError'] = $this->l('Please validate the captcha field before submitting your request'); } } } /** * Validate Captcha * * @return bool */ protected function _validateCaptcha() { $context = Context::getContext(); $captcha = new ReCaptcha(Configuration::get('CAPTCHA_PRIVATE_KEY')); $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; } /** * 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; } }