Example #1
0
        /**
         * Renders the settings page.
         *
         * The settings page contains all UI for the plugin. The user can specify the settings for
         * his or her organization, then register the account with Let's Encrypt and then generate
         * a certificate.
         *
         * The settings page furthermore provides some additional settings to specify how the plugin
         * should behave.
         *
         * @since 1.0.0
         * @access public
         */
        public function render_page()
        {
            if (CoreUtil::needs_filesystem_credentials()) {
                ?>
				<div class="notice notice-warning">
					<p><?php 
                printf(__('The directories %1$s and %2$s that WP Encrypt needs access to are not automatically writable by the site. Unless you change this, it is not possible to auto-renew certificates.', 'wp-encrypt'), '<code>' . CoreUtil::get_letsencrypt_certificates_dir_path() . '</code>', '<code>' . CoreUtil::get_letsencrypt_challenges_dir_path() . '</code>');
                ?>
</p>
					<p><?php 
                _e('Note that you can still manually renew certificates by providing valid filesystem credentials each time.', 'wp-encrypt');
                ?>
</p>
				</div>
				<?php 
            }
            $account_registration_info = Util::get_registration_info('account');
            $certificate_registration_info = Util::get_registration_info('certificate');
            $account_registration_timestamp = false;
            $certificate_generation_timestamp = false;
            $site_domains = array();
            if (isset($account_registration_info['createdAt'])) {
                $account_registration_timestamp = strtotime($account_registration_info['createdAt']) + HOUR_IN_SECONDS * get_option('gmt_offset');
            } elseif (isset($account_registration_info['_wp_time'])) {
                $account_registration_timestamp = strtotime($account_registration_info['_wp_time']);
            }
            if (isset($certificate_registration_info['_wp_time'])) {
                $certificate_generation_timestamp = strtotime($certificate_registration_info['_wp_time']);
                if (isset($certificate_registration_info['domains'])) {
                    $site_domains = $certificate_registration_info['domains'];
                }
            }
            $has_certificate = 0 < count($site_domains);
            $form_action = App::get_admin_action_file($this->context);
            $primary = 'save';
            if (Util::get_option('valid')) {
                $primary = 'register';
                if (Util::can_generate_certificate()) {
                    $primary = 'generate';
                }
            }
            ?>
			<style type="text/css">
				.wp-encrypt-form {
					margin-bottom: 40px;
				}

				.remove,
				.reset {
					color: #aa0000;
					text-decoration: none;
				}

				.remove:hover,
				.reset:hover {
					color: #ff0000;
					text-decoration: none;
					border: none;
				}

				.remove {
					margin-left: 6px;
					line-height: 28px;
				}

				.danger-headline {
					color: #aa0000;
				}
			</style>
			<div class="wrap">
				<h1><?php 
            _e('WP Encrypt', 'wp-encrypt');
            ?>
</h1>

				<form class="wp-encrypt-form" method="post" action="<?php 
            echo $form_action;
            ?>
">
					<?php 
            settings_fields('wp_encrypt_settings');
            ?>
					<?php 
            do_settings_sections(self::PAGE_SLUG);
            ?>
					<?php 
            submit_button('', ('save' === $primary ? 'primary' : 'secondary') . ' large', 'submit', false);
            ?>
				</form>

				<?php 
            if (Util::get_option('valid')) {
                ?>
					<h2><?php 
                _e('Let&rsquo;s Encrypt Account', 'wp-encrypt');
                ?>
</h2>

					<form class="wp-encrypt-form" method="post" action="<?php 
                echo $form_action;
                ?>
">
						<p class="description">
							<?php 
                _e('By clicking on this button, you will register an account for the above organization with Let&rsquo;s Encrypt.', 'wp-encrypt');
                ?>
							<?php 
                printf(__('By registering, you verify that you have read and accepted the <a href="%s" target="_blank">Let&rsquo;s Encrypt Subscriber Agreement</a>.', 'wp-encrypt'), Client::get()->get_license_url());
                ?>
							<?php 
                if ($account_registration_timestamp) {
                    ?>
								<br />
								<?php 
                    printf(__('Your account was registered on %1$s at %2$s.', 'wp-encrypt'), date_i18n(get_option('date_format'), $account_registration_timestamp), date_i18n(get_option('time_format'), $account_registration_timestamp));
                    ?>
							<?php 
                }
                ?>
						</p>
						<?php 
                $this->action_post_fields('wpenc_register_account');
                ?>
						<?php 
                submit_button(__('Register Account', 'wp-encrypt'), 'register' === $primary ? 'primary' : 'secondary', 'submit', false, array('id' => 'register-account-button'));
                ?>
					</form>

					<?php 
                if (Util::can_generate_certificate()) {
                    ?>
						<h2><?php 
                    _e('Let&rsquo;s Encrypt Certificate', 'wp-encrypt');
                    ?>
</h2>

						<form class="wp-encrypt-form" method="post" action="<?php 
                    echo $form_action;
                    ?>
">
							<p class="description">
								<?php 
                    _e('Here you can manage the actual certificate.', 'wp-encrypt');
                    ?>
								<?php 
                    if ('network' === $this->context) {
                        ?>
									<?php 
                        _e('The certificate will be valid for all the sites in your network by default.', 'wp-encrypt');
                        ?>
								<?php 
                    }
                    ?>
								<?php 
                    if ($certificate_generation_timestamp) {
                        ?>
									<br />
									<?php 
                        if ('network' === $this->context && 0 < count($site_domains)) {
                            ?>
										<?php 
                            printf(__('Your certificate was last generated on %1$s at %2$s for the following domains: %3$s', 'wp-encrypt'), date_i18n(get_option('date_format'), $certificate_generation_timestamp), date_i18n(get_option('time_format'), $certificate_generation_timestamp), implode(', ', $site_domains));
                            ?>
									<?php 
                        } else {
                            ?>
										<?php 
                            printf(__('Your certificate was last generated on %1$s at %2$s.', 'wp-encrypt'), date_i18n(get_option('date_format'), $certificate_generation_timestamp), date_i18n(get_option('time_format'), $certificate_generation_timestamp));
                            ?>
									<?php 
                        }
                        ?>
								<?php 
                    }
                    ?>
							</p>
							<?php 
                    $this->action_post_fields('wpenc_generate_certificate');
                    ?>
							<?php 
                    submit_button(__('Generate Certificate', 'wp-encrypt'), 'generate' === $primary ? 'primary' : 'secondary', 'submit', false, array('id' => 'generate-certificate-button'));
                    ?>
							<?php 
                    if ($has_certificate) {
                        ?>
								<a id="revoke-certificate-button" class="remove" href="<?php 
                        echo App::get_admin_action_url($this->context, 'wpenc_revoke_certificate');
                        ?>
"><?php 
                        _e('Revoke Certificate', 'wp-encrypt');
                        ?>
</a>
							<?php 
                    }
                    ?>
						</form>

						<?php 
                    if ($has_certificate) {
                        ?>
							<?php 
                        $site_domain = 'network' === $this->context ? Util::get_network_domain() : Util::get_site_domain();
                        $certificate_dirs = $this->get_certificate_dirs($site_domain);
                        ?>
							<h3><?php 
                        _e('Certificate & Key Locations', 'wp-encrypt');
                        ?>
</h4>
							<ul>
								<li><?php 
                        printf(__('Certificate: %s', 'wp-encrypt'), '<code>' . $certificate_dirs['cert'] . '</code>');
                        ?>
</li>
								<li><?php 
                        printf(__('Certificate Chain: %s', 'wp-encrypt'), '<code>' . $certificate_dirs['chain'] . '</code>');
                        ?>
</li>
								<li><?php 
                        printf(__('Certificate Full Chain: %s', 'wp-encrypt'), '<code>' . $certificate_dirs['fullchain'] . '</code>');
                        ?>
</li>
								<li><?php 
                        printf(__('Private Key: %s', 'wp-encrypt'), '<code>' . $certificate_dirs['key'] . '</code>');
                        ?>
</li>
							</ul>
							<p><?php 
                        _e('Please check the Help tabs at the top of this page to learn how to set up the SSL certificate.', 'wp-encrypt');
                        ?>
</p>
						<?php 
                    }
                    ?>
					<?php 
                }
                ?>
				<?php 
            }
            ?>

				<?php 
            if (defined('WP_ENCRYPT_ENABLE_DANGER_ZONE') && WP_ENCRYPT_ENABLE_DANGER_ZONE && ($account_registration_timestamp || $certificate_generation_timestamp)) {
                ?>
					<h2 class="danger-headline"><?php 
                _e('Danger Zone', 'wp-encrypt');
                ?>
</h2>
					<p>
						<?php 
                _e('By clicking the button below, you will remove all existing certificate and key files permanently. Use this with extreme caution.', 'wp-encrypt');
                ?>
<br />
						<strong><?php 
                _e('Do not hit this button while your server is using any of those files.', 'wp-encrypt');
                ?>
</strong>
					</p>
					<a id="reset-button" class="reset" href="<?php 
                echo App::get_admin_action_url($this->context, 'wpenc_reset');
                ?>
"><?php 
                _e('Reset', 'wp-encrypt');
                ?>
</a>
				<?php 
            }
            ?>
			</div>
			<?php 
            // for AJAX
            /*if ( CoreUtil::needs_filesystem_credentials() ) {
            			wp_print_request_filesystem_credentials_modal();
            		}*/
        }
 /**
  * Deletes all certificates, keys and challenges.
  *
  * Use this method with extreme caution - do not use it when your server is currently using any of
  * those files.
  *
  * @since 1.0.0
  * @access public
  *
  * @return bool|WP_Error True if everything was deleted successfully, an error object otherwise.
  */
 public function reset()
 {
     $filesystem = Util::get_filesystem();
     $paths = array(Util::get_letsencrypt_certificates_dir_path(), Util::get_letsencrypt_challenges_dir_path());
     foreach ($paths as $path) {
         if ($filesystem->is_dir($path)) {
             $filelist = $filesystem->dirlist(trailingslashit($path), true);
             if (is_array($filelist)) {
                 foreach ($filelist as $fileinfo) {
                     if (!$filesystem->delete(trailingslashit($path) . $fileinfo['name'], true, $fileinfo['type'])) {
                         return new WP_Error('cannot_delete_directory', sprintf(__('Unable to delete <code>%s</code>.', 'wp-encrypt'), trailingslashit($path) . $fileinfo['name']));
                     }
                 }
             }
         }
     }
     return true;
 }
