diff --git wp-includes/user.php wp-includes/user.php
index def16fa272..0c7825f329 100644
|
|
function new_user_email_admin_notice() { |
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 | | * @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 | * @return WP_Error|bool Will return true/false based on the success of sending the email, or a WP_Error object. |
2823 | 2822 | */ |
2824 | | function send_confirm_account_action_email( $action_name, $action_description = '', $email = '' ) { |
| 2823 | function wp_send_account_verification_key( $email = '', $action_name = '', $action_description = '' ) { |
| 2824 | if ( ! function_exists( 'wp_get_current_user' ) ) { |
| 2825 | return new WP_Error( 'invalid', __( 'This function cannot be used before init.' ) ); |
| 2826 | } |
| 2827 | |
2825 | 2828 | $action_name = sanitize_key( $action_name ); |
2826 | 2829 | $action_description = wp_kses_post( $action_description ); |
2827 | 2830 | |
2828 | 2831 | if ( empty( $action_name ) ) { |
2829 | | return new WP_Error( 'invalid_action', __( 'Invalid action' ) ); |
| 2832 | $action_name = 'confirm_email'; |
| 2833 | } |
| 2834 | |
| 2835 | if ( empty( $action_description ) ) { |
| 2836 | $action_description = __( 'Confirm your email address.' ); |
2830 | 2837 | } |
2831 | 2838 | |
2832 | 2839 | if ( empty( $email ) ) { |
… |
… |
function send_confirm_account_action_email( $action_name, $action_description = |
2846 | 2853 | $user = get_user_by( 'email', $email ); |
2847 | 2854 | } |
2848 | 2855 | |
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 ); |
| 2856 | $confirm_key = wp_get_account_verification_key( $email, $action_name ); |
2853 | 2857 | |
2854 | 2858 | if ( is_wp_error( $confirm_key ) ) { |
2855 | 2859 | return $confirm_key; |
2856 | 2860 | } |
2857 | 2861 | |
2858 | | // Prepare the email content. |
2859 | | if ( ! $action_description ) { |
2860 | | $action_description = $action_name; |
| 2862 | // We could be dealing with a registered user account, or a visitor. |
| 2863 | $is_registered_user = $user && ! is_wp_error( $user ); |
| 2864 | |
| 2865 | if ( $is_registered_user ) { |
| 2866 | $uid = $user->ID; |
| 2867 | } else { |
| 2868 | $uid = function_exists( 'hash' ) ? hash( 'sha256', $email ) : sha1( $email ); |
2861 | 2869 | } |
2862 | 2870 | |
2863 | 2871 | /* translators: Do not translate DESCRIPTION, CONFIRM_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */ |
2864 | 2872 | $email_text = __( |
2865 | 2873 | 'Howdy, |
2866 | 2874 | |
2867 | | An account linked to your email address has requested to perform |
2868 | | the following action: |
| 2875 | An account linked to your email address has requested to: |
2869 | 2876 | |
2870 | 2877 | ###DESCRIPTION### |
2871 | 2878 | |
2872 | | To confirm this action, please click on the following link: |
| 2879 | To do this, please click on the following link: |
2873 | 2880 | ###CONFIRM_URL### |
2874 | 2881 | |
2875 | 2882 | You can safely ignore and delete this email if you do not want to |
… |
… |
All at ###SITENAME### |
2887 | 2894 | 'email' => $email, |
2888 | 2895 | 'description' => $action_description, |
2889 | 2896 | 'confirm_url' => add_query_arg( array( |
2890 | | 'action' => 'emailconfirm', |
| 2897 | 'action' => 'verifyaccount', |
2891 | 2898 | 'confirm_action' => $action_name, |
2892 | 2899 | 'uid' => $uid, |
2893 | 2900 | 'confirm_key' => $confirm_key, |
… |
… |
All at ###SITENAME### |
2907 | 2914 | * ###SITENAME### The name of the site. |
2908 | 2915 | * ###SITEURL### The URL to the site. |
2909 | 2916 | * |
| 2917 | * @since 5.0.0 |
| 2918 | * |
2910 | 2919 | * @param string $email_text Text in the email. |
2911 | 2920 | * @param array $email_data { |
2912 | 2921 | * Data relating to the account action email. |
… |
… |
All at ###SITENAME### |
2919 | 2928 | * @type string $siteurl The site URL sending the mail. |
2920 | 2929 | * } |
2921 | 2930 | */ |
2922 | | $content = apply_filters( 'confirm_account_action_email_content', $email_text, $email_data ); |
| 2931 | $content = apply_filters( 'account_verification_email_content', $email_text, $email_data ); |
2923 | 2932 | |
2924 | 2933 | $content = str_replace( '###DESCRIPTION###', $email_data['description'], $content ); |
2925 | 2934 | $content = str_replace( '###CONFIRM_URL###', esc_url_raw( $email_data['confirm_url'] ), $content ); |
… |
… |
All at ###SITENAME### |
2928 | 2937 | $content = str_replace( '###SITEURL###', esc_url_raw( $email_data['siteurl'] ), $content ); |
2929 | 2938 | |
2930 | 2939 | /* 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 ); |
| 2940 | return wp_mail( $email_data['email'], sprintf( __( '[%s] Confirm Action' ), wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ) ), $content ); |
2932 | 2941 | } |
2933 | 2942 | |
2934 | 2943 | /** |
… |
… |
All at ###SITENAME### |
2936 | 2945 | * |
2937 | 2946 | * @since 5.0.0 |
2938 | 2947 | * |
2939 | | * @param string $action_name Name of the action this key is being generated for. |
2940 | 2948 | * @param string $email User email address. This can be the address of a registered or non-registered user. |
2941 | | * |
| 2949 | * @param string $action_name Name of the action this key is being generated for. |
2942 | 2950 | * @return string|WP_Error Confirmation key on success. WP_Error on error. |
2943 | 2951 | */ |
2944 | | function get_confirm_account_action_key( $action_name, $email ) { |
| 2952 | function wp_get_account_verification_key( $email, $action_name ) { |
2945 | 2953 | global $wp_hasher; |
2946 | 2954 | |
2947 | 2955 | if ( ! is_email( $email ) ) { |
… |
… |
function get_confirm_account_action_key( $action_name, $email ) { |
2969 | 2977 | $hashed_key = $wp_hasher->HashPassword( $key ); |
2970 | 2978 | |
2971 | 2979 | if ( $is_registered_user ) { |
2972 | | $key_saved = (bool) update_user_meta( $user->ID, '_account_action_' . $action_name, implode( ':', array( time(), $hashed_key ) ) ); |
| 2980 | $key_saved = (bool) update_user_meta( $user->ID, '_verify_' . $action_name, implode( ':', array( time(), $hashed_key ) ) ); |
2973 | 2981 | } else { |
2974 | | $key_saved = (bool) update_site_option( '_account_action_' . hash( 'sha256', $email ) . '_' . $action_name, implode( ':', array( time(), $hashed_key, $email ) ) ); |
| 2982 | $uid = function_exists( 'hash' ) ? hash( 'sha256', $email ) : sha1( $email ); |
| 2983 | $key_saved = (bool) update_site_option( '_verify_' . $uid . '_' . $action_name, implode( ':', array( time(), $hashed_key, $email ) ) ); |
2975 | 2984 | } |
2976 | 2985 | |
2977 | 2986 | if ( false === $key_saved ) { |
2978 | | return new WP_Error( 'no_confirm_account_action_key_update', __( 'Could not save confirm account action key to database.' ) ); |
| 2987 | return new WP_Error( 'no_account_verification_key_update', __( 'Could not save confirm account action key to database.' ) ); |
2979 | 2988 | } |
2980 | 2989 | |
2981 | 2990 | return $key; |
… |
… |
function get_confirm_account_action_key( $action_name, $email ) { |
2986 | 2995 | * |
2987 | 2996 | * @since 5.0.0 |
2988 | 2997 | * |
2989 | | * @param string $action_name Name of the action this key is being generated for. |
2990 | 2998 | * @param string $key Key to confirm. |
2991 | 2999 | * @param string $uid Email hash or user ID. |
2992 | | * |
| 3000 | * @param string $action_name Name of the action this key is being generated for. |
2993 | 3001 | * @return array|WP_Error WP_Error on failure, action name and user email address on success. |
2994 | 3002 | */ |
2995 | | function check_confirm_account_action_key( $action_name, $key, $uid ) { |
| 3003 | function wp_check_account_verification_key( $key, $uid, $action_name ) { |
2996 | 3004 | global $wp_hasher; |
2997 | 3005 | |
2998 | | if ( ! empty( $action_name ) && ! empty( $key ) && ! empty( $uid ) ) { |
2999 | | $user = false; |
| 3006 | if ( empty( $action_name ) || empty( $key ) || empty( $uid ) ) { |
| 3007 | return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); |
| 3008 | } |
3000 | 3009 | |
3001 | | if ( is_numeric( $uid ) ) { |
3002 | | $user = get_user_by( 'id', absint( $uid ) ); |
3003 | | } |
| 3010 | $user = false; |
3004 | 3011 | |
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 = ''; |
| 3012 | if ( is_numeric( $uid ) ) { |
| 3013 | $user = get_user_by( 'id', absint( $uid ) ); |
| 3014 | } |
3010 | 3015 | |
3011 | | if ( empty( $wp_hasher ) ) { |
3012 | | require_once ABSPATH . WPINC . '/class-phpass.php'; |
3013 | | $wp_hasher = new PasswordHash( 8, true ); |
3014 | | } |
| 3016 | // We could be dealing with a registered user account, or a visitor. |
| 3017 | $is_registered_user = $user && ! is_wp_error( $user ); |
| 3018 | $key_request_time = ''; |
| 3019 | $saved_key = ''; |
| 3020 | $email = ''; |
3015 | 3021 | |
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; |
| 3022 | if ( empty( $wp_hasher ) ) { |
| 3023 | require_once ABSPATH . WPINC . '/class-phpass.php'; |
| 3024 | $wp_hasher = new PasswordHash( 8, true ); |
| 3025 | } |
3020 | 3026 | |
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, '' ); |
| 3027 | // Get the saved key from the database. |
| 3028 | if ( $is_registered_user ) { |
| 3029 | $confirm_action_data = get_user_meta( $user->ID, '_verify_' . $action_name, true ); |
| 3030 | $email = $user->user_email; |
3026 | 3031 | |
3027 | | if ( false !== strpos( $confirm_action_data, ':' ) ) { |
3028 | | list( $key_request_time, $saved_key, $email ) = explode( ':', $confirm_action_data, 3 ); |
3029 | | } |
| 3032 | if ( false !== strpos( $confirm_action_data, ':' ) ) { |
| 3033 | list( $key_request_time, $saved_key ) = explode( ':', $confirm_action_data, 2 ); |
3030 | 3034 | } |
| 3035 | } else { |
| 3036 | $confirm_action_data = get_site_option( '_verify_' . $uid . '_' . $action_name, '' ); |
3031 | 3037 | |
3032 | | if ( ! $saved_key ) { |
3033 | | return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); |
| 3038 | if ( false !== strpos( $confirm_action_data, ':' ) ) { |
| 3039 | list( $key_request_time, $saved_key, $email ) = explode( ':', $confirm_action_data, 3 ); |
3034 | 3040 | } |
| 3041 | } |
3035 | 3042 | |
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 | | } |
| 3043 | if ( ! $saved_key ) { |
| 3044 | return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); |
| 3045 | } |
3053 | 3046 | |
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 | | } |
| 3047 | /** |
| 3048 | * Filters the expiration time of confirm keys. |
| 3049 | * |
| 3050 | * @since 5.0.0 |
| 3051 | * |
| 3052 | * @param int $expiration The expiration time in seconds. |
| 3053 | */ |
| 3054 | $expiration_duration = apply_filters( 'account_verification_expiration', DAY_IN_SECONDS ); |
| 3055 | $expiration_time = $key_request_time + $expiration_duration; |
3060 | 3056 | |
3061 | | return $return; |
3062 | | } |
| 3057 | if ( ! $wp_hasher->CheckPassword( $key, $saved_key ) ) { |
| 3058 | return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); |
3063 | 3059 | } |
3064 | 3060 | |
3065 | | return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); |
3066 | | } |
| 3061 | if ( $expiration_time && time() < $expiration_time ) { |
| 3062 | $return = array( |
| 3063 | 'action' => $action_name, |
| 3064 | 'email' => $email, |
| 3065 | ); |
| 3066 | } else { |
| 3067 | $return = new WP_Error( 'expired_key', __( 'The confirmation email has expired.' ) ); |
| 3068 | } |
| 3069 | |
| 3070 | // Clean up stored keys. |
| 3071 | if ( $is_registered_user ) { |
| 3072 | delete_user_meta( $user->ID, '_verify_' . $action_name ); |
| 3073 | } else { |
| 3074 | delete_site_option( '_verify_' . $uid . '_' . $action_name ); |
| 3075 | } |
| 3076 | |
| 3077 | return $return; |
| 3078 | } |
| 3079 | No newline at end of file |
diff --git wp-login.php wp-login.php
index 349f232443..815b44fbad 100644
|
|
if ( isset( $_GET['key'] ) ) { |
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 | |
… |
… |
switch ( $action ) { |
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 | } |
… |
… |
switch ( $action ) { |
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 ); |
… |
… |
switch ( $action ) { |
887 | 889 | * Using this you can assume the user has agreed to perform the action by |
888 | 890 | * clicking on the link in the confirmation email. |
889 | 891 | * |
890 | | * After firing this action hook the page will redirect to wp-login a callback |
| 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 | * |