Make WordPress Core

Ticket #43443: 43443.4.diff

File 43443.4.diff, 14.4 KB (added by mikejolley, 7 years ago)

Synced with master and working :)

  • wp-includes/user.php

    diff --git wp-includes/user.php wp-includes/user.php
    index 476aa51424..2c38690252 100644
    function new_user_email_admin_notice() { 
    28152815 *
    28162816 * @since 5.0.0
    28172817 *
    2818  * @param string $action_name        Name of the action that is being confirmed.
    2819  * @param string $action_description User facing description of the action they will be confirming.
    2820  * @param string $email              User email address. This can be the address of a registered or non-registered user. Defaults to logged in user email address.
    2821  *
    2822  * @return WP_ERROR|bool Will return true/false based on the success of sending the email, or a WP_Error object.
     2818 * @param string $email              User email address. This can be the address of a registered or non-registered user. Defaults to logged in user email address.
     2819 * @param string $action_name        Name of the action that is being confirmed. Defaults to 'confirm_email'.
     2820 * @param string $action_description User facing description of the action they will be confirming. Defaults to "confirm your email address".
     2821 * @param array  $request_data       Misc data you want to send with the verification request and pass to the actions once the request is confirmed.
     2822 * @return WP_Error|bool Will return true/false based on the success of sending the email, or a WP_Error object.
    28232823 */
    2824 function send_confirm_account_action_email( $action_name, $action_description = '', $email = '' ) {
     2824function wp_send_account_verification_key( $email = '', $action_name = '', $action_description = '', $request_data = array() ) {
     2825        if ( ! function_exists( 'wp_get_current_user' ) ) {
     2826                return new WP_Error( 'invalid', __( 'This function cannot be used before init.' ) );
     2827        }
     2828
    28252829        $action_name        = sanitize_key( $action_name );
    28262830        $action_description = wp_kses_post( $action_description );
    28272831
    28282832        if ( empty( $action_name ) ) {
    2829                 return new WP_Error( 'invalid_action', __( 'Invalid action' ) );
     2833                $action_name = 'confirm_email';
     2834        }
     2835
     2836        if ( empty( $action_description ) ) {
     2837                $action_description = __( 'Confirm your email address.' );
    28302838        }
    28312839
    28322840        if ( empty( $email ) ) {
    function send_confirm_account_action_email( $action_name, $action_description = 
    28462854                $user = get_user_by( 'email', $email );
    28472855        }
    28482856
    2849         // We could be dealing with a registered user account, or a visitor.
    2850         $is_registered_user = $user && ! is_wp_error( $user );
    2851         $uid                = $is_registered_user ? $user->ID : hash( 'sha256', $email );
    2852         $confirm_key        = get_confirm_account_action_key( $action_name, $email );
     2857        $confirm_key = wp_get_account_verification_key( $email, $action_name, $request_data );
    28532858
    28542859        if ( is_wp_error( $confirm_key ) ) {
    28552860                return $confirm_key;
    28562861        }
    28572862
    2858         // Prepare the email content.
    2859         if ( ! $action_description ) {
    2860                 $action_description = $action_name;
     2863        // We could be dealing with a registered user account, or a visitor.
     2864        $is_registered_user = $user && ! is_wp_error( $user );
     2865
     2866        if ( $is_registered_user ) {
     2867                $uid = $user->ID;
     2868        } else {
     2869                // Generate a UID for this email address so we don't send the actual email in the query string. Hash is not supported on all systems.
     2870                $uid = function_exists( 'hash' ) ? hash( 'sha256', $email ) : sha1( $email );
    28612871        }
    28622872
    28632873        /* translators: Do not translate DESCRIPTION, CONFIRM_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
    28642874        $email_text = __(
    28652875                'Howdy,
    28662876
    2867 An account linked to your email address has requested to perform
    2868 the following action:
     2877A request has been made to perform the following action on your account:
    28692878
    28702879     ###DESCRIPTION###
    28712880
    2872 To confirm this action, please click on the following link:
     2881To confirm this, please click on the following link:
    28732882###CONFIRM_URL###
    28742883
    28752884You can safely ignore and delete this email if you do not want to
    All at ###SITENAME### 
    28872896                'email'       => $email,
    28882897                'description' => $action_description,
    28892898                'confirm_url' => add_query_arg( array(
    2890                         'action'         => 'emailconfirm',
     2899                        'action'         => 'verifyaccount',
    28912900                        'confirm_action' => $action_name,
    28922901                        'uid'            => $uid,
    28932902                        'confirm_key'    => $confirm_key,
    All at ###SITENAME### 
    29072916         * ###SITENAME###           The name of the site.
    29082917         * ###SITEURL###            The URL to the site.
    29092918         *
     2919         * @since 5.0.0
     2920         *
    29102921         * @param string $email_text     Text in the email.
    29112922         * @param array  $email_data {
    29122923         *     Data relating to the account action email.
    All at ###SITENAME### 
    29192930         *     @type string $siteurl     The site URL sending the mail.
    29202931         * }
    29212932         */
    2922         $content = apply_filters( 'confirm_account_action_email_content', $email_text, $email_data );
     2933        $content = apply_filters( 'account_verification_email_content', $email_text, $email_data );
    29232934
    29242935        $content = str_replace( '###DESCRIPTION###', $email_data['description'], $content );
    29252936        $content = str_replace( '###CONFIRM_URL###', esc_url_raw( $email_data['confirm_url'] ), $content );
    All at ###SITENAME### 
    29282939        $content = str_replace( '###SITEURL###', esc_url_raw( $email_data['siteurl'] ), $content );
    29292940
    29302941        /* translators: %s Site name. */
    2931         return wp_mail( $email_data['email'], sprintf( __( '[%s] Confirm Account Action' ), wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ) ), $content );
     2942        return wp_mail( $email_data['email'], sprintf( __( '[%s] Confirm Action' ), wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ) ), $content );
    29322943}
    29332944
    29342945/**
    All at ###SITENAME### 
    29362947 *
    29372948 * @since 5.0.0
    29382949 *
    2939  * @param string $action_name Name of the action this key is being generated for.
    2940  * @param string $email       User email address. This can be the address of a registered or non-registered user.
    2941  *
     2950 * @param string $email        User email address. This can be the address of a registered or non-registered user.
     2951 * @param string $action_name  Name of the action this key is being generated for.
     2952 * @param array  $request_data Misc data you want to send with the verification request and pass to the actions once the request is confirmed.
    29422953 * @return string|WP_Error Confirmation key on success. WP_Error on error.
    29432954 */
    2944 function get_confirm_account_action_key( $action_name, $email ) {
     2955function wp_get_account_verification_key( $email, $action_name, $request_data = array() ) {
    29452956        global $wp_hasher;
    29462957
    29472958        if ( ! is_email( $email ) ) {
    function get_confirm_account_action_key( $action_name, $email ) { 
    29672978        }
    29682979
    29692980        $hashed_key = $wp_hasher->HashPassword( $key );
     2981        $value      = array(
     2982                'action'       => $action_name,
     2983                'time'         => time(),
     2984                'hash'         => $hashed_key,
     2985                'email'        => $email,
     2986                'request_data' => $request_data,
     2987        );
    29702988
    29712989        if ( $is_registered_user ) {
    2972                 $key_saved = (bool) update_user_meta( $user->ID, '_account_action_' . $action_name, implode( ':', array( time(), $hashed_key ) ) );
     2990                $key_saved = (bool) update_user_meta( $user->ID, '_verify_action_' . $action_name, wp_json_encode( $value ) );
    29732991        } else {
    2974                 $key_saved = (bool) update_site_option( '_account_action_' . hash( 'sha256', $email ) . '_' . $action_name, implode( ':', array( time(), $hashed_key, $email ) ) );
     2992                $uid       = function_exists( 'hash' ) ? hash( 'sha256', $email ) : sha1( $email );
     2993                $key_saved = (bool) update_site_option( '_verify_action_' . $action_name . '_' . $uid, wp_json_encode( $value ) );
    29752994        }
    29762995
    29772996        if ( false === $key_saved ) {
    2978                 return new WP_Error( 'no_confirm_account_action_key_update', __( 'Could not save confirm account action key to database.' ) );
     2997                return new WP_Error( 'no_account_verification_key_update', __( 'Could not save confirm account action key to database.' ) );
    29792998        }
    29802999
    29813000        return $key;
    function get_confirm_account_action_key( $action_name, $email ) { 
    29863005 *
    29873006 * @since 5.0.0
    29883007 *
    2989  * @param string $action_name Name of the action this key is being generated for.
    29903008 * @param string $key         Key to confirm.
    29913009 * @param string $uid         Email hash or user ID.
    2992  *
     3010 * @param string $action_name Name of the action this key is being generated for.
    29933011 * @return array|WP_Error WP_Error on failure, action name and user email address on success.
    29943012 */
    2995 function check_confirm_account_action_key( $action_name, $key, $uid ) {
     3013function wp_check_account_verification_key( $key, $uid, $action_name ) {
    29963014        global $wp_hasher;
    29973015
    2998         if ( ! empty( $action_name ) && ! empty( $key ) && ! empty( $uid ) ) {
    2999                 $user = false;
     3016        if ( empty( $action_name ) || empty( $key ) || empty( $uid ) ) {
     3017                return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
     3018        }
    30003019
    3001                 if ( is_numeric( $uid ) ) {
    3002                         $user = get_user_by( 'id', absint( $uid ) );
    3003                 }
     3020        $user = false;
    30043021
    3005                 // We could be dealing with a registered user account, or a visitor.
    3006                 $is_registered_user = $user && ! is_wp_error( $user );
    3007                 $key_request_time = '';
    3008                 $saved_key        = '';
    3009                 $email            = '';
     3022        if ( is_numeric( $uid ) ) {
     3023                $user = get_user_by( 'id', absint( $uid ) );
     3024        }
    30103025
    3011                 if ( empty( $wp_hasher ) ) {
    3012                         require_once ABSPATH . WPINC . '/class-phpass.php';
    3013                         $wp_hasher = new PasswordHash( 8, true );
    3014                 }
     3026        // We could be dealing with a registered user account, or a visitor.
     3027        $is_registered_user = ( $user && ! is_wp_error( $user ) );
     3028        $key_request_time   = '';
     3029        $saved_key          = '';
     3030        $email              = '';
    30153031
    3016                 // Get the saved key from the database.
    3017                 if ( $is_registered_user ) {
    3018                         $confirm_action_data = get_user_meta( $user->ID, '_account_action_' . $action_name, true );
    3019                         $email               = $user->user_email;
     3032        if ( empty( $wp_hasher ) ) {
     3033                require_once ABSPATH . WPINC . '/class-phpass.php';
     3034                $wp_hasher = new PasswordHash( 8, true );
     3035        }
    30203036
    3021                         if ( false !== strpos( $confirm_action_data, ':' ) ) {
    3022                                 list( $key_request_time, $saved_key ) = explode( ':', $confirm_action_data, 2 );
    3023                         }
    3024                 } else {
    3025                         $confirm_action_data = get_site_option( '_account_action_' . $uid . '_' . $action_name, '' );
     3037        // Get the saved key from the database.
     3038        if ( $is_registered_user ) {
     3039                $raw_data = get_user_meta( $user->ID, '_verify_action_' . $action_name, true );
     3040                $email    = $user->user_email;
    30263041
    3027                         if ( false !== strpos( $confirm_action_data, ':' ) ) {
    3028                                 list( $key_request_time, $saved_key, $email ) = explode( ':', $confirm_action_data, 3 );
    3029                         }
     3042                if ( false !== strpos( $confirm_action_data, ':' ) ) {
     3043                        list( $key_request_time, $saved_key ) = explode( ':', $confirm_action_data, 2 );
    30303044                }
     3045        } else {
     3046                $raw_data = get_site_option( '_verify_action_' . $action_name . '_' . $uid, '' );
    30313047
    3032                 if ( ! $saved_key ) {
    3033                         return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
     3048                if ( false !== strpos( $confirm_action_data, ':' ) ) {
     3049                        list( $key_request_time, $saved_key, $email ) = explode( ':', $confirm_action_data, 3 );
    30343050                }
     3051        }
    30353052
    3036                 /**
    3037                  * Filters the expiration time of confirm keys.
    3038                  *
    3039                  * @param int $expiration The expiration time in seconds.
    3040                  */
    3041                 $expiration_duration = apply_filters( 'account_action_expiration', DAY_IN_SECONDS );
    3042                 $expiration_time     = $key_request_time + $expiration_duration;
    3043 
    3044                 if ( $wp_hasher->CheckPassword( $key, $saved_key ) ) {
    3045                         if ( $expiration_time && time() < $expiration_time ) {
    3046                                 $return = array(
    3047                                         'action' => $action_name,
    3048                                         'email'  => $email,
    3049                                 );
    3050                         } else {
    3051                                 $return = new WP_Error( 'expired_key', __( 'The confirmation email has expired.' ) );
    3052                         }
     3053        $data             = json_decode( $raw_data, true );
     3054        $key_request_time = (int) isset( $data['time'] ) ? $data['time'] : 0;
     3055        $saved_key        = isset( $data['hash'] ) ? $data['hash'] : '';
     3056        $email            = sanitize_email( isset( $data['email'] ) ? $data['email'] : '' );
     3057        $request_data     = isset( $data['request_data'] ) ? $data['request_data'] : array();
    30533058
    3054                         // Clean up stored keys.
    3055                         if ( $is_registered_user ) {
    3056                                 delete_user_meta( $user->ID, '_account_action_' . $action_name );
    3057                         } else {
    3058                                 delete_site_option( '_account_action_' . $uid . '_' . $action_name );
    3059                         }
     3059        if ( ! $saved_key ) {
     3060                return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
     3061        }
    30603062
    3061                         return $return;
    3062                 }
     3063        if ( ! $key_request_time || ! $email ) {
     3064                return new WP_Error( 'invalid_key', __( 'Invalid action' ) );
    30633065        }
    30643066
    3065         return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
    3066 }
     3067        /**
     3068         * Filters the expiration time of confirm keys.
     3069         *
     3070         * @since 5.0.0
     3071         *
     3072         * @param int $expiration The expiration time in seconds.
     3073         */
     3074        $expiration_duration = apply_filters( 'account_verification_expiration', DAY_IN_SECONDS );
     3075        $expiration_time     = $key_request_time + $expiration_duration;
     3076
     3077        if ( ! $wp_hasher->CheckPassword( $key, $saved_key ) ) {
     3078                return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
     3079        }
     3080
     3081        if ( $expiration_time && time() < $expiration_time ) {
     3082                $return = array(
     3083                        'action'       => $action_name,
     3084                        'email'        => $email,
     3085                        'request_data' => $request_data,
     3086                );
     3087        } else {
     3088                $return = new WP_Error( 'expired_key', __( 'The confirmation email has expired.' ) );
     3089        }
     3090
     3091        // Clean up stored keys.
     3092        if ( $is_registered_user ) {
     3093                delete_user_meta( $user->ID, '_verify_action_' . $action_name );
     3094        } else {
     3095                delete_site_option( '_verify_action_' . $action_name . '_' . $uid );
     3096        }
     3097
     3098        return $return;
     3099}
     3100 No newline at end of file
  • wp-login.php

    diff --git wp-login.php wp-login.php
    index 93d08181ee..960be85cee 100644
    if ( isset( $_GET['key'] ) ) { 
    427427}
    428428
    429429// validate action so as to default to the login screen
    430 if ( ! in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login', 'emailconfirm' ), true ) && false === has_filter( 'login_form_' . $action ) ) {
     430if ( ! in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login', 'verifyaccount' ), true ) && false === has_filter( 'login_form_' . $action ) ) {
    431431        $action = 'login';
    432432}
    433433
    switch ( $action ) { 
    858858
    859859                break;
    860860
    861         case 'emailconfirm' :
     861        case 'verifyaccount' :
    862862                if ( isset( $_GET['confirm_action'], $_GET['confirm_key'], $_GET['uid'] ) ) {
    863                         $action_name = sanitize_key( wp_unslash( $_GET['confirm_action'] ) );
    864863                        $key         = sanitize_text_field( wp_unslash( $_GET['confirm_key'] ) );
    865864                        $uid         = sanitize_text_field( wp_unslash( $_GET['uid'] ) );
    866                         $result      = check_confirm_account_action_key( $action_name, $key, $uid );
     865                        $action_name = sanitize_key( wp_unslash( $_GET['confirm_action'] ) );
     866                        $result      = wp_check_account_verification_key( $key, $uid, $action_name );
    867867                } else {
    868868                        $result = new WP_Error( 'invalid_key', __( 'Invalid key' ) );
    869869                }