Example #3
0
 /**
  * Validates a domain with Let's Encrypt through a HTTP challenge.
  *
  * @since 1.0.0
  * @access public
  * @static
  *
  * @param string $domain              The domain to validate.
  * @param array  $account_key_details The account private key details.
  * @return bool|WP_Error True if the domain was successfully validated, an error object otherwise.
  */
 public static function validate($domain, $account_key_details)
 {
     $filesystem = Util::get_filesystem();
     $status = Util::maybe_create_letsencrypt_challenges_dir();
     if (is_wp_error($status)) {
         return $status;
     }
     $client = Client::get();
     $response = $client->auth($domain);
     if (is_wp_error($response)) {
         return $response;
     }
     $challenge = array_reduce($response['challenges'], function ($v, $w) {
         if ($v) {
             return $v;
         }
         if ('http-01' === $w['type']) {
             return $w;
         }
         return false;
     });
     if (!$challenge) {
         return new WP_Error('no_challenge_available', sprintf(__('No HTTP challenge available for domain %1$s. Original response: %2$s', 'wp-encrypt'), $domain, json_encode($response)));
     }
     $location = $client->get_last_location();
     $directory = Util::get_letsencrypt_challenges_dir_path();
     $token_path = $directory . '/' . $challenge['token'];
     if (!$filesystem->is_dir($directory) && !$filesystem->mkdir($directory, 0755, true)) {
         return new WP_Error('challenge_cannot_create_dir', sprintf(__('Could not create challenge directory <code>%s</code>. Please check your filesystem permissions.', 'wp-encrypt'), $directory));
     }
     $header = array('e' => Util::base64_url_encode($account_key_details['rsa']['e']), 'kty' => 'RSA', 'n' => Util::base64_url_encode($account_key_details['rsa']['n']));
     $data = $challenge['token'] . '.' . Util::base64_url_encode(hash('sha256', json_encode($header), true));
     if (false === $filesystem->put_contents($token_path, $data)) {
         return new WP_Error('challenge_cannot_write_file', sprintf(__('Could not write challenge to file <code>%s</code>. Please check your filesystem permissions.', 'wp-encrypt'), $token_path));
     }
     $filesystem->chmod($token_path, 0644);
     $response = wp_remote_get(Util::get_letsencrypt_challenges_dir_url() . '/' . $challenge['token']);
     if (is_wp_error($response)) {
         $filesystem->delete($token_path);
         return new WP_Error('challenge_request_failed', sprintf(__('Challenge request failed for domain %s.', 'wp-encrypt'), $domain));
     }
     if ($data !== trim(wp_remote_retrieve_body($response))) {
         $filesystem->delete($token_path);
         return new WP_Error('challenge_self_check_failed', sprintf(__('Challenge self check failed for domain %s.', 'wp-encrypt'), $domain));
     }
     $result = $client->challenge($challenge['uri'], $challenge['token'], $data);
     $done = false;
     do {
         if (empty($result['status']) || 'invalid' === $result['status']) {
             $filesystem->delete($token_path);
             return new WP_Error('challenge_remote_check_failed', sprintf(__('Challenge remote check failed for domain %s.', 'wp-encrypt'), $domain));
         }
         $done = 'pending' !== $result['status'];
         if (!$done) {
             sleep(1);
         }
         $result = $client->request($location, 'GET');
         if ('invalid' === $result['status']) {
             $filesystem->delete($token_path);
             return new WP_Error('challenge_remote_check_failed', sprintf(__('Challenge remote check failed for domain %s.', 'wp-encrypt'), $domain));
         }
     } while (!$done);
     $filesystem->delete($token_path);
     return true;
 }