<?php
/**
* NOTICE OF LICENSE
*
* This file is licenced under the Software License Agreement.
* With the purchase or the installation of the software in your application
* you accept the licence agreement.
*
* You must not modify, adapt or create derivative works of this source code.
*
*  @author    Active Design <office@activedesign.ro>
*  @copyright 2017 Active Design
*  @license   LICENSE.txt
*/

if (!defined('_PS_VERSION_')) {
    exit;
}

class Oneclickssl extends Module
{
    protected $config_form = false;

    public function __construct()
    {
        $this->name = 'oneclickssl';
        $this->tab = 'others';
        $this->version = '2.0.1';
        $this->author = 'Active Design';
        $this->need_instance = 0;
        $this->module_key = '0c6bcd532f9fc2c78daa450e4bca295d';
        $this->author_address = '0xc0D7cE57752e47305707d7174B9686C0Afb229c3';

        /**
         * Set $this->bootstrap to true if your module is compliant with bootstrap (PrestaShop 1.6)
         */
        $this->bootstrap = true;

        parent::__construct();

        $this->displayName = $this->l('One click SSL');
        $this->description = $this->l('This module allows you to install a SSL Certificate on your server, for HTTPS connections');
    }

    /**
     * Don't forget to create update methods if needed:
     * http://doc.prestashop.com/display/PS16/Enabling+the+Auto-Update
     */
    public function install()
    {
        return parent::install() &&
            $this->registerHook('displayBackOfficeHeader');
    }

    public function uninstall()
    {
        return parent::uninstall();
    }
    
    public function hookDisplayBackOfficeHeader()
    {
        if(Tools::getValue('module_name') == $this->name || Tools::getValue('configure') == $this->name)
        {
            $this->context->controller->addCSS($this->_path.'views/css/back.css');
            $this->context->controller->addJquery();
            $this->context->controller->addJqueryPlugin('fancybox');
            $this->context->controller->addJS($this->_path.'views/js/back.js');
        }
    }

    /**
     * Load the configuration form
     */
    public function getContent()
    {
        $output = "";
        /**
         * If values have been submitted in the form, process.
         */
        if (((bool)Tools::isSubmit('submitOneclicksslModule')) == true && Tools::getValue('ONECLICKSSL_INSTALL')) {
            $output .= $this->postProcess();
        } else {
            $output = $this->context->smarty->fetch(_PS_MODULE_DIR_.'oneclickssl/views/templates/admin/info.tpl');
        }

        $this->context->smarty->assign('module_dir', $this->_path);

        $domains = $this->getDomains();
        $domain = reset($domains);
        
        $link = new Link;
        $cert_url = $link->getModuleLink('oneclickssl', 'downloadcert', array('cert' => 'cert', 'domain' => $domain));
        $private_url = $link->getModuleLink('oneclickssl', 'downloadcert', array('cert' => 'private', 'domain' => $domain));
        $checkhttps = $this->context->link->getModuleLink($this->name, 'helper');
        if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'])
        {
            $cert_url = str_replace('http://', 'https://', $cert_url);
            $private_url = str_replace('http://', 'https://', $private_url);
        }
        $this->context->smarty->assign(array(
            'cert_url' => $cert_url,
            'private_url' => $private_url,
            'checkhttps' => $checkhttps,
            'oneclickssl_activated_success' => $this->l('HTTPS was successfully activated!'),
            'oneclickssl_activated_error' => $this->l('Error! HTTPS could not be activated.'),
            'oneclickssl_installed_error' => $this->l('Error! HTTPS was not installed correctly on your server.'),
        ));
        if(method_exists('Media', 'addJsDef'))
        {
            Media::addJsDef(array(
                'checkhttps' => $checkhttps,
                'oneclickssl_activated_success' => $this->l('HTTPS was successfully activated!'),
                'oneclickssl_activated_error' => $this->l('Error! HTTPS could not be activated.'),
                'oneclickssl_installed_error' => $this->l('Error! HTTPS was not installed correctly on your server.'),
            ));
        }
        else
        {
            $output .= $this->context->smarty->fetch(_PS_MODULE_DIR_.'oneclickssl/views/templates/admin/scripts.tpl');
        }

        return $output.$this->renderForm();
    }

