diff --git a/wp-includes/user.php b/wp-includes/user.php index ba9fa819fd..a1c12cdb01 100644 --- a/wp-includes/user.php +++ b/wp-includes/user.php @@ -2458,18 +2458,42 @@ function check_password_reset_key($key, $login) { $wp_hasher = new PasswordHash( 8, true ); } - if ( $wp_hasher->CheckPassword( $key, $row->user_activation_key ) ) - return get_userdata( $row->ID ); + /** + * Filter the expiration time of password reset keys. + * + * @since 4.3.0 + * + * @param int $expiration The expiration time in seconds. + */ + $expiration_duration = apply_filters( 'password_reset_expiration', DAY_IN_SECONDS ); - if ( $key === $row->user_activation_key ) { + if ( false !== strpos( $row->user_activation_key, ':' ) ) { + list( $pass_request_time, $pass_key ) = explode( ':', $row->user_activation_key, 2 ); + $expiration_time = $pass_request_time + $expiration_duration; + } else { + $pass_key = $row->user_activation_key; + $expiration_time = false; + } + + $hash_is_correct = $wp_hasher->CheckPassword( $key, $pass_key ); + + if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) { + return get_userdata( $row->ID ); + } elseif ( $hash_is_correct && $expiration_time ) { + // Key has an expiration time that's passed + return new WP_Error( 'expired_key', __( 'Invalid key' ) ); + } + + if ( hash_equals( $row->user_activation_key, $key ) || ( $hash_is_correct && ! $expiration_time ) ) { $return = new WP_Error( 'expired_key', __( 'Invalid key' ) ); $user_id = $row->ID; /** * Filter the return value of check_password_reset_key() when an - * old-style key is used (plain-text key was stored in the database). + * old-style key is used. * - * @since 3.7.0 + * @since 3.7.0 Previously plain-text keys were stored in the database. + * @since 4.3.0 Previously key hashes were stored without an expiration time. * * @param WP_Error $return A WP_Error object denoting an expired key. * Return a WP_User object to validate the key. diff --git a/wp-includes/version.php b/wp-includes/version.php index 46ab5dab37..4cc970a324 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.3-alpha-33018'; +$wp_version = '4.3-alpha-33019'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. diff --git a/wp-login.php b/wp-login.php index 2056852726..080322cc09 100644 --- a/wp-login.php +++ b/wp-login.php @@ -363,7 +363,7 @@ function retrieve_password() { require_once ABSPATH . WPINC . '/class-phpass.php'; $wp_hasher = new PasswordHash( 8, true ); } - $hashed = $wp_hasher->HashPassword( $key ); + $hashed = time() . ':' . $wp_hasher->HashPassword( $key ); $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user_login ) ); $message = __('Someone requested that the password be reset for the following account:') . "\r\n\r\n"; @@ -528,10 +528,11 @@ case 'retrievepassword' : } if ( isset( $_GET['error'] ) ) { - if ( 'invalidkey' == $_GET['error'] ) - $errors->add( 'invalidkey', __( 'Sorry, that key does not appear to be valid.' ) ); - elseif ( 'expiredkey' == $_GET['error'] ) - $errors->add( 'expiredkey', __( 'Sorry, that key has expired. Please try again.' ) ); + if ( 'invalidkey' == $_GET['error'] ) { + $errors->add( 'invalidkey', __( 'Your password reset link appears to be invalid. Please request a new lnk below.' ) ); + } elseif ( 'expiredkey' == $_GET['error'] ) { + $errors->add( 'expiredkey', __( 'Your password reset link has expired. Please request a new link below.' ) ); + } } $lostpassword_redirect = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';