WordPress.org

Make WordPress Core

Ticket #32429: 32429.7.diff

File 32429.7.diff, 5.5 KB (added by dd32, 6 years ago)
  • src/wp-includes/user.php

    function check_password_reset_key($key,  
    24462446        if ( empty( $key ) || !is_string( $key ) )
    24472447                return new WP_Error('invalid_key', __('Invalid key'));
    24482448
    24492449        if ( empty($login) || !is_string($login) )
    24502450                return new WP_Error('invalid_key', __('Invalid key'));
    24512451
    24522452        $row = $wpdb->get_row( $wpdb->prepare( "SELECT ID, user_activation_key FROM $wpdb->users WHERE user_login = %s", $login ) );
    24532453        if ( ! $row )
    24542454                return new WP_Error('invalid_key', __('Invalid key'));
    24552455
    24562456        if ( empty( $wp_hasher ) ) {
    24572457                require_once ABSPATH . WPINC . '/class-phpass.php';
    24582458                $wp_hasher = new PasswordHash( 8, true );
    24592459        }
    24602460
    2461         if ( $wp_hasher->CheckPassword( $key, $row->user_activation_key ) )
     2461        /**
     2462         * Filter the expiration time of password reset keys.
     2463         *
     2464         * @since 4.3.0
     2465         *
     2466         * @param int $expiration The expiration time in seconds.
     2467         */
     2468        $expiration_duration = apply_filters( 'password_reset_expiration', DAY_IN_SECONDS );
     2469
     2470        if ( false !== strpos( $row->user_activation_key, ':' ) ) {
     2471                list( $pass_request_time, $pass_key ) = explode( ':', $row->user_activation_key, 2 );
     2472                $expiration_time = $pass_request_time + $expiration_duration;
     2473        } else {
     2474                $pass_key = $row->user_activation_key;
     2475                $expiration_time = false;
     2476        }
     2477
     2478        $hash_is_correct = $wp_hasher->CheckPassword( $key, $pass_key );
     2479
     2480        if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) {
    24622481                return get_userdata( $row->ID );
     2482        }
    24632483
    2464         if ( $key === $row->user_activation_key ) {
    2465                 $return = new WP_Error( 'expired_key', __( 'Invalid key' ) );
     2484        if ( hash_equals( $row->user_activation_key, $key ) || $hash_is_correct ) {
     2485                $return = new WP_Error( 'expired_key', __( 'Your password reset token has expired.' ) );
    24662486                $user_id = $row->ID;
    24672487
    24682488                /**
    24692489                 * Filter the return value of check_password_reset_key() when an
    2470                  * old-style key is used (plain-text key was stored in the database).
     2490                 * old-style key is used.
    24712491                 *
    2472                  * @since 3.7.0
     2492                 * @since 3.7.0 Previously plain-text keys were stored in the database.
     2493                 * @since 4.3.0 Previously key hashes were stored without an expiration time.
    24732494                 *
    24742495                 * @param WP_Error $return  A WP_Error object denoting an expired key.
    24752496                 *                          Return a WP_User object to validate the key.
    24762497                 * @param int      $user_id The matched user ID.
    24772498                 */
    24782499                return apply_filters( 'password_reset_key_expired', $return, $user_id );
    24792500        }
    24802501
    24812502        return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
    24822503}
    24832504
    24842505/**
    24852506 * Handles resetting the user's password.
    24862507 *
    24872508 * @since 2.5.0
  • src/wp-login.php

    function retrieve_password() { 
    351351        /**
    352352         * Fires when a password reset key is generated.
    353353         *
    354354         * @since 2.5.0
    355355         *
    356356         * @param string $user_login The username for the user.
    357357         * @param string $key        The generated password reset key.
    358358         */
    359359        do_action( 'retrieve_password_key', $user_login, $key );
    360360
    361361        // Now insert the key, hashed, into the DB.
    362362        if ( empty( $wp_hasher ) ) {
    363363                require_once ABSPATH . WPINC . '/class-phpass.php';
    364364                $wp_hasher = new PasswordHash( 8, true );
    365365        }
    366         $hashed = $wp_hasher->HashPassword( $key );
     366        $hashed = time() . ':' . $wp_hasher->HashPassword( $key );
    367367        $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user_login ) );
    368368
    369369        $message = __('Someone requested that the password be reset for the following account:') . "\r\n\r\n";
    370370        $message .= network_home_url( '/' ) . "\r\n\r\n";
    371371        $message .= sprintf(__('Username: %s'), $user_login) . "\r\n\r\n";
    372372        $message .= __('If this was a mistake, just ignore this email and nothing will happen.') . "\r\n\r\n";
    373373        $message .= __('To reset your password, visit the following address:') . "\r\n\r\n";
    374374        $message .= '<' . network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . ">\r\n";
    375375
    376376        if ( is_multisite() )
    377377                $blogname = $GLOBALS['current_site']->site_name;
    378378        else
    379379                /*
    380380                 * The blogname option is escaped with esc_html on the way into the database
    381381                 * in sanitize_option we want to reverse this for the plain text arena of emails.
    case 'lostpassword' : 
    519519case 'retrievepassword' :
    520520
    521521        if ( $http_post ) {
    522522                $errors = retrieve_password();
    523523                if ( !is_wp_error($errors) ) {
    524524                        $redirect_to = !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : 'wp-login.php?checkemail=confirm';
    525525                        wp_safe_redirect( $redirect_to );
    526526                        exit();
    527527                }
    528528        }
    529529
    530530        if ( isset( $_GET['error'] ) ) {
    531531                if ( 'invalidkey' == $_GET['error'] )
    532532                        $errors->add( 'invalidkey', __( 'Sorry, that key does not appear to be valid.' ) );
    533533                elseif ( 'expiredkey' == $_GET['error'] )
    534                         $errors->add( 'expiredkey', __( 'Sorry, that key has expired. Please try again.' ) );
     534                        $errors->add( 'expiredkey', __( 'Your password reset link has expired. Please request a new link below.' ) );
    535535        }
    536536
    537537        $lostpassword_redirect = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
    538538        /**
    539539         * Filter the URL redirected to after submitting the lostpassword/retrievepassword form.
    540540         *
    541541         * @since 3.0.0
    542542         *
    543543         * @param string $lostpassword_redirect The redirect destination URL.
    544544         */
    545545        $redirect_to = apply_filters( 'lostpassword_redirect', $lostpassword_redirect );
    546546
    547547        /**
    548548         * Fires before the lost password form.
    549549         *