    /**
     * Create the form that will be displayed in the configuration of your module.
     */
    protected function renderForm()
    {
        $helper = new HelperForm();

        $helper->show_toolbar = false;
        $helper->table = $this->table;
        $helper->module = $this;
        $helper->default_form_language = $this->context->language->id;
        $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG', 0);

        $helper->identifier = $this->identifier;
        $helper->submit_action = 'submitOneclicksslModule';
        $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(
            'fields_value' => $this->getConfigFormValues(), /* Add values for your inputs */
            'languages' => $this->context->controller->getLanguages(),
            'id_language' => $this->context->language->id,
        );

        return $helper->generateForm(array($this->getConfigForm()));
    }

    /**
     * Create the structure of your form.
     */
    protected function getConfigForm()
    {
        $switchorradio = 'switch';
        if(Tools::version_compare(_PS_VERSION_, '1.6', '<'))
        {
            $switchorradio = 'radio';
        }
        $return = array(
            'form' => array(
                'legend' => array(
                'title' => $this->l('Settings'),
                'icon' => 'icon-cogs',
                ),
                'input' => array(
                    array(
                        'type' => $switchorradio,
                        'label' => $this->l('Issue a SSL certificate'),
                        'name' => 'ONECLICKSSL_INSTALL',
                        'is_bool' => true,
                        'desc' => $this->l('Select "YES" and then click save'),
                        'values' => array(
                            array(
                                'id' => 'active_on',
                                'value' => true,
                                'label' => $this->l('Enabled')
                            ),
                            array(
                                'id' => 'active_off',
                                'value' => false,
                                'label' => $this->l('Disabled')
                            )
                        ),
                        'class' => ($switchorradio == 'radio') ? 't' : '',
                    ),
                    array(
                        'col' => 3,
                        'type' => 'text',
                        'prefix' => '<i class="icon icon-envelope"></i>',
                        'desc' => $this->l('Optional, will be used to remind you when the certificate expires.'),
                        'name' => 'ONECLICKSSL_EMAIL',
                        'label' => $this->l('Email'),
                    ),
                ),
                'submit' => array(
                    'title' => $this->l('Save'),
                ),
            ),
        );
        return $return;
    }

    /**
     * Set values for the inputs.
     */
    protected function getConfigFormValues()
    {
        return array(
            'ONECLICKSSL_INSTALL' => false,
            'ONECLICKSSL_EMAIL' => (trim(Configuration::get('ONECLICKSSL_EMAIL'))) ? trim(Configuration::get('ONECLICKSSL_EMAIL')) : $this->context->employee->email,
        );
    }

