File "class-letsencrypt-handler.php"

Full path: /home/kosmetik/public_html/wp-content/plugins/really-simple-ssl/lets-encrypt/class-letsencrypt-handler.php
File size: 54.37 B
MIME-type: text/x-php
Charset: utf-8

Download   Open   Edit   Advanced Editor   Back

<?php

defined('ABSPATH') or die("you do not have access to this page!");
require_once rsssl_le_path . 'vendor/autoload.php';
use LE_ACME2\Account;
use LE_ACME2\Authorizer\AbstractDNSWriter;
use LE_ACME2\Authorizer\DNS;
use LE_ACME2\Authorizer\HTTP;
use LE_ACME2\Connector\Connector;
use LE_ACME2\Order;
use LE_ACME2\Utilities\Certificate;
use LE_ACME2\Utilities\Logger;
class rsssl_letsencrypt_handler
{
    private static $_this;
    public $account = false;
    public $challenge_directory = false;
    public $key_directory = false;
    public $certs_directory = false;
    public $subjects = array();
    function __construct()
    {
        if (isset(self::$_this)) {
            wp_die(sprintf(__('%s is a singleton class and you cannot create a second instance.', 'really-simple-ssl'), get_class($this)));
        }
        if (rsssl_letsencrypt_generation_allowed(true)) {
            add_action('rsssl_before_save_lets-encrypt_option', array($this, 'before_save_wizard_option'), 10, 4);
            add_action('rsssl_le_activation', array($this, 'cleanup_on_ssl_activation'));
            add_action('rsssl_le_activation', array($this, 'plugin_activation_actions'));
            add_action('admin_init', array($this, 'maybe_add_htaccess_exclude'));
            add_action('admin_init', array($this, 'maybe_create_htaccess_directories'));
            $this->key_directory = $this->key_directory();
            $this->challenge_directory = $this->challenge_directory();
            $this->certs_directory = $this->certs_directory();
            if ($this->key_directory) {
                Account::setCommonKeyDirectoryPath($this->key_directory);
            }
            if ($this->challenge_directory) {
                HTTP::setDirectoryPath($this->challenge_directory);
            }
            Connector::getInstance()->useStagingServer(false);
            Logger::getInstance()->setDesiredLevel(Logger::LEVEL_DISABLED);
            if (!get_option('rsssl_disable_ocsp')) {
                Certificate::enableFeatureOCSPMustStaple();
            }
            Order::setPreferredChain('ISRG Root X1');
            $this->subjects = $this->get_subjects();
            $this->verify_dns();
        }
        self::$_this = $this;
    }
    static function this()
    {
        return self::$_this;
    }
    public function maybe_add_htaccess_exclude()
    {
        if (!current_user_can('manage_options')) {
            return;
        }
        if (!RSSSL()->rsssl_server->uses_htaccess()) {
            return;
        }
        $htaccess_file = RSSSL()->really_simple_ssl->htaccess_file();
        if (!file_exists($htaccess_file)) {
            return;
        }
        if (!is_writable($htaccess_file)) {
            return;
        }
        $htaccess = file_get_contents($htaccess_file);
        if (strpos($htaccess, 'Really Simple SSL LETS ENCRYPT') !== FALSE) {
            return;
        }
        $htaccess = preg_replace("/#\\s?BEGIN\\s?Really Simple SSL LETS ENCRYPT.*?#\\s?END\\s?Really Simple SSL LETS ENCRYPT/s", "", $htaccess);
        $htaccess = preg_replace("/\n+/", "\n", $htaccess);
        $rules = '#BEGIN Really Simple SSL LETS ENCRYPT' . "\n";
        $rules .= 'RewriteRule ^.well-known/(.*)$ - [L]' . "\n";
        $rules .= '#END Really Simple SSL LETS ENCRYPT' . "\n";
        $htaccess = $rules . $htaccess;
        file_put_contents($htaccess_file, $htaccess);
    }
    public function installation_failed()
    {
        $installation_active = get_option("rsssl_le_start_installation");
        $installation_failed = get_option("rsssl_installation_error");
        return $installation_active && $installation_failed;
    }
    public function plugin_activation_actions()
    {
        if (get_option('rsssl_activated_plugin')) {
            delete_option('rsssl_activated_plugin');
        }
    }
    public function cleanup_on_ssl_activation()
    {
        if (!current_user_can('manage_options')) {
            return;
        }
        $delete_credentials = !rsssl_get_value('store_credentials');
        if (!$this->certificate_automatic_install_possible() || !$this->certificate_install_required() || $delete_credentials) {
            $fields = RSSSL_LE()->config->fields;
            $fields = array_filter($fields, function ($i) {
                return isset($i['type']) && $i['type'] === 'password';
            });
            $options = get_option('rsssl_options_lets-encrypt');
            foreach ($fields as $fieldname => $field) {
                unset($options[$fieldname]);
            }
            update_option('rsssl_options_lets-encrypt', $options);
        }
    }
    public function before_save_wizard_option($fieldname, $fieldvalue, $prev_value, $type)
    {
        rsssl_progress_add('domain');
        if ($fieldvalue === $prev_value) {
            return;
        }
        if ($fieldname === 'other_host_type') {
            if (!rsssl_do_local_lets_encrypt_generation()) {
                rsssl_progress_add('directories');
                rsssl_progress_add('generation');
                rsssl_progress_add('dns-verification');
            }
        }
        if ($fieldname === 'email') {
            if (!is_email($fieldvalue)) {
                rsssl_progress_remove('domain');
            }
        }
    }
    public function check_domain()
    {
        $details = parse_url(site_url());
        $path = isset($details['path']) ? $details['path'] : '';
        if (strpos(site_url(), 'localhost') !== false) {
            rsssl_progress_remove('system-status');
            $action = 'stop';
            $status = 'error';
            $message = __("It is not possible to install Let's Encrypt on a localhost environment.", "really-simple-ssl");
        } else {
            if (is_multisite() && get_current_blog_id() !== get_main_site_id()) {
                rsssl_progress_remove('system-status');
                $action = 'stop';
                $status = 'error';
                $message = __("It is not possible to install Let's Encrypt on a subsite. Please go to the main site of your website.", "really-simple-ssl");
            } else {
                if (strlen($path) > 0) {
                    rsssl_progress_remove('system-status');
                    $action = 'stop';
                    $status = 'error';
                    $message = __("It is not possible to install Let's Encrypt on a subfolder configuration.", "really-simple-ssl") . rsssl_read_more('https://really-simple-ssl.com/install-ssl-on-subfolders');
                } else {
                    $action = 'continue';
                    $status = 'success';
                    $message = __("Your domain meets the requirements for Let's Encrypt.", "really-simple-ssl");
                }
            }
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    public function search_ssl_installation_url()
    {
        $url = 'https://really-simple-ssl.com/install-ssl-certificate';
        $host = 'enter-your-dashboard-url-here';
        if (function_exists('wp_get_direct_update_https_url') && !empty(wp_get_direct_update_https_url())) {
            $url = wp_get_direct_update_https_url();
        }
        if (rsssl_is_cpanel()) {
            $cpanel = new rsssl_cPanel();
            $host = $cpanel->host;
            $url = $cpanel->ssl_installation_url;
        } else {
            if (rsssl_is_plesk()) {
                $plesk = new rsssl_plesk();
                $host = $plesk->host;
                $url = $plesk->ssl_installation_url;
            } else {
                if (rsssl_is_directadmin()) {
                    $directadmin = new rsssl_directadmin();
                    $host = $directadmin->host;
                    $url = $directadmin->ssl_installation_url;
                }
            }
        }
        $hosting_company = rsssl_get_other_host();
        if ($hosting_company && $hosting_company !== 'none') {
            $hosting_specific_link = RSSSL_LE()->config->hosts[$hosting_company]['ssl_installation_link'];
            if ($hosting_specific_link) {
                $site = trailingslashit(str_replace(array('https://', 'http://', 'www.'), '', site_url()));
                if (strpos($hosting_specific_link, '{host}') !== false && empty($host)) {
                    $url = '';
                } else {
                    $url = str_replace(array('{host}', '{domain}'), array($host, $site), $hosting_specific_link);
                }
            }
        }
        $action = 'continue';
        $status = 'warning';
        $message = rsssl_get_manual_instructions_text($url);
        $output = $url;
        return new RSSSL_RESPONSE($status, $action, $message, $output);
    }
    public function certificate_status()
    {
        delete_transient('rsssl_certinfo');
        if (RSSSL()->rsssl_certificate->is_valid()) {
            $certinfo = get_transient('rsssl_certinfo');
            $end_date = isset($certinfo['validTo_time_t']) ? $certinfo['validTo_time_t'] : false;
            $grace_period = strtotime('+' . rsssl_le_manual_generation_renewal_check . ' days');
            $expiry_date = !empty($end_date) ? date(get_option('date_format'), $end_date) : __("(unknown)", "really-simple-ssl");
            if ($grace_period > $end_date) {
                $action = 'continue';
                $status = 'success';
                $message = sprintf(__("Your certificate will expire on %s.", "really-simple-ssl") . ' ' . __("Continue to renew.", "really-simple-ssl"), $expiry_date);
            } else {
                $action = 'continue';
                $status = 'error';
                $message = __("You already have a valid SSL certificate.", "really-simple-ssl");
            }
        } else {
            $action = 'continue';
            $status = 'success';
            $message = __("SSL certificate should be generated and installed.", "really-simple-ssl");
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    public function certificate_about_to_expire()
    {
        $about_to_expire = RSSSL()->rsssl_certificate->about_to_expire();
        if (!$about_to_expire) {
            delete_option('rsssl_le_start_renewal');
            delete_option('rsssl_le_start_installation');
            return false;
        } else {
            return true;
        }
    }
    public function server_software()
    {
        $action = 'continue';
        $status = 'warning';
        $message = __("The Hosting Panel software was not recognized. Depending on your hosting provider, the generated certificate may need to be installed manually.", "really-simple-ssl");
        if (rsssl_is_cpanel()) {
            $status = 'success';
            $message = __("CPanel recognized. Possibly the certificate can be installed automatically.", "really-simple-ssl");
        } else {
            if (rsssl_is_plesk()) {
                $status = 'success';
                $message = __("Plesk recognized. Possibly the certificate can be installed automatically.", "really-simple-ssl");
            } else {
                if (rsssl_is_directadmin()) {
                    $status = 'success';
                    $message = __("DirectAdmin recognized. Possibly the certificate can be installed automatically.", "really-simple-ssl");
                }
            }
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    public function curl_exists()
    {
        if (function_exists('curl_init') === false) {
            $action = 'stop';
            $status = 'error';
            $message = __("The PHP function CURL is not available on your server, which is required. Please contact your hosting provider.", "really-simple-ssl");
        } else {
            $action = 'continue';
            $status = 'success';
            $message = __("The PHP function CURL has successfully been detected.", "really-simple-ssl");
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    public function get_account()
    {
        $account_email = $this->account_email();
        if (is_email($account_email)) {
            try {
                $this->account = !Account::exists($account_email) ? Account::create($account_email) : Account::get($account_email);
                $status = 'success';
                $action = 'continue';
                $message = __("Successfully retrieved account", "really-simple-ssl");
            } catch (Exception $e) {
                error_log(print_r($e, true));
                $response = $this->get_error($e);
                $status = 'error';
                $action = 'retry';
                if (strpos($response, 'invalid contact domain')) {
                    $action = 'stop';
                    $response = __("The used domain for your email address is not allowed.", "really-simple-ssl") . '&nbsp;' . sprintf(__("Please change your email address %shere%s and try again.", "really-simple-ssl"), '<a href="' . rsssl_letsencrypt_wizard_url() . '&step=2' . '">', '</a>');
                }
                $message = $response;
            }
        } else {
            error_log("no email set");
            $status = 'error';
            $action = 'stop';
            $message = __("The email address was not set. Please set the email address", 'really-simple-ssl');
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    public function get_dns_token()
    {
        if (rsssl_is_ready_for('dns-verification')) {
            $use_dns = rsssl_dns_verification_required();
            $challenge_type = $use_dns ? Order::CHALLENGE_TYPE_DNS : Order::CHALLENGE_TYPE_HTTP;
            if ($use_dns) {
                try {
                    $this->get_account();
                    $dnsWriter = new class extends AbstractDNSWriter
                    {
                        public function write(Order $order, string $identifier, string $digest) : bool
                        {
                            $tokens = get_option('rsssl_le_dns_tokens', array());
                            $tokens[$identifier] = $digest;
                            update_option("rsssl_le_dns_tokens", $tokens);
                            rsssl_progress_add('dns-verification');
                            return false;
                        }
                    };
                    DNS::setWriter($dnsWriter);
                    $response = $this->get_order();
                    $order = $response->output;
                    $response->output = false;
                    if ($order) {
                        try {
                            if ($order->authorize($challenge_type)) {
                                $response = new RSSSL_RESPONSE('success', 'continue', __("Token successfully retrieved.", 'really-simple-ssl'), json_encode(get_option('rsssl_le_dns_tokens')));
                            } else {
                                if (get_option('rsssl_le_dns_tokens')) {
                                    $response = new RSSSL_RESPONSE('success', 'continue', __("Token successfully retrieved.", 'really-simple-ssl'), json_encode(get_option('rsssl_le_dns_tokens')));
                                } else {
                                    $response = new RSSSL_RESPONSE('error', 'retry', __("Token not received yet.", 'really-simple-ssl'));
                                }
                            }
                        } catch (Exception $e) {
                            error_log(print_r($e, true));
                            $error = $this->get_error($e);
                            if (strpos($error, 'Order has status "invalid"') !== false) {
                                $order->clear();
                                $error = __("The order is invalid, possibly due to too many failed authorization attempts. Please start at the previous step.", "really-simple-ssl");
                            } else {
                                if (strpos($error, 'No order for ID ') !== FALSE) {
                                    $error .= '&nbsp;' . __("Order ID mismatch, regenerate order.", "really-simple-ssl");
                                    $order->clear();
                                    rsssl_progress_remove('dns-verification');
                                    $error .= '&nbsp;' . __("If you entered your DNS records before, they need to be changed.", "really-simple-ssl");
                                }
                            }
                            $response = new RSSSL_RESPONSE('error', 'retry', $error);
                        }
                    }
                } catch (Exception $e) {
                    rsssl_progress_remove('dns-verification');
                    $response = $this->get_error($e);
                    error_log(print_r($e, true));
                    $response = new RSSSL_RESPONSE('error', 'retry', $response);
                }
            } else {
                $response = new RSSSL_RESPONSE('error', 'stop', __("Configured for HTTP challenge", 'really-simple-ssl'));
            }
        } else {
            rsssl_progress_remove('dns-verification');
            $response = new RSSSL_RESPONSE('error', 'stop', $this->not_completed_steps_message('dns-verification'));
        }
        return $response;
    }
    public function verify_dns()
    {
        if (rsssl_is_ready_for('generation')) {
            update_option('rsssl_le_dns_records_verified', false);
            $tokens = get_option('rsssl_le_dns_tokens');
            if (!$tokens) {
                $status = 'error';
                $action = 'stop';
                $message = __('Token not generated. Please complete the previous step.', "really-simple-ssl");
                return new RSSSL_RESPONSE($status, $action, $message);
            }
            foreach ($tokens as $identifier => $token) {
                if (strpos($identifier, '*') !== false) {
                    continue;
                }
                set_error_handler(array($this, 'custom_error_handling'));
                $response = dns_get_record("_acme-challenge.{$identifier}", DNS_TXT);
                restore_error_handler();
                if (isset($response[0]['txt'])) {
                    if ($response[0]['txt'] === $token) {
                        $response = new RSSSL_RESPONSE('success', 'continue', sprintf(__('Successfully verified DNS records', "really-simple-ssl"), "_acme-challenge.{$identifier}"));
                        update_option('rsssl_le_dns_records_verified', true);
                    } else {
                        $response = new RSSSL_RESPONSE('error', 'stop', sprintf(__('The DNS response for %s was %s, while it should be %s.', "really-simple-ssl"), "_acme-challenge.{$identifier}", $response[0]['txt'], $token));
                        break;
                    }
                } else {
                    $action = get_option('rsssl_skip_dns_check') ? 'continue' : 'stop';
                    $response = new RSSSL_RESPONSE('warning', $action, sprintf(__('Could not verify TXT record for domain %s', "really-simple-ssl"), "_acme-challenge.{$identifier}"));
                }
            }
        } else {
            $response = new RSSSL_RESPONSE('error', 'stop', $this->not_completed_steps_message('dns-verification'));
        }
        return $response;
    }
    public function clear_order()
    {
        $this->get_account();
        if ($this->account) {
            $response = $this->get_order();
            $order = $response->output;
            if ($order) {
                $order->clear();
            }
        }
    }
    public function create_bundle_or_renew()
    {
        $bundle_completed = false;
        $use_dns = rsssl_dns_verification_required();
        $attempt_count = intval(get_transient('rsssl_le_generate_attempt_count'));
        if ($attempt_count > 5) {
            delete_option("rsssl_le_start_renewal");
            $message = __("The certificate generation was rate limited for 10 minutes because the authorization failed.", 'really-simple-ssl');
            if ($use_dns) {
                $message .= '&nbsp;' . __("Please double check your DNS txt record.", 'really-simple-ssl');
            }
            return new RSSSL_RESPONSE('error', 'stop', $message);
        }
        if (!get_option('rsssl_skip_dns_check')) {
            if ($use_dns && !get_option('rsssl_le_dns_records_verified')) {
                return new RSSSL_RESPONSE('error', 'stop', __("DNS records were not verified yet. Please complete the previous step.", 'really-simple-ssl'));
            }
        }
        if (rsssl_is_ready_for('generation')) {
            $this->get_account();
            if ($use_dns) {
                $dnsWriter = new class extends AbstractDNSWriter
                {
                    public function write(Order $order, string $identifier, string $digest) : bool
                    {
                        $status = false;
                        if (get_option('rsssl_le_dns_tokens')) {
                            $status = true;
                        }
                        return $status;
                    }
                };
                DNS::setWriter($dnsWriter);
            }
            $response = $this->get_order();
            $order = $response->output;
            $response->output = false;
            if ($order) {
                if ($order->isCertificateBundleAvailable()) {
                    try {
                        $order->enableAutoRenewal();
                        $response = new RSSSL_RESPONSE('success', 'continue', __("Certificate already generated. It was renewed if required.", 'really-simple-ssl'));
                        $bundle_completed = true;
                    } catch (Exception $e) {
                        error_log(print_r($e, true));
                        $response = new RSSSL_RESPONSE('error', 'retry', $this->get_error($e));
                        $bundle_completed = false;
                    }
                } else {
                    $finalized = false;
                    $challenge_type = $use_dns ? Order::CHALLENGE_TYPE_DNS : Order::CHALLENGE_TYPE_HTTP;
                    try {
                        if ($order->authorize($challenge_type)) {
                            $order->finalize();
                            $this->reset_attempt();
                            $finalized = true;
                        } else {
                            $this->count_attempt();
                            $response = new RSSSL_RESPONSE('error', 'retry', __('Authorization not completed yet.', "really-simple-ssl"));
                            $bundle_completed = false;
                        }
                    } catch (Exception $e) {
                        $this->count_attempt();
                        $message = $this->get_error($e);
                        error_log(print_r($e, true));
                        $response = new RSSSL_RESPONSE('error', 'stop', $message);
                        if (strpos($message, 'Order has status "invalid"') !== false) {
                            $order->clear();
                            $response->message = __("The order is invalid, possibly due to too many failed authorization attempts. Please start at the previous step.", "really-simple-ssl");
                            if ($use_dns) {
                                rsssl_progress_remove('dns-verification');
                                $response->message .= '&nbsp;' . __("As your order will be regenerated, you'll need to update your DNS text records.", "really-simple-ssl");
                            }
                        } else {
                            if (!get_option('rsssl_disable_ocsp')) {
                                update_option('rsssl_disable_ocsp', true);
                                $response->action = 'retry';
                                $response->status = 'warning';
                                $response->message = __("OCSP not supported, the certificate will be generated without OCSP.", "really-simple-ssl");
                            }
                        }
                    }
                    if ($finalized) {
                        try {
                            if ($order->isCertificateBundleAvailable()) {
                                error_log("cert bundle available");
                                $bundle_completed = true;
                                $success_cert = $success_intermediate = $success_private = false;
                                $bundle = $order->getCertificateBundle();
                                $pathToPrivateKey = $bundle->path . $bundle->private;
                                $pathToCertificate = $bundle->path . $bundle->certificate;
                                $pathToIntermediate = $bundle->path . $bundle->intermediate;
                                if (file_exists($pathToPrivateKey)) {
                                    $success_private = true;
                                    update_option('rsssl_private_key_path', $pathToPrivateKey);
                                }
                                if (file_exists($pathToCertificate)) {
                                    $success_cert = true;
                                    update_option('rsssl_certificate_path', $pathToCertificate);
                                }
                                if (file_exists($pathToIntermediate)) {
                                    $success_intermediate = true;
                                    update_option('rsssl_intermediate_path', $pathToIntermediate);
                                }
                                if (!$success_cert || !$success_private || !$success_intermediate) {
                                    $bundle_completed = false;
                                }
                                if ($bundle_completed) {
                                    $response = new RSSSL_RESPONSE('success', 'continue', __("Successfully generated certificate.", 'really-simple-ssl'));
                                } else {
                                    $response = new RSSSL_RESPONSE('error', 'retry', __("Files not created yet...", 'really-simple-ssl'));
                                }
                            } else {
                                $response = new RSSSL_RESPONSE('error', 'retry', __("Bundle not available yet...", 'really-simple-ssl'));
                            }
                        } catch (Exception $e) {
                            error_log(print_r($e, true));
                            $response = new RSSSL_RESPONSE('error', 'retry', $this->get_error($e));
                        }
                    }
                }
            }
        } else {
            $response = new RSSSL_RESPONSE('error', 'stop', $this->not_completed_steps_message('generation'));
        }
        if ($bundle_completed) {
            rsssl_progress_add('generation');
            update_option('rsssl_le_certificate_generated_by_rsssl', true);
            delete_option("rsssl_le_start_renewal");
        } else {
            rsssl_progress_remove('generation');
        }
        return $response;
    }
    public function get_order()
    {
        if (!Order::exists($this->account, $this->subjects)) {
            try {
                $response = new RSSSL_RESPONSE('success', 'continue', __("Order successfully created.", 'really-simple-ssl'));
                $response->output = Order::create($this->account, $this->subjects);
            } catch (Exception $e) {
                error_log(print_r($e, true));
                $response = new RSSSL_RESPONSE('error', 'retry', $this->get_error($e));
            }
        } else {
            $response = new RSSSL_RESPONSE('success', 'continue', __("Order successfully retrieved.", 'really-simple-ssl'));
            $response->output = Order::get($this->account, $this->subjects);
        }
        return $response;
    }
    public function count_attempt()
    {
        $attempt_count = intval(get_transient('rsssl_le_generate_attempt_count'));
        $attempt_count++;
        set_transient('rsssl_le_generate_attempt_count', $attempt_count, 10 * MINUTE_IN_SECONDS);
    }
    public function reset_attempt()
    {
        delete_transient('rsssl_le_generate_attempt_count');
    }
    public function ssl_generation_can_auto_renew()
    {
        if (get_option('rsssl_verification_type') === 'DNS' && !get_option('rsssl_le_dns_configured_by_rsssl')) {
            return false;
        } else {
            return true;
        }
    }
    public function certificate_automatic_install_possible()
    {
        $install_method = get_option('rsssl_le_certificate_installed_by_rsssl');
        if ($install_method === false) {
            return false;
        } else {
            return true;
        }
    }
    public function should_start_manual_installation_renewal()
    {
        if (!$this->should_start_manual_ssl_generation() && get_option("rsssl_le_start_installation")) {
            return true;
        }
        return false;
    }
    public function should_start_manual_ssl_generation()
    {
        return get_option("rsssl_le_start_renewal");
    }
    public function certificate_renewal_status_notice()
    {
        if (!RSSSL_LE()->letsencrypt_handler->ssl_generation_can_auto_renew()) {
            return 'manual-generation';
        }
        if ($this->certificate_install_required() && $this->certificate_automatic_install_possible() && $this->installation_failed()) {
            return 'automatic-installation-failed';
        }
        if ($this->certificate_install_required() && !$this->certificate_automatic_install_possible()) {
            return 'manual-installation';
        }
        return 'automatic';
    }
    public function certificate_install_required()
    {
        $install_method = get_option('rsssl_le_certificate_installed_by_rsssl');
        $hosting_company = rsssl_get_other_host();
        if (in_array($install_method, RSSSL_LE()->config->no_installation_renewal_needed) || in_array($hosting_company, RSSSL_LE()->config->no_installation_renewal_needed)) {
            return false;
        }
        return true;
    }
    public function cron_certificate_needs_renewal()
    {
        $cert_file = get_option('rsssl_certificate_path');
        if (empty($cert_file)) {
            return false;
        }
        $certificate = file_get_contents($cert_file);
        $certificateInfo = openssl_x509_parse($certificate);
        $valid_to = $certificateInfo['validTo_time_t'];
        $in_expiry_days = strtotime("+" . rsssl_le_cron_generation_renewal_check . " days");
        if ($in_expiry_days > $valid_to) {
            return true;
        } else {
            return false;
        }
    }
    public function account_email()
    {
        return rsssl_get_value('email_address', false);
    }
    public function terms_accepted()
    {
        $accepted = rsssl_get_value('accept_le_terms', false);
        if ($accepted) {
            $status = 'success';
            $action = 'continue';
            $message = __("Terms & Conditions are accepted.", 'really-simple-ssl');
        } else {
            $status = 'error';
            $action = 'stop';
            $message = __("The Terms & Conditions were not accepted. Please accept in the general settings.", 'really-simple-ssl');
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    public function update_account($new_email)
    {
        if (!$this->account) {
            return;
        }
        try {
            $this->account->update($new_email);
        } catch (Exception $e) {
            error_log("Lets encrypt email update failed");
            error_log(print_r($e, true));
        }
    }
    public function get_subjects()
    {
        $subjects = array();
        $domain = rsssl_get_domain();
        $root = str_replace('www.', '', $domain);
        $subjects[] = $domain;
        if (!rsssl_is_subdomain()) {
            if (rsssl_get_value('include_alias')) {
                if (strpos($domain, 'www.') !== false) {
                    $alias_domain = $root;
                } else {
                    $alias_domain = 'www.' . $root;
                }
                $subjects[] = $alias_domain;
            }
        }
        if (rsssl_wildcard_certificate_required()) {
            $domain = rsssl_get_domain();
            $domain = str_replace('www.', '', $domain);
            $subjects = array($domain, '*.' . $domain);
        }
        return apply_filters('rsssl_le_subjects', $subjects);
    }
    public function is_ready_for($item)
    {
        if (!rsssl_do_local_lets_encrypt_generation()) {
            rsssl_progress_add('directories');
            rsssl_progress_add('generation');
            rsssl_progress_add('dns-verification');
        }
        if (!rsssl_dns_verification_required()) {
            rsssl_progress_add('dns-verification');
        }
        if (empty(rsssl_get_not_completed_steps($item))) {
            return true;
        } else {
            return false;
        }
    }
    public function custom_error_handling($errno, $errstr, $errfile, $errline, $errcontext = array())
    {
        return true;
    }
    public function not_completed_steps_message($step)
    {
        $not_completed_steps = rsssl_get_not_completed_steps($step);
        $nice_names = array();
        foreach ($not_completed_steps as $not_completed_step) {
            $index = array_search($not_completed_step, array_column(RSSSL_LE()->config->steps['lets-encrypt'], 'id'));
            $nice_names[] = RSSSL_LE()->config->steps['lets-encrypt'][$index + 1]['title'];
        }
        return sprintf(__('Please complete the following step(s) first: %s', "really-simple-ssl"), implode(", ", $nice_names));
    }
    public function check_writing_permissions()
    {
        $directories_without_permissions = $this->directories_without_writing_permissions();
        $has_missing_permissions = count($directories_without_permissions) > 0;
        if ($has_missing_permissions) {
            rsssl_progress_remove('directories');
            $action = 'stop';
            $status = 'error';
            $message = __("The following directories do not have the necessary writing permissions.", "really-simple-ssl") . "&nbsp;" . __("Set permissions to 644 to enable SSL generation.", "really-simple-ssl");
            foreach ($directories_without_permissions as $directories_without_permission) {
                $message .= "<br> - " . $directories_without_permission;
            }
        } else {
            $action = 'continue';
            $status = 'success';
            $message = __("The required directories have the necessary writing permissions.", "really-simple-ssl");
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    public function check_challenge_directory()
    {
        if (!$this->challenge_directory()) {
            rsssl_progress_remove('directories');
            $action = 'stop';
            $status = 'error';
            $message = __("The challenge directory is not created yet.", "really-simple-ssl");
        } else {
            $action = 'continue';
            $status = 'success';
            $message = __("The challenge directory was successfully created.", "really-simple-ssl");
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    public function check_key_directory()
    {
        $action = 'stop';
        $status = 'error';
        $message = __("The key directory is not created yet.", "really-simple-ssl");
        if (!get_option('rsssl_create_folders_in_root')) {
            $action = 'retry';
            $message = __("Trying to create directory in root of website.", "really-simple-ssl");
        }
        if (!$this->key_directory()) {
            rsssl_progress_remove('directories');
        } else {
            $action = 'continue';
            $status = 'success';
            $message = __("The key directory was successfully created.", "really-simple-ssl");
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    public function check_certs_directory()
    {
        if (!$this->certs_directory()) {
            rsssl_progress_remove('directories');
            $action = 'stop';
            $status = 'error';
            $message = __("The certs directory is not created yet.", "really-simple-ssl");
        } else {
            $action = 'continue';
            $status = 'success';
            $message = __("The certs directory was successfully created.", "really-simple-ssl");
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    public function directories_without_writing_permissions()
    {
        $required_folders = array($this->key_directory, $this->certs_directory);
        if (!rsssl_dns_verification_required()) {
            $required_folders[] = $this->challenge_directory;
        }
        $no_writing_permissions = array();
        foreach ($required_folders as $required_folder) {
            if (!$this->directory_has_writing_permissions($required_folder)) {
                $no_writing_permissions[] = $required_folder;
            }
        }
        return $no_writing_permissions;
    }
    public function directory_has_writing_permissions($directory)
    {
        set_error_handler(array($this, 'custom_error_handling'));
        $test_file = fopen($directory . "/really-simple-ssl-permissions-check.txt", "w");
        if (!$test_file) {
            return false;
        }
        fwrite($test_file, 'file to test writing permissions for Really Simple SSL');
        fclose($test_file);
        restore_error_handler();
        if (!file_exists($directory . "/really-simple-ssl-permissions-check.txt")) {
            return false;
        } else {
            return true;
        }
    }
    public function challenge_directory_reachable()
    {
        $file_content = false;
        $status_code = __('no response', 'really-simple-ssl');
        $url = str_replace('https://', 'http://', site_url('.well-known/acme-challenge/really-simple-ssl-permissions-check.txt'));
        $error_message = sprintf(__("Could not reach challenge directory over %s.", "really-simple-ssl"), '<a target="_blank" href="' . $url . '">' . $url . '</a>');
        $test_string = 'Really Simple SSL';
        $folders = $this->directories_without_writing_permissions();
        if (!$this->challenge_directory() || count($folders) !== 0) {
            $status = 'error';
            $action = 'stop';
            $message = __("Challenge directory not writable.", "really-simple-ssl");
            return new RSSSL_RESPONSE($status, $action, $message);
        }
        $response = wp_remote_get($url);
        if (is_array($response)) {
            $status_code = wp_remote_retrieve_response_code($response);
            $file_content = wp_remote_retrieve_body($response);
        }
        if ($status_code !== 200) {
            if (get_option('rsssl_skip_challenge_directory_request')) {
                $status = 'warning';
                $action = 'continue';
                $message = $error_message . ' ' . sprintf(__("Error code %s.", "really-simple-ssl"), $status_code);
            } else {
                $status = 'error';
                $action = 'stop';
                $message = $error_message . ' ' . sprintf(__("Error code %s.", "really-simple-ssl"), $status_code);
                rsssl_progress_remove('directories');
            }
        } else {
            if (!is_wp_error($response) && strpos($file_content, $test_string) !== false) {
                $status = 'success';
                $action = 'continue';
                $message = __("Successfully verified alias domain.", "really-simple-ssl");
                set_transient('rsssl_alias_domain_available', 'available', 30 * MINUTE_IN_SECONDS);
            } else {
                $status = 'error';
                $action = 'stop';
                $message = $error_message;
                rsssl_progress_remove('directories');
            }
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    public function challenge_directory()
    {
        $root_directory = trailingslashit(ABSPATH);
        if (!file_exists($root_directory . '.well-known')) {
            mkdir($root_directory . '.well-known');
        }
        if (!file_exists($root_directory . '.well-known/acme-challenge')) {
            mkdir($root_directory . '.well-known/acme-challenge');
        }
        if (file_exists($root_directory . '.well-known/acme-challenge')) {
            return $root_directory . '.well-known/acme-challenge';
        } else {
            return false;
        }
    }
    public function certs_directory()
    {
        $directory = $this->get_directory_path();
        if (!file_exists($directory . 'ssl')) {
            mkdir($directory . 'ssl');
        }
        if (!file_exists($directory . 'ssl/certs')) {
            mkdir($directory . 'ssl/certs');
        }
        if (file_exists($directory . 'ssl/certs')) {
            return $directory . 'ssl/certs';
        } else {
            return false;
        }
    }
    public function get_directory_path()
    {
        $root_directory = trailingslashit(ABSPATH);
        if (get_option('rsssl_create_folders_in_root')) {
            if (!get_option('rsssl_ssl_dirname')) {
                $token = str_shuffle(time());
                update_option('rsssl_ssl_dirname', $token);
            }
            if (!file_exists($root_directory . get_option('rsssl_ssl_dirname'))) {
                mkdir($root_directory . get_option('rsssl_ssl_dirname'));
            }
            return $root_directory . trailingslashit(get_option('rsssl_ssl_dirname'));
        } else {
            return trailingslashit(dirname($root_directory));
        }
    }
    public function key_directory()
    {
        $directory = $this->get_directory_path();
        if (!file_exists($directory . 'ssl')) {
            mkdir($directory . 'ssl');
        }
        if (!file_exists($directory . 'ssl/keys')) {
            mkdir($directory . 'ssl/keys');
        }
        if (file_exists($directory . 'ssl/keys')) {
            return $directory . 'ssl/keys';
        } else {
            $challenge_dir = $this->challenge_directory;
            $has_writing_permissions = $this->directory_has_writing_permissions($challenge_dir);
            if (RSSSL()->rsssl_server->uses_htaccess() && $has_writing_permissions) {
                update_option('rsssl_create_folders_in_root', true);
            }
            return false;
        }
    }
    public function clear_keys_directory()
    {
        if (!current_user_can('manage_options')) {
            return;
        }
        $dir = $this->key_directory();
        $this->delete_files_directories_recursively($dir);
    }
    private function delete_files_directories_recursively($dir)
    {
        if (strpos($dir, 'ssl/keys') !== false) {
            foreach (glob($dir . '/*') as $file) {
                if (is_dir($file)) {
                    $this->delete_files_directories_recursively($file);
                } else {
                    unlink($file);
                }
            }
            rmdir($dir);
        }
    }
    public function maybe_create_htaccess_directories()
    {
        if (!current_user_can('manage_options')) {
            return;
        }
        if (!RSSSL()->rsssl_server->uses_htaccess()) {
            return;
        }
        if (!get_option('rsssl_create_folders_in_root')) {
            return;
        }
        if (!empty($this->get_directory_path())) {
            $this->write_htaccess_dir_file($this->get_directory_path() . 'ssl/.htaccess', 'ssl');
        }
        if (!empty($this->key_directory())) {
            $this->write_htaccess_dir_file(trailingslashit($this->key_directory()) . '.htaccess', 'key');
        }
        if (!empty($this->certs_directory())) {
            $this->write_htaccess_dir_file(trailingslashit($this->certs_directory()) . '.htaccess', 'certs');
        }
    }
    public function write_htaccess_dir_file($path, $type)
    {
        $htaccess = '<ifModule mod_authz_core.c>' . "\n" . '    Require all denied' . "\n" . '</ifModule>' . "\n" . '<ifModule !mod_authz_core.c>' . "\n" . '    Deny from all' . "\n" . '</ifModule>';
        insert_with_markers($path, 'Really Simple SSL LETS ENCRYPT', $htaccess);
        $htaccess = file_get_contents($path);
        if (strpos($htaccess, 'deny from all') !== FALSE) {
            update_option('rsssl_htaccess_file_set_' . $type, true);
            return;
        }
    }
    public function is_subdomain_setup()
    {
        if (!is_multisite()) {
            $is_subdomain = false;
        } else {
            if (defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
                $is_subdomain = true;
            } else {
                $is_subdomain = false;
            }
        }
        if ($is_subdomain) {
            $status = 'error';
            $action = 'stop';
            $message = sprintf(__("This is a multisite configuration with subdomains, which requires a wildcard certificate. Wildcard certificates are part of the %spremium%s plan.", 'really-simple-ssl'), '<a href="https://really-simple-ssl.com/pro" target="_blank">', '</a>');
            rsssl_progress_remove('system-status');
        } else {
            $status = 'success';
            $action = 'continue';
            $message = __("No subdomain setup detected.", "really-simple-ssl");
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    public function is_wildcard()
    {
        $subjects = $this->get_subjects();
        $is_wildcard = false;
        foreach ($subjects as $domain) {
            if (strpos($domain, '*') !== false) {
                $is_wildcard = true;
            }
        }
        return $is_wildcard;
    }
    public function alias_domain_available()
    {
        if (rsssl_is_subdomain()) {
            return new RSSSL_RESPONSE('success', 'continue', __("Alias domain check is not relevant for a subdomain", "really-simple-ssl"));
        }
        $uploads = wp_upload_dir();
        $upload_dir = trailingslashit($uploads['basedir']);
        $upload_url = trailingslashit($uploads['baseurl']);
        $file_content = false;
        $status_code = __('no response', 'really-simple-ssl');
        $domain = rsssl_get_domain();
        if (strpos($domain, 'www.') !== false) {
            $is_www = true;
            $alias_domain = str_replace('www.', '', $domain);
        } else {
            $is_www = false;
            $alias_domain = 'www.' . $domain;
        }
        if ($is_www) {
            $message = __("Please check if the non www version of your site also points to this website.", "really-simple-ssl");
        } else {
            $message = __("Please check if the www version of your site also points to this website.", "really-simple-ssl");
        }
        $error_message = __("Could not verify alias domain.", "really-simple-ssl") . ' ' . $message . ' ' . __("If this is not the case, don't add this alias to your certificate.", "really-simple-ssl");
        $cached_status = get_transient('rsssl_alias_domain_available');
        if ($cached_status) {
            if ($cached_status === 'available') {
                $status = 'success';
                $action = 'continue';
                $message = __("Successfully verified alias domain.", "really-simple-ssl");
            } else {
                $status = 'warning';
                $action = 'continue';
                $message = $error_message;
            }
            return new RSSSL_RESPONSE($status, $action, $message);
        }
        if (!file_exists($upload_dir . 'rsssl')) {
            mkdir($upload_dir . 'rsssl');
        }
        $test_string = 'file to test alias domain existence';
        $test_file = $upload_dir . 'rsssl/test.txt';
        file_put_contents($test_file, $test_string);
        $test_url = $upload_url . 'rsssl/test.txt';
        if (!file_exists($test_file)) {
            $status = 'error';
            $action = 'stop';
            $message = __("Could not create test folder and file.", "really-simple-ssl") . ' ' . __("Please create a folder 'rsssl' in the uploads directory, with 644 permissions.", "really-simple-ssl");
        } else {
            set_transient('rsssl_alias_domain_available', 'not-available', 30 * MINUTE_IN_SECONDS);
            $alias_test_url = str_replace($domain, $alias_domain, $test_url);
            $alias_test_url = str_replace('https://', 'http://', $alias_test_url);
            $response = wp_remote_get($alias_test_url);
            if (is_array($response)) {
                $status_code = wp_remote_retrieve_response_code($response);
                $file_content = wp_remote_retrieve_body($response);
            }
            if ($status_code !== 200) {
                $status = 'warning';
                $action = 'continue';
                $message = $error_message;
                if (intval($status_code) != 0) {
                    $message .= ' ' . sprintf(__("Error code %s", "really-simple-ssl"), $status_code);
                }
            } else {
                if (!is_wp_error($response) && strpos($file_content, $test_string) !== false) {
                    if (!get_option('rsssl_initial_alias_domain_value_set')) {
                        RSSSL_LE()->field->save_field('rsssl_include_alias', true);
                        update_option('rsssl_initial_alias_domain_value_set', true);
                    }
                    $status = 'success';
                    $action = 'continue';
                    $message = __("Successfully verified alias domain.", "really-simple-ssl");
                    set_transient('rsssl_alias_domain_available', 'available', 30 * MINUTE_IN_SECONDS);
                } else {
                    $status = 'warning';
                    $action = 'continue';
                    $message = $error_message;
                }
            }
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    private function get_error($e)
    {
        $is_raw_response = false;
        if (method_exists($e, 'getRawResponse') && isset($e->getRawResponse()->body['detail'])) {
            $is_raw_response = true;
            $error = $e->getRawResponse()->body['detail'];
            error_log($error);
            if (isset($e->getRawResponse()->body['subproblems'])) {
                $error .= '<ul>';
                foreach ($e->getRawResponse()->body['subproblems'] as $index => $problem) {
                    $error .= '<li>' . $this->cleanup_error_message($e->getRawResponse()->body['subproblems'][$index]['detail']) . '</li>';
                }
                $error .= '</ul>';
            }
        } else {
            $error = $e->getMessage();
        }
        $max = strpos($error, 'CURL response');
        if ($max === false) {
            $max = 200;
        }
        if (!$is_raw_response) {
            $error = substr($error, 0, $max);
        }
        return $error;
    }
    public function cron_renew_installation()
    {
        $install_method = get_option('rsssl_le_certificate_installed_by_rsssl');
        $data = explode(':', $install_method);
        $server = isset($data[0]) ? $data[0] : false;
        $type = isset($data[1]) ? $data[1] : false;
        $attempt_count = intval(get_transient('rsssl_le_install_attempt_count'));
        $attempt_count++;
        set_transient('rsssl_le_install_attempt_count', $attempt_count, DAY_IN_SECONDS);
        if ($attempt_count > 10) {
            delete_option("rsssl_le_start_installation");
            $status = 'error';
            $action = 'stop';
            $message = __("The certificate installation was rate limited. Please try again later.", 'really-simple-ssl');
            return new RSSSL_RESPONSE($status, $action, $message);
        }
        if (rsssl_is_ready_for('installation')) {
            try {
                if ($server === 'cpanel') {
                    if ($type === 'default') {
                        $response = rsssl_install_cpanel_default();
                    } else {
                        if (function_exists('rsssl_install_cpanel_shell')) {
                            $response = rsssl_install_cpanel_shell();
                        }
                    }
                    if ($response->status === 'success') {
                        delete_option("rsssl_le_start_installation");
                    }
                    return $response;
                } else {
                    if ($server === 'plesk') {
                        $response = rsssl_plesk_install();
                        if ($response->status === 'success') {
                            delete_option("rsssl_le_start_installation");
                        }
                        return $response;
                    } else {
                        $status = 'error';
                        $action = 'stop';
                        $message = __("Not recognized server.", "really-simple-ssl");
                    }
                }
            } catch (Exception $e) {
                error_log(print_r($e, true));
                $status = 'error';
                $action = 'stop';
                $message = __("Installation failed.", "really-simple-ssl");
            }
        } else {
            $status = 'error';
            $action = 'stop';
            $message = __("The system is not ready for the installation yet. Please run the wizard again.", "really-simple-ssl");
        }
        return new RSSSL_RESPONSE($status, $action, $message);
    }
    private function cleanup_error_message($msg)
    {
        return str_replace(array('Refer to sub-problems for more information.', 'Error creating new order ::'), '', $msg);
    }
    public function encode($string)
    {
        if (strlen(trim($string)) === 0) {
            return $string;
        }
        if (strpos($string, 'rsssl_') !== FALSE) {
            return $string;
        }
        $key = $this->get_key();
        if (!$key) {
            $key = $this->set_key();
        }
        $ivlength = openssl_cipher_iv_length('aes-256-cbc');
        $iv = openssl_random_pseudo_bytes($ivlength);
        $ciphertext_raw = openssl_encrypt($string, 'aes-256-cbc', $key, 0, $iv);
        $key = base64_encode($iv . $ciphertext_raw);
        return 'rsssl_' . $key;
    }
    public function decode($string)
    {
        if (!wp_doing_cron() && !current_user_can('manage_options')) {
            return '';
        }
        if (strpos($string, 'rsssl_') !== FALSE) {
            $key = $this->get_key();
            $string = str_replace('rsssl_', '', $string);
            $ivlength = openssl_cipher_iv_length('aes-256-cbc');
            $iv = substr(base64_decode($string), 0, $ivlength);
            $encrypted_data = substr(base64_decode($string), $ivlength);
            $decrypted = openssl_decrypt($encrypted_data, 'aes-256-cbc', $key, 0, $iv);
            return $decrypted;
        }
        return $string;
    }
    private function set_key()
    {
        update_site_option('rsssl_key', time());
        return get_site_option('rsssl_key');
    }
    private function get_key()
    {
        return get_site_option('rsssl_key');
    }
}