ru-se.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

class-wp-recovery-mode-key-service.php (4270B)


      1 <?php
      2 /**
      3  * Error Protection API: WP_Recovery_Mode_Key_Service class
      4  *
      5  * @package WordPress
      6  * @since 5.2.0
      7  */
      8 
      9 /**
     10  * Core class used to generate and validate keys used to enter Recovery Mode.
     11  *
     12  * @since 5.2.0
     13  */
     14 final class WP_Recovery_Mode_Key_Service {
     15 
     16 	/**
     17 	 * The option name used to store the keys.
     18 	 *
     19 	 * @since 5.2.0
     20 	 * @var string
     21 	 */
     22 	private $option_name = 'recovery_keys';
     23 
     24 	/**
     25 	 * Creates a recovery mode token.
     26 	 *
     27 	 * @since 5.2.0
     28 	 *
     29 	 * @return string A random string to identify its associated key in storage.
     30 	 */
     31 	public function generate_recovery_mode_token() {
     32 		return wp_generate_password( 22, false );
     33 	}
     34 
     35 	/**
     36 	 * Creates a recovery mode key.
     37 	 *
     38 	 * @since 5.2.0
     39 	 *
     40 	 * @global PasswordHash $wp_hasher
     41 	 *
     42 	 * @param string $token A token generated by {@see generate_recovery_mode_token()}.
     43 	 * @return string Recovery mode key.
     44 	 */
     45 	public function generate_and_store_recovery_mode_key( $token ) {
     46 
     47 		global $wp_hasher;
     48 
     49 		$key = wp_generate_password( 22, false );
     50 
     51 		if ( empty( $wp_hasher ) ) {
     52 			require_once ABSPATH . WPINC . '/class-phpass.php';
     53 			$wp_hasher = new PasswordHash( 8, true );
     54 		}
     55 
     56 		$hashed = $wp_hasher->HashPassword( $key );
     57 
     58 		$records = $this->get_keys();
     59 
     60 		$records[ $token ] = array(
     61 			'hashed_key' => $hashed,
     62 			'created_at' => time(),
     63 		);
     64 
     65 		$this->update_keys( $records );
     66 
     67 		/**
     68 		 * Fires when a recovery mode key is generated.
     69 		 *
     70 		 * @since 5.2.0
     71 		 *
     72 		 * @param string $token The recovery data token.
     73 		 * @param string $key   The recovery mode key.
     74 		 */
     75 		do_action( 'generate_recovery_mode_key', $token, $key );
     76 
     77 		return $key;
     78 	}
     79 
     80 	/**
     81 	 * Verifies if the recovery mode key is correct.
     82 	 *
     83 	 * Recovery mode keys can only be used once; the key will be consumed in the process.
     84 	 *
     85 	 * @since 5.2.0
     86 	 *
     87 	 * @param string $token The token used when generating the given key.
     88 	 * @param string $key   The unhashed key.
     89 	 * @param int    $ttl   Time in seconds for the key to be valid for.
     90 	 * @return true|WP_Error True on success, error object on failure.
     91 	 */
     92 	public function validate_recovery_mode_key( $token, $key, $ttl ) {
     93 
     94 		$records = $this->get_keys();
     95 
     96 		if ( ! isset( $records[ $token ] ) ) {
     97 			return new WP_Error( 'token_not_found', __( 'Recovery Mode not initialized.' ) );
     98 		}
     99 
    100 		$record = $records[ $token ];
    101 
    102 		$this->remove_key( $token );
    103 
    104 		if ( ! is_array( $record ) || ! isset( $record['hashed_key'], $record['created_at'] ) ) {
    105 			return new WP_Error( 'invalid_recovery_key_format', __( 'Invalid recovery key format.' ) );
    106 		}
    107 
    108 		if ( ! wp_check_password( $key, $record['hashed_key'] ) ) {
    109 			return new WP_Error( 'hash_mismatch', __( 'Invalid recovery key.' ) );
    110 		}
    111 
    112 		if ( time() > $record['created_at'] + $ttl ) {
    113 			return new WP_Error( 'key_expired', __( 'Recovery key expired.' ) );
    114 		}
    115 
    116 		return true;
    117 	}
    118 
    119 	/**
    120 	 * Removes expired recovery mode keys.
    121 	 *
    122 	 * @since 5.2.0
    123 	 *
    124 	 * @param int $ttl Time in seconds for the keys to be valid for.
    125 	 */
    126 	public function clean_expired_keys( $ttl ) {
    127 
    128 		$records = $this->get_keys();
    129 
    130 		foreach ( $records as $key => $record ) {
    131 			if ( ! isset( $record['created_at'] ) || time() > $record['created_at'] + $ttl ) {
    132 				unset( $records[ $key ] );
    133 			}
    134 		}
    135 
    136 		$this->update_keys( $records );
    137 	}
    138 
    139 	/**
    140 	 * Removes a used recovery key.
    141 	 *
    142 	 * @since 5.2.0
    143 	 *
    144 	 * @param string $token The token used when generating a recovery mode key.
    145 	 */
    146 	private function remove_key( $token ) {
    147 
    148 		$records = $this->get_keys();
    149 
    150 		if ( ! isset( $records[ $token ] ) ) {
    151 			return;
    152 		}
    153 
    154 		unset( $records[ $token ] );
    155 
    156 		$this->update_keys( $records );
    157 	}
    158 
    159 	/**
    160 	 * Gets the recovery key records.
    161 	 *
    162 	 * @since 5.2.0
    163 	 *
    164 	 * @return array Associative array of $token => $data pairs, where $data has keys 'hashed_key'
    165 	 *               and 'created_at'.
    166 	 */
    167 	private function get_keys() {
    168 		return (array) get_option( $this->option_name, array() );
    169 	}
    170 
    171 	/**
    172 	 * Updates the recovery key records.
    173 	 *
    174 	 * @since 5.2.0
    175 	 *
    176 	 * @param array $keys Associative array of $token => $data pairs, where $data has keys 'hashed_key'
    177 	 *                    and 'created_at'.
    178 	 * @return bool True on success, false on failure.
    179 	 */
    180 	private function update_keys( array $keys ) {
    181 		return update_option( $this->option_name, $keys );
    182 	}
    183 }