    /**
     * Save form data.
     */
    protected function postProcess()
    {
        if(!defined("PHP_VERSION_ID") || PHP_VERSION_ID < 50300 || !extension_loaded('openssl') || !extension_loaded('curl')) {
            return "You need at least PHP 5.3.0 with OpenSSL and curl extension\n";
        }
        require_once('LEClient-master/LEClient/LEClient.php');

        $email = array(Tools::getValue('ONECLICKSSL_EMAIL'));
        // Listing the domains to be included on the certificate
        $domains = $this->getDomains();
        
        $basename = $domains[0];

        // Initiating the client instance. In this case using the staging server (argument 2) and outputting all status and debug information (argument 3).
        $client = new LEClient($email, LEClient::LE_PRODUCTION, LECLient::LOG_STATUS, dirname(__FILE__).'/certificates/');
        // Initiating the order instance. The keys and certificate will be stored in /example.org/ (argument 1) and the domains in the array (argument 2) will be on the certificate.
        $order = $client->getOrCreateOrder($basename, $domains);
        // Check whether there are any authorizations pending. If that is the case, try to verify the pending authorizations.
        if(!$order->allAuthorizationsValid())
        {
            // Get the HTTP challenges from the pending authorizations.
            $pending = $order->getPendingAuthorizations(LEOrder::CHALLENGE_TYPE_HTTP);
            // Walk the list of pending authorization HTTP challenges.
            if(!empty($pending))
            {
                foreach($pending as $challenge)
                {
                    // Define the folder in which to store the challenge. For the purpose of this example, a fictitious path is set.
                    $folder = $this->getRootDir().'/.well-known/acme-challenge/';
                    // Check if that directory yet exists. If not, create it.
                    if(!file_exists($folder)) mkdir($folder, 0777, true);
                    // Store the challenge file for this domain.
                    file_put_contents($folder . $challenge['filename'], $challenge['content']);
                    // Let LetsEncrypt verify this challenge.
                    $order->verifyPendingOrderAuthorization($challenge['identifier'], LEOrder::CHALLENGE_TYPE_HTTP);
                }
            }
        }
        // Check once more whether all authorizations are valid before we can finalize the order.
        $failed = true;
        if($order->allAuthorizationsValid())
        {
            // Finalize the order first, if that is not yet done.
            if(!$order->isFinalized()) $order->finalizeOrder();
            // Check whether the order has been finalized before we can get the certificate. If finalized, get the certificate.
            if($order->isFinalized()) {
                $order->getCertificate();
                $failed = false;
            }
        }
        $errors = array();
        if(!$failed)
        {
            $errors[] = $this->l("Warning! Manual installation is required");
        }
        if($failed)
        {
            $errors[] = $this->l("Warning! Could not generate Certificate, response below:");
        }

        $tpl_vars = array(
            "loginfo" => LEFunctions::$logmessage,
            "errors" => $errors,
        );
        
        if(!$failed) {
            $cpanelcert_file = dirname(__FILE__).'/certificates/fullchain.crt';
            $pleskcert_file = dirname(__FILE__).'/certificates/fullchain.crt';
            $private_file = dirname(__FILE__).'/certificates/private.pem';
            $cpanelcert = Tools::file_get_contents($cpanelcert_file);
            if(!$cpanelcert)
            {
                $cpanelcert = sprintf($this->l("Warning! Could not open file %s"), $cpanelcert_file);
            }
            $pleskcert = Tools::file_get_contents($pleskcert_file);
            if(!$pleskcert)
            {
                $pleskcert = sprintf($this->l("Warning! Could not open file %s"), $pleskcert_file);
            }
            $private = Tools::file_get_contents($private_file);
            if(!$private)
            {
                $private = sprintf($this->l("Warning! Could not open file %s"), $private_file);
            }
             
            $tpl_vars["cpanelcert"] = $cpanelcert;
            $tpl_vars["pleskcert"] = $pleskcert;
            $tpl_vars["private"] = $private;
        }
        $tpl_vars["failed"] = $failed;

        $this->context->smarty->assign($tpl_vars);

        return $this->context->smarty->fetch(_PS_MODULE_DIR_.'oneclickssl/views/templates/admin/loginfo.tpl');
    }

    protected function getDomains()
    {
        $context = Context::getContext();
        if (isset($context->shop->domain_ssl) && $context->shop->domain_ssl) {
            $domain = $context->shop->domain_ssl;
        }
        else {
            $domain = $context->shop->domain;
        }
            
        $domain = 'www.'.$domain;
        if (Tools::substr($domain, 0, 4) == 'www.') {
            $domain = substr($domain, 4);
        }
        $domains = array(
            $domain,
            'www.'.$domain,
        );
        return $domains;
    }
    
    protected function getRootDir()
    {
        $context = Context::getContext();
        $physical_uri = trim($context->shop->physical_uri);
        if($physical_uri == '/')
        {
            return _PS_ROOT_DIR_;
        }
        else {
            $parts_text = trim($physical_uri, '/');
            $parts = explode('/', $parts_text);
            $extra_folders = sizeof($parts);
            
            $root_dir = trim(_PS_ROOT_DIR_, DIRECTORY_SEPARATOR);
            $root_dir_array = explode(DIRECTORY_SEPARATOR, $root_dir);
            $root_dir_array_finish = array_slice($root_dir_array, 0, sizeof($root_dir_array)-$extra_folders);
            
            $root_dir_return = DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $root_dir_array_finish).DIRECTORY_SEPARATOR;
            return $root_dir_return;
        }
    }
}
