Ticket #43443: 43443.3.patch
File 43443.3.patch, 14.4 KB (added by , 6 years ago) |
---|
-
src/wp-includes/user.php
2815 2815 * 2816 2816 * @since 5.0.0 2817 2817 * 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 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. 2821 * 2822 * @return WP_ERROR|bool Will return true/false based on the success of sending the email, or a WP_Error object. 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. 2823 2823 */ 2824 function send_confirm_account_action_email( $action_name, $action_description = '', $email = '' ) { 2824 function 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 2825 2829 $action_name = sanitize_key( $action_name ); 2826 2830 $action_description = wp_kses_post( $action_description ); 2827 2831 2828 2832 if ( empty( $action_name ) ) { 2829 return new WP_Error( 'invalid_action', __( 'Invalid action' ) );2833 $action_name = 'confirm_email'; 2830 2834 } 2831 2835 2836 if ( empty( $action_description ) ) { 2837 $action_description = __( 'Confirm your email address.' ); 2838 } 2839 2832 2840 if ( empty( $email ) ) { 2833 2841 $user = wp_get_current_user(); 2834 2842 $email = $user->ID ? $user->user_email : ''; … … 2846 2854 $user = get_user_by( 'email', $email ); 2847 2855 } 2848 2856 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 ); 2853 2858 2854 2859 if ( is_wp_error( $confirm_key ) ) { 2855 2860 return $confirm_key; 2856 2861 } 2857 2862 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 ); 2861 2871 } 2862 2872 2863 2873 /* translators: Do not translate DESCRIPTION, CONFIRM_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */ … … 2864 2874 $email_text = __( 2865 2875 'Howdy, 2866 2876 2867 An account linked to your email address has requested to perform 2868 the following action: 2877 A request has been made to perform the following action on your account: 2869 2878 2870 2879 ###DESCRIPTION### 2871 2880 2872 To confirm this action, please click on the following link:2881 To confirm this, please click on the following link: 2873 2882 ###CONFIRM_URL### 2874 2883 2875 2884 You can safely ignore and delete this email if you do not want to … … 2887 2896 'email' => $email, 2888 2897 'description' => $action_description, 2889 2898 'confirm_url' => add_query_arg( array( 2890 'action' => ' emailconfirm',2899 'action' => 'verifyaccount', 2891 2900 'confirm_action' => $action_name, 2892 2901 'uid' => $uid, 2893 2902 'confirm_key' => $confirm_key, … … 2907 2916 * ###SITENAME### The name of the site. 2908 2917 * ###SITEURL### The URL to the site. 2909 2918 * 2919 * @since 5.0.0 2920 * 2910 2921 * @param string $email_text Text in the email. 2911 2922 * @param array $email_data { 2912 2923 * Data relating to the account action email. … … 2919 2930 * @type string $siteurl The site URL sending the mail. 2920 2931 * } 2921 2932 */ 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 ); 2923 2934 2924 2935 $content = str_replace( '###DESCRIPTION###', $email_data['description'], $content ); 2925 2936 $content = str_replace( '###CONFIRM_URL###', esc_url_raw( $email_data['confirm_url'] ), $content ); … … 2928 2939 $content = str_replace( '###SITEURL###', esc_url_raw( $email_data['siteurl'] ), $content ); 2929 2940 2930 2941 /* translators: %s Site name. */ 2931 return wp_mail( $email_data['email'], sprintf( __( '[%s] Confirm Ac count 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 ); 2932 2943 } 2933 2944 2934 2945 /** … … 2936 2947 * 2937 2948 * @since 5.0.0 2938 2949 * 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. 2942 2953 * @return string|WP_Error Confirmation key on success. WP_Error on error. 2943 2954 */ 2944 function get_confirm_account_action_key( $action_name, $email) {2955 function wp_get_account_verification_key( $email, $action_name, $request_data = array() ) { 2945 2956 global $wp_hasher; 2946 2957 2947 2958 if ( ! is_email( $email ) ) { … … 2967 2978 } 2968 2979 2969 2980 $hashed_key = $wp_hasher->HashPassword( $key ); 2981 $value = array( 2982 'time' => time(), 2983 'hash' => $hashed_key, 2984 'email' => $email, 2985 'request_data' => $request_data, 2986 ); 2970 2987 2971 2988 if ( $is_registered_user ) { 2972 $key_saved = (bool) update_user_meta( $user->ID, '_ account_action_' . $action_name, implode( ':', array( time(), $hashed_key )) );2989 $key_saved = (bool) update_user_meta( $user->ID, '_verify_' . $action_name, wp_json_encode( $value ) ); 2973 2990 } else { 2974 $key_saved = (bool) update_site_option( '_account_action_' . hash( 'sha256', $email ) . '_' . $action_name, implode( ':', array( time(), $hashed_key, $email ) ) ); 2991 $uid = function_exists( 'hash' ) ? hash( 'sha256', $email ) : sha1( $email ); 2992 $key_saved = (bool) update_site_option( '_verify_' . $action_name . '_' . $uid, wp_json_encode( $value ) ); 2975 2993 } 2976 2994 2977 2995 if ( false === $key_saved ) { 2978 return new WP_Error( 'no_ confirm_account_action_key_update', __( 'Could not save confirm account action key to database.' ) );2996 return new WP_Error( 'no_account_verification_key_update', __( 'Could not save confirm account action key to database.' ) ); 2979 2997 } 2980 2998 2981 2999 return $key; … … 2986 3004 * 2987 3005 * @since 5.0.0 2988 3006 * 2989 * @param string $action_name Name of the action this key is being generated for.2990 3007 * @param string $key Key to confirm. 2991 3008 * @param string $uid Email hash or user ID. 2992 * 3009 * @param string $action_name Name of the action this key is being generated for. 2993 3010 * @return array|WP_Error WP_Error on failure, action name and user email address on success. 2994 3011 */ 2995 function check_confirm_account_action_key( $action_name, $key, $uid) {3012 function wp_check_account_verification_key( $key, $uid, $action_name ) { 2996 3013 global $wp_hasher; 2997 3014 2998 if ( ! empty( $action_name ) && ! empty( $key ) && ! empty( $uid ) ) { 2999 $user = false; 3015 if ( empty( $action_name ) || empty( $key ) || empty( $uid ) ) { 3016 return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); 3017 } 3000 3018 3001 if ( is_numeric( $uid ) ) { 3002 $user = get_user_by( 'id', absint( $uid ) ); 3003 } 3019 $user = false; 3004 3020 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 = ''; 3021 if ( is_numeric( $uid ) ) { 3022 $user = get_user_by( 'id', absint( $uid ) ); 3023 } 3010 3024 3011 if ( empty( $wp_hasher ) ) { 3012 require_once ABSPATH . WPINC . '/class-phpass.php'; 3013 $wp_hasher = new PasswordHash( 8, true ); 3014 } 3025 // We could be dealing with a registered user account, or a visitor. 3026 $is_registered_user = ( $user && ! is_wp_error( $user ) ); 3027 $key_request_time = ''; 3028 $saved_key = ''; 3029 $email = ''; 3015 3030 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;3031 if ( empty( $wp_hasher ) ) { 3032 require_once ABSPATH . WPINC . '/class-phpass.php'; 3033 $wp_hasher = new PasswordHash( 8, true ); 3034 } 3020 3035 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, '' ); 3036 // Get the saved key from the database. 3037 if ( $is_registered_user ) { 3038 $raw_data = get_user_meta( $user->ID, '_verify_' . $action_name, true ); 3039 $email = $user->user_email; 3026 3040 3027 if ( false !== strpos( $confirm_action_data, ':' ) ) { 3028 list( $key_request_time, $saved_key, $email ) = explode( ':', $confirm_action_data, 3 ); 3029 } 3041 if ( false !== strpos( $confirm_action_data, ':' ) ) { 3042 list( $key_request_time, $saved_key ) = explode( ':', $confirm_action_data, 2 ); 3030 3043 } 3044 } else { 3045 $raw_data = get_site_option( '_verify_' . $action_name . '_' . $uid, '' ); 3031 3046 3032 if ( ! $saved_key) {3033 return new WP_Error( 'invalid_key', __( 'Invalid key' ));3047 if ( false !== strpos( $confirm_action_data, ':' ) ) { 3048 list( $key_request_time, $saved_key, $email ) = explode( ':', $confirm_action_data, 3 ); 3034 3049 } 3050 } 3035 3051 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; 3052 $data = json_decode( $raw_data, true ); 3053 $key_request_time = (int) isset( $data['time'] ) ? $data['time'] : 0; 3054 $saved_key = isset( $data['hash'] ) ? $data['hash'] : ''; 3055 $email = sanitize_email( isset( $data['email'] ) ? $data['email'] : '' ); 3056 $request_data = isset( $data['request_data'] ) ? $data['request_data'] : array(); 3043 3057 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 } 3058 if ( ! $saved_key ) { 3059 return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); 3060 } 3053 3061 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 } 3062 if ( ! $key_request_time || ! $email ) { 3063 return new WP_Error( 'invalid_key', __( 'Invalid action' ) ); 3064 } 3060 3065 3061 return $return; 3062 } 3066 /** 3067 * Filters the expiration time of confirm keys. 3068 * 3069 * @since 5.0.0 3070 * 3071 * @param int $expiration The expiration time in seconds. 3072 */ 3073 $expiration_duration = apply_filters( 'account_verification_expiration', DAY_IN_SECONDS ); 3074 $expiration_time = $key_request_time + $expiration_duration; 3075 3076 if ( ! $wp_hasher->CheckPassword( $key, $saved_key ) ) { 3077 return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); 3063 3078 } 3064 3079 3065 return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); 3080 if ( $expiration_time && time() < $expiration_time ) { 3081 $return = array( 3082 'action' => $action_name, 3083 'email' => $email, 3084 'request_data' => $request_data, 3085 ); 3086 } else { 3087 $return = new WP_Error( 'expired_key', __( 'The confirmation email has expired.' ) ); 3088 } 3089 3090 // Clean up stored keys. 3091 if ( $is_registered_user ) { 3092 delete_user_meta( $user->ID, '_verify_' . $action_name ); 3093 } else { 3094 delete_site_option( '_verify_' . $action_name . '_' . $uid ); 3095 } 3096 3097 return $return; 3066 3098 } -
src/wp-login.php
427 427 } 428 428 429 429 // 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 ) ) {430 if ( ! in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login', 'verifyaccount' ), true ) && false === has_filter( 'login_form_' . $action ) ) { 431 431 $action = 'login'; 432 432 } 433 433 … … 858 858 859 859 break; 860 860 861 case ' emailconfirm' :861 case 'verifyaccount' : 862 862 if ( isset( $_GET['confirm_action'], $_GET['confirm_key'], $_GET['uid'] ) ) { 863 $action_name = sanitize_key( wp_unslash( $_GET['confirm_action'] ) );864 863 $key = sanitize_text_field( wp_unslash( $_GET['confirm_key'] ) ); 865 864 $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 ); 867 867 } else { 868 868 $result = new WP_Error( 'invalid_key', __( 'Invalid key' ) ); 869 869 } … … 874 874 * 875 875 * After running this action hook the page will die. 876 876 * 877 * @since 5.0.0 878 * 877 879 * @param WP_Error $result Error object. 878 880 */ 879 881 do_action( 'account_action_failed', $result ); … … 890 892 * After firing this action hook the page will redirect to wp-login a callback 891 893 * redirects or exits first. 892 894 * 895 * @since 5.0.0 896 * 893 897 * @param array $result { 894 898 * Data about the action which was confirmed. 895 899 *