wp/wp-includes/class-wp-recovery-mode-key-service.php
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
equal deleted inserted replaced
21:48c4eec2b7e6 22:8c2e4d02f4ef
    35 
    35 
    36 	/**
    36 	/**
    37 	 * Creates a recovery mode key.
    37 	 * Creates a recovery mode key.
    38 	 *
    38 	 *
    39 	 * @since 5.2.0
    39 	 * @since 5.2.0
    40 	 *
    40 	 * @since 6.8.0 The stored key is now hashed using wp_fast_hash() instead of phpass.
    41 	 * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
       
    42 	 *
    41 	 *
    43 	 * @param string $token A token generated by {@see generate_recovery_mode_token()}.
    42 	 * @param string $token A token generated by {@see generate_recovery_mode_token()}.
    44 	 * @return string Recovery mode key.
    43 	 * @return string Recovery mode key.
    45 	 */
    44 	 */
    46 	public function generate_and_store_recovery_mode_key( $token ) {
    45 	public function generate_and_store_recovery_mode_key( $token ) {
    47 
       
    48 		global $wp_hasher;
       
    49 
       
    50 		$key = wp_generate_password( 22, false );
    46 		$key = wp_generate_password( 22, false );
    51 
       
    52 		if ( empty( $wp_hasher ) ) {
       
    53 			require_once ABSPATH . WPINC . '/class-phpass.php';
       
    54 			$wp_hasher = new PasswordHash( 8, true );
       
    55 		}
       
    56 
       
    57 		$hashed = $wp_hasher->HashPassword( $key );
       
    58 
    47 
    59 		$records = $this->get_keys();
    48 		$records = $this->get_keys();
    60 
    49 
    61 		$records[ $token ] = array(
    50 		$records[ $token ] = array(
    62 			'hashed_key' => $hashed,
    51 			'hashed_key' => wp_fast_hash( $key ),
    63 			'created_at' => time(),
    52 			'created_at' => time(),
    64 		);
    53 		);
    65 
    54 
    66 		$this->update_keys( $records );
    55 		$this->update_keys( $records );
    67 
    56 
    83 	 *
    72 	 *
    84 	 * Recovery mode keys can only be used once; the key will be consumed in the process.
    73 	 * Recovery mode keys can only be used once; the key will be consumed in the process.
    85 	 *
    74 	 *
    86 	 * @since 5.2.0
    75 	 * @since 5.2.0
    87 	 *
    76 	 *
    88 	 * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
       
    89 	 *
       
    90 	 * @param string $token The token used when generating the given key.
    77 	 * @param string $token The token used when generating the given key.
    91 	 * @param string $key   The unhashed key.
    78 	 * @param string $key   The plain text key.
    92 	 * @param int    $ttl   Time in seconds for the key to be valid for.
    79 	 * @param int    $ttl   Time in seconds for the key to be valid for.
    93 	 * @return true|WP_Error True on success, error object on failure.
    80 	 * @return true|WP_Error True on success, error object on failure.
    94 	 */
    81 	 */
    95 	public function validate_recovery_mode_key( $token, $key, $ttl ) {
    82 	public function validate_recovery_mode_key( $token, $key, $ttl ) {
    96 		global $wp_hasher;
       
    97 
       
    98 		$records = $this->get_keys();
    83 		$records = $this->get_keys();
    99 
    84 
   100 		if ( ! isset( $records[ $token ] ) ) {
    85 		if ( ! isset( $records[ $token ] ) ) {
   101 			return new WP_Error( 'token_not_found', __( 'Recovery Mode not initialized.' ) );
    86 			return new WP_Error( 'token_not_found', __( 'Recovery Mode not initialized.' ) );
   102 		}
    87 		}
   107 
    92 
   108 		if ( ! is_array( $record ) || ! isset( $record['hashed_key'], $record['created_at'] ) ) {
    93 		if ( ! is_array( $record ) || ! isset( $record['hashed_key'], $record['created_at'] ) ) {
   109 			return new WP_Error( 'invalid_recovery_key_format', __( 'Invalid recovery key format.' ) );
    94 			return new WP_Error( 'invalid_recovery_key_format', __( 'Invalid recovery key format.' ) );
   110 		}
    95 		}
   111 
    96 
   112 		if ( empty( $wp_hasher ) ) {
    97 		if ( ! wp_verify_fast_hash( $key, $record['hashed_key'] ) ) {
   113 			require_once ABSPATH . WPINC . '/class-phpass.php';
       
   114 			$wp_hasher = new PasswordHash( 8, true );
       
   115 		}
       
   116 
       
   117 		if ( ! $wp_hasher->CheckPassword( $key, $record['hashed_key'] ) ) {
       
   118 			return new WP_Error( 'hash_mismatch', __( 'Invalid recovery key.' ) );
    98 			return new WP_Error( 'hash_mismatch', __( 'Invalid recovery key.' ) );
   119 		}
    99 		}
   120 
   100 
   121 		if ( time() > $record['created_at'] + $ttl ) {
   101 		if ( time() > $record['created_at'] + $ttl ) {
   122 			return new WP_Error( 'key_expired', __( 'Recovery key expired.' ) );
   102 			return new WP_Error( 'key_expired', __( 'Recovery key expired.' ) );
   167 
   147 
   168 	/**
   148 	/**
   169 	 * Gets the recovery key records.
   149 	 * Gets the recovery key records.
   170 	 *
   150 	 *
   171 	 * @since 5.2.0
   151 	 * @since 5.2.0
       
   152 	 * @since 6.8.0 Each key is now hashed using wp_fast_hash() instead of phpass.
       
   153 	 *              Existing keys may still be hashed using phpass.
   172 	 *
   154 	 *
   173 	 * @return array Associative array of $token => $data pairs, where $data has keys 'hashed_key'
   155 	 * @return array {
   174 	 *               and 'created_at'.
   156 	 *     Associative array of token => data pairs, where the data is an associative
       
   157 	 *     array of information about the key.
       
   158 	 *
       
   159 	 *     @type array ...$0 {
       
   160 	 *         Information about the key.
       
   161 	 *
       
   162 	 *         @type string $hashed_key The hashed value of the key.
       
   163 	 *         @type int    $created_at The timestamp when the key was created.
       
   164 	 *     }
       
   165 	 * }
   175 	 */
   166 	 */
   176 	private function get_keys() {
   167 	private function get_keys() {
   177 		return (array) get_option( $this->option_name, array() );
   168 		return (array) get_option( $this->option_name, array() );
   178 	}
   169 	}
   179 
   170 
   180 	/**
   171 	/**
   181 	 * Updates the recovery key records.
   172 	 * Updates the recovery key records.
   182 	 *
   173 	 *
   183 	 * @since 5.2.0
   174 	 * @since 5.2.0
       
   175 	 * @since 6.8.0 Each key should now be hashed using wp_fast_hash() instead of phpass.
   184 	 *
   176 	 *
   185 	 * @param array $keys Associative array of $token => $data pairs, where $data has keys 'hashed_key'
   177 	 * @param array $keys {
   186 	 *                    and 'created_at'.
   178 	 *     Associative array of token => data pairs, where the data is an associative
       
   179 	 *     array of information about the key.
       
   180 	 *
       
   181 	 *     @type array ...$0 {
       
   182 	 *         Information about the key.
       
   183 	 *
       
   184 	 *         @type string $hashed_key The hashed value of the key.
       
   185 	 *         @type int    $created_at The timestamp when the key was created.
       
   186 	 *     }
       
   187 	 * }
   187 	 * @return bool True on success, false on failure.
   188 	 * @return bool True on success, false on failure.
   188 	 */
   189 	 */
   189 	private function update_keys( array $keys ) {
   190 	private function update_keys( array $keys ) {
   190 		return update_option( $this->option_name, $keys );
   191 		return update_option( $this->option_name, $keys, false );
   191 	}
   192 	}
   192 }
   193 }