<?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 LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://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 license@prestashop.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
 * versions in the future. If you wish to customize PrestaShop for your
 * needs please refer to http://www.prestashop.com for more information.
 *
 * @author    PrestaShop SA <contact@prestashop.com>
 * @copyright 2007-2018 PrestaShop SA
 * @license   http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
 * International Registered Trademark & Property of PrestaShop SA
 */

class Recaptcha extends Module
{
    private $html;

    public function __construct()
    {
        $this->author = 'StudioCloud';
        $this->name = 'recaptcha';
        $this->tab = 'front_office_features';
        $this->version = '1.1.9';
        $this->need_instance = 1;
        $this->bootstrap = true;
        $this->module_key = '043ded363584caaa9e93cf89cbaac5e9';
        parent::__construct();
        if (version_compare(_PS_VERSION_, '1.5', '<')) {
            require(_PS_MODULE_DIR_.$this->name.'/backward_compatibility/backward.php');
        }
        $this->ps_versions_compliancy = array('min' => '1.4.0.2', 'max' => '1.7.99.99');
        $this->displayName = $this->l('reCaptcha');
        $this->description = $this->l('Add a captcha to the registration and contact forms.');
        if ($this->active &&
            (!Configuration::get('CAPTCHA_PUBLIC_KEY') || !Configuration::get('CAPTCHA_PRIVATE_KEY'))) {
            $this->warning = $this->l('ReCaptcha Module needs to be configured.');
        }
    }

    public function install()
    {
        $this->warning = 'warning';
        if (version_compare(_PS_VERSION_, '1.5', '<')) {
            if (!Db::getInstance()->getValue('SELECT id_hook FROM '._DB_PREFIX_.'hook WHERE name = "contactFormBottom"')) {
                Db::getInstance()->autoExecute(_DB_PREFIX_.'hook', array(
                        'name' => 'contactFormBottom',
                        'title' => 'Contact form bottom',
                        'description' => null,
                        'position' => 1,
                        'live_edit' => 1
                    ), 'INSERT');
            }
            if (!Db::getInstance()->getValue('SELECT id_hook FROM '._DB_PREFIX_.'hook WHERE name = "contactCaptchaValidate"')) {
                Db::getInstance()->autoExecute(_DB_PREFIX_.'hook', array(
                        'name' => 'contactCaptchaValidate',
                        'title' => 'Contact Captcha Validate',
                        'description' => null,
                        'position' => 1,
                        'live_edit' => 1
                    ), 'INSERT');
            }
            if (!Db::getInstance()->getValue('SELECT id_hook FROM '._DB_PREFIX_.'hook WHERE name = "storespagesCaptchaValidate"')) {
                Db::getInstance()->autoExecute(_DB_PREFIX_.'hook', array(
                        'name' => 'storespagesCaptchaValidate',
                        'title' => 'Storespages Captcha Validate',
                        'description' => null,
                        'position' => 1,
                        'live_edit' => 1
                    ), 'INSERT');
            }
            if (!Db::getInstance()->getValue('SELECT id_hook FROM '._DB_PREFIX_.'hook WHERE name = "displayStorespagesCaptcha"')) {
                Db::getInstance()->autoExecute(_DB_PREFIX_.'hook', array(
                        'name' => 'displayStorespagesCaptcha',
                        'title' => 'Display Storespages Captcha',
                        'description' => null,
                        'position' => 1,
                        'live_edit' => 1
                    ), 'INSERT');
            }
            if (!Db::getInstance()->getValue('SELECT id_hook FROM '._DB_PREFIX_.'hook WHERE name = "displayMobileHeader"')) {
                Db::getInstance()->autoExecute(_DB_PREFIX_.'hook', array(
                        'name' => 'displayMobileHeader',
                        'title' => 'Display mobile header',
                        'description' => null,
                        'position' => 1,
                        'live_edit' => 1
                    ), 'INSERT');
            }
            if (!parent::install()
                || !$this->registerHook('header')
                || !$this->registerHook('displayMobileHeader')
                || !$this->registerHook('createAccountForm')
                || !$this->registerHook('storespagesCaptchaValidate')
                || !$this->registerHook('displayStorespagesCaptcha')
                || !$this->registerHook('contactFormBottom')) {
                return false;
            }
            if (file_exists(_PS_ROOT_DIR_.'/override/controllers/ContactController.php')
                || !copy(
                    _PS_MODULE_DIR_.'recaptcha/override/controllers/front/ContactController.php',
                    _PS_ROOT_DIR_.'/override/controllers/ContactController.php'
                )) {
                return false;
            }
            if (file_exists(_PS_ROOT_DIR_.'/override/controllers/AuthController.php')
                || !copy(
                    _PS_MODULE_DIR_.'recaptcha/override/controllers/front/AuthController.php',
                    _PS_ROOT_DIR_.'/override/controllers/AuthController.php'
                )) {
                return false;
            }
        } else {
            if (!parent::install()
                || !$this->registerHook('header')
                || !$this->registerHook('displayMobileHeader')
                || !$this->registerHook('displayCustomerAccountForm')
                || !$this->registerHook('actionBeforeSubmitAccount')
                || !$this->registerHook('storespagesCaptchaValidate')
                || !$this->registerHook('displayStorespagesCaptcha')
                || !$this->registerHook('contactFormBottom')
                || !$this->registerHook('contactCaptchaValidate')) {
                return false;
            }
        }

        $this->clearSmartyCache();

        return true;
    }

    public function uninstall($keep_data = false)
    {
        if (!$keep_data) {
            Configuration::deleteByName('CAPTCHA_PUBLIC_KEY');
            Configuration::deleteByName('CAPTCHA_PRIVATE_KEY');
            Configuration::deleteByName('CAPTCHA_ENABLE_ACCOUNT');
            Configuration::deleteByName('CAPTCHA_ENABLE_CONTACT');
        }
        if (!parent::uninstall()) {
            return false;
        }
        $this->clearSmartyCache();
        return true;
    }

    public function reset($keep_data = true)
    {
        if ($this->uninstall($keep_data)) {
            return $this->install($keep_data);
        }
    }

    public function getContent()
    {
        $this->postProcess();
        $documentation_url = $this->_path.'Readme_'.($this->context->language->iso_code === 'fr' ? 'fr' : 'en').'.pdf';

        if (version_compare(_PS_VERSION_, '1.5', '<')) {
            $this->context->smarty->assign(array(
                'current_url' => 'index.php?tab=AdminModules&configure='.$this->name.
                    '&tab_module='.$this->tab.
                    '&module_name='.$this->name.
                    '&token='.Tools::getAdminTokenLite('AdminModules'),
                'captcha_public_key' => Configuration::get('CAPTCHA_PUBLIC_KEY'),
                'captcha_private_key' => Configuration::get('CAPTCHA_PRIVATE_KEY'),
                'captcha_enable_account' => Configuration::get('CAPTCHA_ENABLE_ACCOUNT'),
                'captcha_enable_contact' => Configuration::get('CAPTCHA_ENABLE_CONTACT'),
                'documentation_url' => $documentation_url,
            ));
            return $this->display(__FILE__, '/views/templates/admin/configure_ps14.tpl');
        } else {
            $fields_form = array(
                'form' => array(
                    'legend' => array(
                        'title' => $this->l('Captcha Configuration'),
                        'icon' => 'icon-cogs'
                    ),
                    'input' => array(
                        array(
                            'type' => 'html',
                            'name' => 'installation',
                            'html_content' => '<div class="alert alert-info">'.
                                $this->l('Please read the instructions of installation before using this module:').
                                ' <a href="'.$documentation_url.'" target="_blank">'.$this->l('Documentation').'</a></div>'
                        ),
                        array(
                            'type' => 'text',
                            'label' => $this->l('Site key'),
                            'name' => 'captcha_public_key'
                        ),
                        array(
                            'type' => 'text',
                            'label' => $this->l('Secret key'),
                            'name' => 'captcha_private_key',
                            'desc' => $this->l('To get your own key pair please click on the following link').
                                '<br /><a href="https://www.google.com/recaptcha/admin#whyrecaptcha" target="_blank">https://www.google.com/recaptcha/admin#whyrecaptcha</a>',
                        ),
                        array(
                            'type'      => 'radio',
                            'label'     => $this->l('Enable Captcha for account creation'),
                            'name'      => 'captcha_enable_account',
                            'is_bool'   => true,
                            'class'     => 't',
                            'values'    => array(
                                array(
                                    'id'    => 'active_on',
                                    'value' => 1,
                                    'label' => $this->l('Yes')
                                ),
                                array(
                                    'id'    => 'active_off',
                                    'value' => 0,
                                    'label' => $this->l('No')
                                )
                            )
                        ),
                        array(
                            'type'      => 'radio',
                            'label'     => $this->l('Enable Captcha on contact form'),
                            'name'      => 'captcha_enable_contact',
                            'is_bool'   => true,
                            'class'     => 't',
                            'values'    => array(
                                array(
                                    'id'    => 'active_on',
                                    'value' => 1,
                                    'label' => $this->l('Yes')
                                ),
                                array(
                                    'id'    => 'active_off',
                                    'value' => 0,
                                    'label' => $this->l('No')
                                )
                            )
                        )
                    ),
                    'submit' => array(
                        'title' => $this->l('Save'),
                        'name' => 'SubmitCaptchaConfiguration'
                    )
                ),
            );
            $helper = new HelperForm();
            $helper->show_toolbar = false;
            $helper->table = $this->table;
            $lang = new Language((int)Configuration::get('PS_LANG_DEFAULT'));
            $helper->default_form_language = $lang->id;
            $helper->module = $this;
            $helper->allow_employee_form_lang = (int)Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG');
            $helper->identifier = $this->identifier;
            $helper->submit_action = '';
            $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false).
                '&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
            $helper->token = Tools::getAdminTokenLite('AdminModules');
            $helper->tpl_vars = array(
                'uri' => $this->getPathUri(),
                'fields_value' => $this->getConfigFieldsValues(),
                'languages' => $this->context->controller->getLanguages(),
                'id_language' => $this->context->language->id
            );
            return $helper->generateForm(array($fields_form));
        }
    }

    public function getConfigFieldsValues()
    {
        return array(
            'captcha_private_key' => Tools::getValue('captcha_private_key', Configuration::get('CAPTCHA_PRIVATE_KEY')),
            'captcha_public_key' => Tools::getValue('captcha_public_key', Configuration::get('CAPTCHA_PUBLIC_KEY')),
            'captcha_enable_account' => Tools::getValue('captcha_enable_account', Configuration::get('CAPTCHA_ENABLE_ACCOUNT')),
            'captcha_enable_contact' => Tools::getValue('captcha_enable_contact', Configuration::get('CAPTCHA_ENABLE_CONTACT'))
        );
    }

    public function postProcess()
    {
        if (Tools::isSubmit('SubmitCaptchaConfiguration')) {
            Configuration::updateValue('CAPTCHA_PUBLIC_KEY', pSQL(Tools::getValue('captcha_public_key')));
            Configuration::updateValue('CAPTCHA_PRIVATE_KEY', pSQL(Tools::getValue('captcha_private_key')));
            Configuration::updateValue('CAPTCHA_ENABLE_ACCOUNT', (int)Tools::getValue('captcha_enable_account'));
            Configuration::updateValue('CAPTCHA_ENABLE_CONTACT', (int)Tools::getValue('captcha_enable_contact'));

            $this->clearSmartyCache();

            Tools::redirectAdmin(
                'index.php?tab=AdminModules&configure='.$this->name.
                '&tab_module='.$this->tab.
                '&module_name='.$this->name.
                '&token='.Tools::getAdminTokenLite('AdminModules').
                '&conf=4'
            );
        }
    }

    public function hookHeader()
    {
        //to alter ajax request on OPC registration
        if (version_compare(_PS_VERSION_, '1.7', '<') &&
            ($this->context->controller instanceof OrderOpcController || $this->context->controller instanceof ControllerBackwardModule) &&
            Configuration::get('CAPTCHA_ENABLE_ACCOUNT')) {
            if (method_exists($this->context->controller, 'addJS')) {
                $this->context->controller->addJS($this->_path.'views/js/front.js');
            } elseif (method_exists(Tools, 'addJS')) {
                Tools::addJS($this->_path.'views/js/front.js');
            }
        }
        if ($this->context->controller instanceof ControllerBackwardModule
            || $this->context->controller instanceof ProductController
            || ($this->context->controller instanceof ContactController && Configuration::get('CAPTCHA_ENABLE_CONTACT'))
            || ($this->context->controller instanceof AuthController && Configuration::get('CAPTCHA_ENABLE_ACCOUNT'))
            || ($this->context->controller instanceof ParentOrderController && Configuration::get('CAPTCHA_ENABLE_ACCOUNT'))
            || ($this->context->controller instanceof OrderOpcController && Configuration::get('CAPTCHA_ENABLE_ACCOUNT'))
            || ($this->context->controller instanceof OrderController && Configuration::get('CAPTCHA_ENABLE_ACCOUNT'))
            || $this->context->controller instanceof StoresPagesStoreModuleFrontController) {
            if (method_exists($this->context->controller, 'registerJavascript')) {
                $this->context->controller->registerJavascript(
                    'remote-recaptcha',
                    'https://www.google.com/recaptcha/api.js?hl='.$this->context->language->language_code,
                    array('server' => 'remote')
                );
            } elseif (version_compare(_PS_VERSION_, '1.5.0', '>') && method_exists($this->context->controller, 'addJS')) {
                $this->context->controller->addJS('https://www.google.com/recaptcha/api.js?hl='.$this->context->language->language_code, false);
            } elseif (version_compare(_PS_VERSION_, '1.5.0', '>') && method_exists(Tools, 'addJS')) {
                Tools::addJS('https://www.google.com/recaptcha/api.js?hl='.$this->context->language->language_code, false);
            } else {
                return '<script src="https://www.google.com/recaptcha/api.js?hl='.$this->context->language->language_code.'" async defer></script>';
            }
        }
    }

    public function hookDisplayMobileHeader()
    {
        return $this->hookHeader();
    }

    public function hookCreateAccountForm()
    {
        if (Configuration::get('CAPTCHA_ENABLE_ACCOUNT') == 1) {
            return $this->displayCaptcha();
        }
    }

    public function hookDisplayCustomerAccountForm()
    {
        if (Configuration::get('CAPTCHA_ENABLE_ACCOUNT') == 1) {
            return $this->displayCaptcha();
        }
    }

    public function hookDisplayStorespagesCaptcha()
    {
        return $this->displayCaptcha();
    }

    public function hookContactFormBottom()
    {
        if (Configuration::get('CAPTCHA_ENABLE_CONTACT') == 1) {
            return $this->displayCaptcha();
        }
    }

    protected function displayCaptcha()
    {
        $this->context->smarty->assign('site_key', Configuration::get('CAPTCHA_PUBLIC_KEY'));
        if (version_compare(_PS_VERSION_, '1.7.0.0', '>=')) {
            return $this->fetch('module:recaptcha/views/templates/hook/captcha1.7.tpl');
        } else {
            return $this->display(__FILE__, '/views/templates/hook/captcha.tpl');
        }
    }

    /*
     * Validation Hooks
     */
    public function hookContactCaptchaValidate()
    {
        if (Configuration::get('CAPTCHA_ENABLE_CONTACT') == 1) {
            return $this->validateCaptcha();
        }
    }

    public function hookActionBeforeSubmitAccount()
    {
        if (Configuration::get('CAPTCHA_ENABLE_ACCOUNT') == 1) {
            return $this->validateCaptcha();
        }
        return true;
    }

    /* For storespages module */
    public function hookStorespagesCaptchaValidate()
    {
        return $this->validateCaptcha();
    }

    public function validateCaptcha()
    {
        $google_request_url =
            'https://www.google.com/recaptcha/api/siteverify?secret='.
            Configuration::get('CAPTCHA_PRIVATE_KEY').
            '&response='.Tools::getValue('g-recaptcha-response').
            '&remoteip='.$_SERVER['REMOTE_ADDR'];

        $ch = curl_init($google_request_url);
        curl_setopt_array($ch, array(
            CURLOPT_TIMEOUT => 10,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_HEADER => false,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
        ));
        $google_response = curl_exec($ch);
        curl_close($ch);

        if (version_compare(_PS_VERSION_, '1.7.0.0', '<')) {
            $google_response = Tools::jsonDecode($google_response);
        } else {
            $google_response = json_decode($google_response);
        }

        if (empty($google_response->success) || $google_response->success !== true) {
            if (version_compare(_PS_VERSION_, '1.5', '>=')) {
                Context::getContext()->controller->errors[] = $this->l('Invalid captcha.');
            }
            return false;
        }

        return true;
    }

    protected function clearSmartyCache()
    {
        if (method_exists('ToolsCore', 'clearSmartyCache')) {
            Tools::clearSmartyCache();
        } else {
            $smarty = Context::getContext()->smarty;
            $smarty->clearAllCache();
            $smarty->clearCompiledTemplate();
        }

        if (file_exists(_PS_ROOT_DIR_.'/cache/class_index.php')) {
            unlink(_PS_ROOT_DIR_.'/cache/class_index.php');
        }
    }
}
