Changeset 43083
- Timestamp:
- 05/02/2018 01:00:46 AM (6 years ago)
- Location:
- branches/4.9
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/4.9
-
branches/4.9/src/wp-admin/includes/admin-filters.php
r43071 r43083 47 47 48 48 // Privacy tools 49 add_action( 'account_action_failed', '_wp_privacy_account_request_failed' );50 49 add_action( 'admin_menu', '_wp_privacy_hook_requests_page' ); 51 50 -
branches/4.9/src/wp-admin/includes/ajax-actions.php
r43075 r43083 4156 4156 // Find the request CPT 4157 4157 $request = get_post( $request_id ); 4158 if ( ' user_remove_request' !== $request->post_type ) {4158 if ( 'remove_personal_data' !== $request->post_title ) { 4159 4159 wp_send_json_error( __( 'Error: Invalid request ID.' ) ); 4160 4160 } 4161 4161 4162 $email_address = get_post_meta( $request_id, '_ user_email', true );4162 $email_address = get_post_meta( $request_id, '_wp_user_request_user_email', true ); 4163 4163 4164 4164 if ( ! is_email( $email_address ) ) { -
branches/4.9/src/wp-admin/includes/user.php
r43075 r43083 541 541 542 542 /** 543 * Get action description from the name.543 * Resend an existing request and return the result. 544 544 * 545 545 * @since 4.9.6 546 546 * @access private 547 547 * 548 * @return string 549 */ 550 function _wp_privacy_action_description( $request_type ) { 551 switch ( $request_type ) { 552 case 'user_export_request': 553 return __( 'Export Personal Data' ); 554 case 'user_remove_request': 555 return __( 'Remove Personal Data' ); 556 } 557 } 558 559 /** 560 * Log a request and send to the user. 561 * 562 * @since 4.9.6 563 * @access private 564 * 565 * @param string $email_address Email address sending the request to. 566 * @param string $action Action being requested. 567 * @param string $description Description of request. 568 * @return bool|WP_Error depending on success. 569 */ 570 function _wp_privacy_create_request( $email_address, $action, $description ) { 571 $user_id = 0; 572 $user = get_user_by( 'email', $email_address ); 573 574 if ( $user ) { 575 $user_id = $user->ID; 576 } 577 578 $privacy_request_id = wp_insert_post( array( 579 'post_author' => $user_id, 580 'post_status' => 'request-pending', 581 'post_type' => $action, 582 'post_date' => current_time( 'mysql', false ), 583 'post_date_gmt' => current_time( 'mysql', true ), 584 ), true ); 585 586 if ( is_wp_error( $privacy_request_id ) ) { 587 return $privacy_request_id; 588 } 589 590 update_post_meta( $privacy_request_id, '_user_email', $email_address ); 591 update_post_meta( $privacy_request_id, '_action_name', $action ); 592 update_post_meta( $privacy_request_id, '_confirmed_timestamp', false ); 593 594 return wp_send_account_verification_key( $email_address, $action, $description, array( 595 'privacy_request_id' => $privacy_request_id, 596 ) ); 597 } 598 599 /** 600 * Resend an existing request and return the result. 601 * 602 * @since 4.9.6 603 * @access private 604 * 605 * @param int $privacy_request_id Request ID. 548 * @param int $request_id Request ID. 606 549 * @return bool|WP_Error 607 550 */ 608 function _wp_privacy_resend_request( $ privacy_request_id ) {609 $ privacy_request_id = absint( $privacy_request_id );610 $ privacy_request = get_post( $privacy_request_id );611 612 if ( ! $ privacy_request || ! in_array( $privacy_request->post_type, _wp_privacy_action_request_types(), true )) {551 function _wp_privacy_resend_request( $request_id ) { 552 $request_id = absint( $request_id ); 553 $request = get_post( $request_id ); 554 555 if ( ! $request || 'user_request' !== $request->post_type ) { 613 556 return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) ); 614 557 } 615 558 616 $email_address = get_post_meta( $privacy_request_id, '_user_email', true ); 617 $action = get_post_meta( $privacy_request_id, '_action_name', true ); 618 $description = _wp_privacy_action_description( $action ); 619 $result = wp_send_account_verification_key( $email_address, $action, $description, array( 620 'privacy_request_id' => $privacy_request_id, 621 ) ); 559 $result = wp_send_user_request( $request_id ); 622 560 623 561 if ( is_wp_error( $result ) ) { … … 627 565 } 628 566 629 wp_update_post( array(630 'ID' => $privacy_request_id,631 'post_status' => 'request-pending',632 'post_date' => current_time( 'mysql', false ),633 'post_date_gmt' => current_time( 'mysql', true ),634 ) );635 636 567 return true; 637 568 } … … 643 574 * @access private 644 575 * 645 * @param int $ privacy_request_id Request ID.646 * @return bool|WP_Error647 */ 648 function _wp_privacy_completed_request( $ privacy_request_id ) {649 $ privacy_request_id = absint( $privacy_request_id );650 $ privacy_request = get_post( $privacy_request_id );651 652 if ( ! $ privacy_request || ! in_array( $privacy_request->post_type, _wp_privacy_action_request_types(), true )) {576 * @param int $request_id Request ID. 577 * @return int|WP_Error Request ID on succes or WP_Error. 578 */ 579 function _wp_privacy_completed_request( $request_id ) { 580 $request_id = absint( $request_id ); 581 $request_data = wp_get_user_request_data( $request_id ); 582 583 if ( ! $request_data ) { 653 584 return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) ); 654 585 } 655 586 656 wp_update_post( array( 657 'ID' => $privacy_request_id, 658 'post_status' => 'request-completed', 587 update_post_meta( $request_id, '_wp_user_request_confirmed_timestamp', time() ); 588 $request = wp_update_post( array( 589 'ID' => $request_data['request_id'], 590 'post_status' => 'request-confirmed', 659 591 ) ); 660 661 update_post_meta( $privacy_request_id, '_completed_timestamp', time() ); 592 return $request; 662 593 } 663 594 … … 763 694 } 764 695 765 if ( ! empty( $email_address ) ) { 766 $result = _wp_privacy_create_request( $email_address, $action_type, _wp_privacy_action_description( $action_type ) ); 767 768 if ( is_wp_error( $result ) ) { 769 add_settings_error( 770 'username_or_email_to_export', 771 'username_or_email_to_export', 772 $result->get_error_message(), 773 'error' 774 ); 775 } elseif ( ! $result ) { 776 add_settings_error( 777 'username_or_email_to_export', 778 'username_or_email_to_export', 779 __( 'Unable to initiate confirmation request.' ), 780 'error' 781 ); 782 } else { 783 add_settings_error( 784 'username_or_email_to_export', 785 'username_or_email_to_export', 786 __( 'Confirmation request initiated successfully.' ), 787 'updated' 788 ); 789 } 696 if ( empty( $email_address ) ) { 697 break; 790 698 } 699 700 $request_id = wp_create_user_request( $email_address, $action_type ); 701 702 if ( is_wp_error( $request_id ) ) { 703 add_settings_error( 704 'username_or_email_to_export', 705 'username_or_email_to_export', 706 $request_id->get_error_message(), 707 'error' 708 ); 709 break; 710 } elseif ( ! $request_id ) { 711 add_settings_error( 712 'username_or_email_to_export', 713 'username_or_email_to_export', 714 __( 'Unable to initiate confirmation request.' ), 715 'error' 716 ); 717 break; 718 } 719 720 wp_send_user_request( $request_id ); 721 722 add_settings_error( 723 'username_or_email_to_export', 724 'username_or_email_to_export', 725 __( 'Confirmation request initiated successfully.' ), 726 'updated' 727 ); 791 728 break; 792 729 } … … 831 768 <?php wp_nonce_field( 'personal-data-request' ); ?> 832 769 <input type="hidden" name="action" value="add_export_personal_data_request" /> 833 <input type="hidden" name="type_of_action" value=" user_export_request" />770 <input type="hidden" name="type_of_action" value="export_personal_data" /> 834 771 </form> 835 772 <hr /> … … 897 834 <?php wp_nonce_field( 'personal-data-request' ); ?> 898 835 <input type="hidden" name="action" value="add_remove_personal_data_request" /> 899 <input type="hidden" name="type_of_action" value=" user_remove_request" />836 <input type="hidden" name="type_of_action" value="remove_personal_data" /> 900 837 </form> 901 838 <hr /> … … 971 908 public function get_columns() { 972 909 $columns = array( 973 'cb' => '<input type="checkbox" />',974 'email' => __( 'Requester' ),975 'status' => __( 'Status' ),976 'requested '=> __( 'Requested' ),977 'next_steps' => __( 'Next Steps' ),910 'cb' => '<input type="checkbox" />', 911 'email' => __( 'Requester' ), 912 'status' => __( 'Status' ), 913 'requested_timestamp' => __( 'Requested' ), 914 'next_steps' => __( 'Next Steps' ), 978 915 ); 979 916 return $columns; … … 1000 937 protected function get_default_primary_column_name() { 1001 938 return 'email'; 939 } 940 941 /** 942 * Count number of requests for each status. 943 * 944 * @since 4.9.6 945 * 946 * @return object Number of posts for each status. 947 */ 948 protected function get_request_counts() { 949 global $wpdb; 950 951 $cache_key = $this->post_type . '-' . $this->request_type; 952 $counts = wp_cache_get( $cache_key, 'counts' ); 953 954 if ( false !== $counts ) { 955 return $counts; 956 } 957 958 $query = " 959 SELECT post_status, COUNT( * ) AS num_posts 960 FROM {$wpdb->posts} 961 WHERE post_type = %s 962 AND post_title = %s 963 GROUP BY post_status"; 964 965 $results = (array) $wpdb->get_results( $wpdb->prepare( $query, $this->post_type, $this->request_type ), ARRAY_A ); 966 $counts = array_fill_keys( get_post_stati(), 0 ); 967 968 foreach ( $results as $row ) { 969 $counts[ $row['post_status'] ] = $row['num_posts']; 970 } 971 972 $counts = (object) $counts; 973 wp_cache_set( $cache_key, $counts, 'counts' ); 974 975 return $counts; 1002 976 } 1003 977 … … 1015 989 $views = array(); 1016 990 $admin_url = admin_url( 'tools.php?page=' . $this->request_type ); 1017 $counts = wp_count_posts( $this->post_type);991 $counts = $this->get_request_counts(); 1018 992 1019 993 $current_link_attributes = empty( $current_status ) ? ' class="current" aria-current="page"' : ''; … … 1050 1024 $action = $this->current_action(); 1051 1025 $request_ids = isset( $_REQUEST['request_id'] ) ? wp_parse_id_list( wp_unslash( $_REQUEST['request_id'] ) ) : array(); // WPCS: input var ok, CSRF ok. 1026 $count = 0; 1052 1027 1053 1028 if ( $request_ids ) { … … 1057 1032 switch ( $action ) { 1058 1033 case 'delete': 1059 $count = 0;1060 1061 1034 foreach ( $request_ids as $request_id ) { 1062 1035 if ( wp_delete_post( $request_id, true ) ) { … … 1073 1046 break; 1074 1047 case 'resend': 1075 $count = 0;1076 1077 1048 foreach ( $request_ids as $request_id ) { 1078 if ( _wp_privacy_resend_request( $request_id ) ) { 1079 $count ++; 1049 $resend = _wp_privacy_resend_request( $request_id ); 1050 1051 if ( $resend && ! is_wp_error( $resend ) ) { 1052 $count++; 1080 1053 } 1081 1054 } … … 1111 1084 $args = array( 1112 1085 'post_type' => $this->post_type, 1086 'title' => $this->request_type, 1113 1087 'posts_per_page' => $posts_per_page, 1114 1088 'offset' => isset( $_REQUEST['paged'] ) ? max( 0, absint( $_REQUEST['paged'] ) - 1 ) * $posts_per_page: 0, … … 1126 1100 'relation' => 'AND', 1127 1101 array( 1128 'key' => '_ user_email',1102 'key' => '_wp_user_request_user_email', 1129 1103 'value' => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ): '', 1130 'compare' => 'LIKE' 1104 'compare' => 'LIKE', 1131 1105 ), 1132 1106 ); 1133 1107 } 1134 1108 1135 $privacy_requests_query = new WP_Query( $args ); 1136 $privacy_requests = $privacy_requests_query->posts; 1137 1138 foreach ( $privacy_requests as $privacy_request ) { 1139 $this->items[] = array( 1140 'request_id' => $privacy_request->ID, 1141 'user_id' => $privacy_request->post_author, 1142 'email' => get_post_meta( $privacy_request->ID, '_user_email', true ), 1143 'action' => get_post_meta( $privacy_request->ID, '_action_name', true ), 1144 'requested' => strtotime( $privacy_request->post_date_gmt ), 1145 'confirmed' => get_post_meta( $privacy_request->ID, '_confirmed_timestamp', true ), 1146 'completed' => get_post_meta( $privacy_request->ID, '_completed_timestamp', true ), 1147 ); 1109 $requests_query = new WP_Query( $args ); 1110 $requests = $requests_query->posts; 1111 1112 foreach ( $requests as $request ) { 1113 $this->items[] = wp_get_user_request_data( $request->ID ); 1148 1114 } 1149 1115 1150 1116 $this->set_pagination_args( 1151 1117 array( 1152 'total_items' => $ privacy_requests_query->found_posts,1118 'total_items' => $requests_query->found_posts, 1153 1119 'per_page' => $posts_per_page, 1154 1120 ) … … 1188 1154 switch ( $status ) { 1189 1155 case 'request-confirmed': 1190 $timestamp = $item['confirmed '];1156 $timestamp = $item['confirmed_timestamp']; 1191 1157 break; 1192 1158 case 'request-completed': 1193 $timestamp = $item['completed '];1159 $timestamp = $item['completed_timestamp']; 1194 1160 break; 1195 1161 } … … 1239 1205 $cell_value = $item[ $column_name ]; 1240 1206 1241 if ( in_array( $column_name, array( 'requested ' ), true ) ) {1207 if ( in_array( $column_name, array( 'requested_timestamp' ), true ) ) { 1242 1208 return $this->get_timestamp_as_date( $cell_value ); 1243 1209 } … … 1312 1278 * @var string $post_type The post type. 1313 1279 */ 1314 protected $post_type = 'user_ export_request';1280 protected $post_type = 'user_request'; 1315 1281 1316 1282 /** … … 1397 1363 * @var string $post_type The post type. 1398 1364 */ 1399 protected $post_type = 'user_re move_request';1365 protected $post_type = 'user_request'; 1400 1366 1401 1367 /** -
branches/4.9/src/wp-includes/default-filters.php
r43080 r43083 302 302 add_action( 'do_robots', 'do_robots' ); 303 303 add_action( 'set_comment_cookies', 'wp_set_comment_cookies', 10, 2 ); 304 add_filter( 'wp_privacy_personal_data_exporters', 'wp_register_comment_personal_data_exporter', 10 );305 add_filter( 'wp_privacy_personal_data_erasers', 'wp_register_comment_personal_data_eraser', 10 );306 304 add_action( 'sanitize_comment_cookies', 'sanitize_comment_cookies' ); 307 305 add_action( 'admin_print_scripts', 'print_emoji_detection_script' ); … … 323 321 add_action( 'welcome_panel', 'wp_welcome_panel' ); 324 322 323 // Privacy 324 add_action( 'user_request_action_confirmed', '_wp_privacy_account_request_confirmed' ); 325 add_filter( 'user_request_action_confirmed_message', '_wp_privacy_account_request_confirmed_message', 10, 2 ); 326 add_filter( 'wp_privacy_personal_data_exporters', 'wp_register_comment_personal_data_exporter' ); 327 add_filter( 'wp_privacy_personal_data_erasers', 'wp_register_comment_personal_data_eraser' ); 328 325 329 // Cron tasks 326 330 add_action( 'wp_scheduled_delete', 'wp_scheduled_delete' ); -
branches/4.9/src/wp-includes/post.php
r43071 r43083 211 211 ) ); 212 212 213 register_post_type( 'user_ export_request', array(213 register_post_type( 'user_request', array( 214 214 'labels' => array( 215 'name' => __( ' Export Personal DataRequests' ),216 'singular_name' => __( ' Export Personal DataRequest' ),215 'name' => __( 'User Requests' ), 216 'singular_name' => __( 'User Request' ), 217 217 ), 218 218 'public' => false, … … 223 223 'can_export' => false, 224 224 'delete_with_user' => false, 225 ) ); 226 227 register_post_type( 'user_remove_request', array( 228 'labels' => array( 229 'name' => __( 'Remove Personal Data Requests' ), 230 'singular_name' => __( 'Remove Personal Data Request' ), 231 ), 232 'public' => false, 233 '_builtin' => true, /* internal use only. don't use this when registering your own post type. */ 234 'hierarchical' => false, 235 'rewrite' => false, 236 'query_var' => false, 237 'can_export' => false, 238 'delete_with_user' => false, 225 'supports' => array(), 239 226 ) ); 240 227 -
branches/4.9/src/wp-includes/user.php
r43071 r43083 2736 2736 * Get all user privacy request types. 2737 2737 * 2738 * @since 5.0.02738 * @since 4.9.6 2739 2739 * @access private 2740 2740 * … … 2743 2743 function _wp_privacy_action_request_types() { 2744 2744 return array( 2745 ' user_export_request',2746 ' user_remove_request',2745 'export_personal_data', 2746 'remove_personal_data', 2747 2747 ); 2748 2748 } … … 2751 2751 * Update log when privacy request is confirmed. 2752 2752 * 2753 * @since 5.0.02753 * @since 4.9.6 2754 2754 * @access private 2755 2755 * 2756 * @param array $result Result of the request from the user. 2757 */ 2758 function _wp_privacy_account_request_confirmed( $result ) { 2759 if ( isset( $result['action'], $result['request_data'], $result['request_data']['privacy_request_id'] ) && in_array( $result['action'], _wp_privacy_action_request_types(), true ) ) { 2760 $privacy_request_id = absint( $result['request_data']['privacy_request_id'] ); 2761 $privacy_request = get_post( $privacy_request_id ); 2762 2763 if ( ! $privacy_request || ! in_array( $privacy_request->post_type, _wp_privacy_action_request_types(), true ) ) { 2764 return; 2765 } 2766 2767 update_post_meta( $privacy_request_id, '_confirmed_timestamp', time() ); 2756 * @param int $request_id ID of the request. 2757 */ 2758 function _wp_privacy_account_request_confirmed( $request_id ) { 2759 $request_data = wp_get_user_request_data( $request_id ); 2760 2761 if ( ! $request_data ) { 2762 return; 2763 } 2764 2765 if ( ! in_array( $request_data['status'], array( 'request-pending', 'request-failed' ), true ) ) { 2766 return; 2767 } 2768 2769 update_post_meta( $request_id, '_wp_user_request_confirmed_timestamp', time() ); 2770 wp_update_post( array( 2771 'ID' => $request_data['request_id'], 2772 'post_status' => 'request-confirmed', 2773 ) ); 2774 } 2775 2776 /** 2777 * Return request confirmation message HTML. 2778 * 2779 * @since 4.9.6 2780 * @access private 2781 * 2782 * @return string $message The confirmation message. 2783 */ 2784 function _wp_privacy_account_request_confirmed_message( $message, $request_id ) { 2785 $request = wp_get_user_request_data( $request_id ); 2786 2787 if ( $request && in_array( $request['action'], _wp_privacy_action_request_types(), true ) ) { 2788 $message = '<p class="message">' . __( 'Action has been confirmed.' ) . '</p>'; 2789 $message .= __( 'The site administrator has been notified and will fulfill your request as soon as possible.' ); 2790 } 2791 2792 return $message; 2793 } 2794 2795 /** 2796 * Create and log a user request to perform a specific action. 2797 * 2798 * Requests are stored inside a post type named `user_request` since they can apply to both 2799 * users on the site, or guests without a user account. 2800 * 2801 * @since 4.9.6 2802 * 2803 * @param string $email_address User email address. This can be the address of a registered or non-registered user. 2804 * @param string $action_name Name of the action that is being confirmed. Required. 2805 * @param array $request_data Misc data you want to send with the verification request and pass to the actions once the request is confirmed. 2806 * @return int|WP_Error Returns the request ID if successful, or a WP_Error object on failure. 2807 */ 2808 function wp_create_user_request( $email_address = '', $action_name = '', $request_data = array() ) { 2809 $email_address = sanitize_email( $email_address ); 2810 $action_name = sanitize_key( $action_name ); 2811 2812 if ( ! is_email( $email_address ) ) { 2813 return new WP_Error( 'invalid_email', __( 'Invalid email address' ) ); 2814 } 2815 2816 if ( ! $action_name ) { 2817 return new WP_Error( 'invalid_action', __( 'Invalid action name' ) ); 2818 } 2819 2820 $user = get_user_by( 'email', $email_address ); 2821 $user_id = $user && ! is_wp_error( $user ) ? $user->ID: 0; 2822 2823 // Check for duplicates. 2824 $requests_query = new WP_Query( array( 2825 'post_type' => 'user_request', 2826 'title' => $action_name, 2827 'post_status' => 'any', 2828 'fields' => 'ids', 2829 'meta_query' => array( 2830 array( 2831 'key' => '_wp_user_request_user_email', 2832 'value' => $email_address, 2833 ), 2834 ), 2835 ) ); 2836 2837 if ( $requests_query->found_posts ) { 2838 return new WP_Error( 'duplicate_request', __( 'A request for this email address already exists.' ) ); 2839 } 2840 2841 $request_id = wp_insert_post( array( 2842 'post_author' => $user_id, 2843 'post_title' => $action_name, 2844 'post_content' => wp_json_encode( $request_data ), 2845 'post_status' => 'request-pending', 2846 'post_type' => 'user_request', 2847 'post_date' => current_time( 'mysql', false ), 2848 'post_date_gmt' => current_time( 'mysql', true ), 2849 ), true ); 2850 2851 if ( is_wp_error( $request_id ) ) { 2852 return $request_id; 2853 } 2854 2855 update_post_meta( $request_id, '_wp_user_request_user_email', $email_address ); 2856 update_post_meta( $request_id, '_wp_user_request_confirmed_timestamp', false ); 2857 2858 return $request_id; 2859 } 2860 2861 /** 2862 * Get action description from the name and return a string. 2863 * 2864 * @since 4.9.6 2865 * 2866 * @param string $action_name Action name of the request. 2867 * @return string 2868 */ 2869 function wp_user_request_action_description( $action_name ) { 2870 switch ( $action_name ) { 2871 case 'export_personal_data': 2872 $description = __( 'Export Personal Data' ); 2873 break; 2874 case 'remove_personal_data': 2875 $description = __( 'Remove Personal Data' ); 2876 break; 2877 default: 2878 /* translators: %s: action name */ 2879 $description = sprintf( __( 'Confirm the "%s" action' ), $action_name ); 2880 break; 2881 } 2882 2883 /** 2884 * Filters the user action description. 2885 * 2886 * @param string $description The default description. 2887 * @param string $action_name The name of the request. 2888 */ 2889 return apply_filters( 'user_request_action_description', $description, $action_name ); 2890 } 2891 2892 /** 2893 * Send a confirmation request email to confirm an action. 2894 * 2895 * If the request is not already pending, it will be updated. 2896 * 2897 * @since 4.9.6 2898 * 2899 * @param string $request_id ID of the request created via wp_create_user_request(). 2900 * @return WP_Error|bool Will return true/false based on the success of sending the email, or a WP_Error object. 2901 */ 2902 function wp_send_user_request( $request_id ) { 2903 $request_id = absint( $request_id ); 2904 $request = get_post( $request_id ); 2905 2906 if ( ! $request || 'user_request' !== $request->post_type ) { 2907 return new WP_Error( 'user_request_error', __( 'Invalid request.' ) ); 2908 } 2909 2910 if ( 'request-pending' !== $request->post_status ) { 2768 2911 wp_update_post( array( 2769 'ID' => $privacy_request_id, 2770 'post_status' => 'request-confirmed', 2912 'ID' => $request_id, 2913 'post_status' => 'request-pending', 2914 'post_date' => current_time( 'mysql', false ), 2915 'post_date_gmt' => current_time( 'mysql', true ), 2771 2916 ) ); 2772 2917 } 2773 } 2774 add_action( 'account_action_confirmed', '_wp_privacy_account_request_confirmed' ); 2775 2776 /** 2777 * Update log when privacy request fails. 2778 * 2779 * @since 5.0.0 2780 * @access private 2781 * 2782 * @param array $result Result of the request from the user. 2783 */ 2784 function _wp_privacy_account_request_failed( $result ) { 2785 if ( isset( $result['action'], $result['request_data'], $result['request_data']['privacy_request_id'] ) && 2786 in_array( $result['action'], _wp_privacy_action_request_types(), true ) ) { 2787 2788 $privacy_request_id = absint( $result['request_data']['privacy_request_id'] ); 2789 $privacy_request = get_post( $privacy_request_id ); 2790 2791 if ( ! $privacy_request || ! in_array( $privacy_request->post_type, _wp_privacy_action_request_types(), true ) ) { 2792 return; 2793 } 2794 2795 wp_update_post( array( 2796 'ID' => $privacy_request_id, 2797 'post_status' => 'request-failed', 2798 ) ); 2799 } 2800 } 2801 2802 /** 2803 * Send a confirmation request email to confirm an action. 2804 * 2805 * @since 5.0.0 2806 * 2807 * @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. 2808 * @param string $action_name Name of the action that is being confirmed. Defaults to 'confirm_email'. 2809 * @param string $action_description User facing description of the action they will be confirming. Defaults to "confirm your email address". 2810 * @param array $request_data Misc data you want to send with the verification request and pass to the actions once the request is confirmed. 2811 * @return WP_Error|bool Will return true/false based on the success of sending the email, or a WP_Error object. 2812 */ 2813 function wp_send_account_verification_key( $email = '', $action_name = '', $action_description = '', $request_data = array() ) { 2814 if ( ! function_exists( 'wp_get_current_user' ) ) { 2815 return new WP_Error( 'invalid', __( 'This function cannot be used before init.' ) ); 2816 } 2817 2818 $action_name = sanitize_key( $action_name ); 2819 $action_description = wp_kses_post( $action_description ); 2820 2821 if ( empty( $action_name ) ) { 2822 $action_name = 'confirm_email'; 2823 } 2824 2825 if ( empty( $action_description ) ) { 2826 $action_description = __( 'Confirm your email address.' ); 2827 } 2828 2829 if ( empty( $email ) ) { 2830 $user = wp_get_current_user(); 2831 $email = $user->ID ? $user->user_email : ''; 2832 } else { 2833 $user = false; 2834 } 2835 2836 $email = sanitize_email( $email ); 2837 2838 if ( ! is_email( $email ) ) { 2839 return new WP_Error( 'invalid_email', __( 'Invalid email address' ) ); 2840 } 2841 2842 if ( ! $user ) { 2843 $user = get_user_by( 'email', $email ); 2844 } 2845 2846 $confirm_key = wp_get_account_verification_key( $email, $action_name, $request_data ); 2847 2848 if ( is_wp_error( $confirm_key ) ) { 2849 return $confirm_key; 2850 } 2851 2852 // We could be dealing with a registered user account, or a visitor. 2853 $is_registered_user = $user && ! is_wp_error( $user ); 2854 2855 if ( $is_registered_user ) { 2856 $uid = $user->ID; 2857 } else { 2858 // 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. 2859 $uid = function_exists( 'hash' ) ? hash( 'sha256', $email ) : sha1( $email ); 2860 } 2918 2919 $email_data = array( 2920 'action_name' => $request->post_title, 2921 'email' => get_post_meta( $request->ID, '_wp_user_request_user_email', true ), 2922 'description' => wp_user_request_action_description( $request->post_title ), 2923 'confirm_url' => add_query_arg( array( 2924 'action' => 'confirmaction', 2925 'request_id' => $request_id, 2926 'confirm_key' => wp_generate_user_request_key( $request_id ), 2927 ), site_url( 'wp-login.php' ) ), 2928 'sitename' => is_multisite() ? get_site_option( 'site_name' ) : get_option( 'blogname' ), 2929 'siteurl' => network_home_url(), 2930 ); 2861 2931 2862 2932 /* translators: Do not translate DESCRIPTION, CONFIRM_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */ … … 2879 2949 All at ###SITENAME### 2880 2950 ###SITEURL###' 2881 );2882 2883 $email_data = array(2884 'action_name' => $action_name,2885 'email' => $email,2886 'description' => $action_description,2887 'confirm_url' => add_query_arg( array(2888 'action' => 'verifyaccount',2889 'confirm_action' => $action_name,2890 'uid' => $uid,2891 'confirm_key' => $confirm_key,2892 ), site_url( 'wp-login.php' ) ),2893 'sitename' => is_multisite() ? get_site_option( 'site_name' ) : get_option( 'blogname' ),2894 'siteurl' => network_home_url(),2895 2951 ); 2896 2952 … … 2906 2962 * ###SITEURL### The URL to the site. 2907 2963 * 2908 * @since 5.0.02964 * @since 4.9.6 2909 2965 * 2910 2966 * @param string $email_text Text in the email. … … 2920 2976 * } 2921 2977 */ 2922 $content = apply_filters( ' account_verification_email_content', $email_text, $email_data );2978 $content = apply_filters( 'user_request_action_email_content', $email_text, $email_data ); 2923 2979 2924 2980 $content = str_replace( '###DESCRIPTION###', $email_data['description'], $content ); … … 2933 2989 2934 2990 /** 2935 * Creates, stores, then returns a confirmation key for an account action. 2936 * 2937 * @since 5.0.0 2938 * 2939 * @param string $email User email address. This can be the address of a registered or non-registered user. 2940 * @param string $action_name Name of the action this key is being generated for. 2941 * @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 * @return string|WP_Error Confirmation key on success. WP_Error on error. 2943 */ 2944 function wp_get_account_verification_key( $email, $action_name, $request_data = array() ) { 2991 * Returns a confirmation key for a user action and stores the hashed version. 2992 * 2993 * @since 4.9.6 2994 * 2995 * @param int $request_id Request ID. 2996 * @return string Confirmation key. 2997 */ 2998 function wp_generate_user_request_key( $request_id ) { 2945 2999 global $wp_hasher; 2946 2947 if ( ! is_email( $email ) ) {2948 return new WP_Error( 'invalid_email', __( 'Invalid email address' ) );2949 }2950 2951 if ( empty( $action_name ) ) {2952 return new WP_Error( 'invalid_action', __( 'Invalid action' ) );2953 }2954 2955 $user = get_user_by( 'email', $email );2956 2957 // We could be dealing with a registered user account, or a visitor.2958 $is_registered_user = $user && ! is_wp_error( $user );2959 3000 2960 3001 // Generate something random for a confirmation key. 2961 3002 $key = wp_generate_password( 20, false ); 2962 3003 2963 // Now insert the key, hashed, into the DB.3004 // Return the key, hashed. 2964 3005 if ( empty( $wp_hasher ) ) { 2965 3006 require_once ABSPATH . WPINC . '/class-phpass.php'; … … 2967 3008 } 2968 3009 2969 $hashed_key = $wp_hasher->HashPassword( $key ); 2970 $value = array( 2971 'action' => $action_name, 2972 'time' => time(), 2973 'hash' => $hashed_key, 2974 'email' => $email, 2975 'request_data' => $request_data, 2976 ); 2977 2978 if ( $is_registered_user ) { 2979 $key_saved = (bool) update_user_meta( $user->ID, '_verify_action_' . $action_name, wp_json_encode( $value ) ); 2980 } else { 2981 $uid = function_exists( 'hash' ) ? hash( 'sha256', $email ) : sha1( $email ); 2982 $key_saved = (bool) update_site_option( '_verify_action_' . $action_name . '_' . $uid, wp_json_encode( $value ) ); 2983 } 2984 2985 if ( false === $key_saved ) { 2986 return new WP_Error( 'no_account_verification_key_update', __( 'Could not save confirm account action key to database.' ) ); 2987 } 3010 update_post_meta( $request_id, '_wp_user_request_confirm_key', $wp_hasher->HashPassword( $key ) ); 3011 update_post_meta( $request_id, '_wp_user_request_confirm_key_timestamp', time() ); 2988 3012 2989 3013 return $key; … … 2991 3015 2992 3016 /** 2993 * Checks if a key is valid and handles the action based on this. 2994 * 2995 * @since 5.0.0 2996 * 2997 * @param string $key Key to confirm. 2998 * @param string $uid Email hash or user ID. 2999 * @param string $action_name Name of the action this key is being generated for. 3000 * @return array|WP_Error WP_Error on failure, action name and user email address on success. 3001 */ 3002 function wp_check_account_verification_key( $key, $uid, $action_name ) { 3017 * Valdate a user request by comparing the key with the request's key. 3018 * 3019 * @since 4.9.6 3020 * 3021 * @param string $request_id ID of the request being confirmed. 3022 * @param string $key Provided key to validate. 3023 * @return bool|WP_Error WP_Error on failure, true on success. 3024 */ 3025 function wp_validate_user_request_key( $request_id, $key ) { 3003 3026 global $wp_hasher; 3004 3027 3005 if ( empty( $action_name ) || empty( $key ) || empty( $uid ) ) { 3028 $request_id = absint( $request_id ); 3029 $request = wp_get_user_request_data( $request_id ); 3030 3031 if ( ! $request ) { 3032 return new WP_Error( 'user_request_error', __( 'Invalid request.' ) ); 3033 } 3034 3035 if ( ! in_array( $request['status'], array( 'request-pending', 'request-failed' ), true ) ) { 3036 return __( 'This link has expired.' ); 3037 } 3038 3039 if ( empty( $key ) ) { 3006 3040 return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); 3007 3041 } 3008 3009 $user = false;3010 3011 if ( is_numeric( $uid ) ) {3012 $user = get_user_by( 'id', absint( $uid ) );3013 }3014 3015 // We could be dealing with a registered user account, or a visitor.3016 $is_registered_user = ( $user && ! is_wp_error( $user ) );3017 $key_request_time = '';3018 $saved_key = '';3019 $email = '';3020 3042 3021 3043 if ( empty( $wp_hasher ) ) { … … 3024 3046 } 3025 3047 3026 // Get the saved key from the database. 3027 if ( $is_registered_user ) { 3028 $raw_data = get_user_meta( $user->ID, '_verify_action_' . $action_name, true ); 3029 $email = $user->user_email; 3030 3031 if ( false !== strpos( $raw_data, ':' ) ) { 3032 list( $key_request_time, $saved_key ) = explode( ':', $raw_data, 2 ); 3033 } 3034 } else { 3035 $raw_data = get_site_option( '_verify_action_' . $action_name . '_' . $uid, '' ); 3036 3037 if ( false !== strpos( $raw_data, ':' ) ) { 3038 list( $key_request_time, $saved_key, $email ) = explode( ':', $raw_data, 3 ); 3039 } 3040 } 3041 3042 $data = json_decode( $raw_data, true ); 3043 $key_request_time = (int) isset( $data['time'] ) ? $data['time'] : 0; 3044 $saved_key = isset( $data['hash'] ) ? $data['hash'] : ''; 3045 $email = sanitize_email( isset( $data['email'] ) ? $data['email'] : '' ); 3046 $request_data = isset( $data['request_data'] ) ? $data['request_data'] : array(); 3048 $key_request_time = $request['confirm_key_timestamp']; 3049 $saved_key = $request['confirm_key']; 3047 3050 3048 3051 if ( ! $saved_key ) { … … 3050 3053 } 3051 3054 3052 if ( ! $key_request_time || ! $email) {3055 if ( ! $key_request_time ) { 3053 3056 return new WP_Error( 'invalid_key', __( 'Invalid action' ) ); 3054 3057 } … … 3057 3060 * Filters the expiration time of confirm keys. 3058 3061 * 3059 * @since 5.0.03062 * @since 4.9.6 3060 3063 * 3061 3064 * @param int $expiration The expiration time in seconds. 3062 3065 */ 3063 $expiration_duration = apply_filters( 'account_verification_expiration', DAY_IN_SECONDS );3066 $expiration_duration = (int) apply_filters( 'user_request_key_expiration', DAY_IN_SECONDS ); 3064 3067 $expiration_time = $key_request_time + $expiration_duration; 3065 3068 … … 3068 3071 } 3069 3072 3070 if ( $expiration_time && time() < $expiration_time ) { 3071 $return = array( 3072 'action' => $action_name, 3073 'email' => $email, 3074 'request_data' => $request_data, 3075 ); 3076 } else { 3073 if ( ! $expiration_time || time() > $expiration_time ) { 3077 3074 $return = new WP_Error( 'expired_key', __( 'The confirmation email has expired.' ) ); 3078 3075 } 3079 3076 3080 // Clean up stored keys. 3081 if ( $is_registered_user ) { 3082 delete_user_meta( $user->ID, '_verify_action_' . $action_name ); 3083 } else { 3084 delete_site_option( '_verify_action_' . $action_name . '_' . $uid ); 3085 } 3086 3087 return $return; 3088 } 3077 return true; 3078 } 3079 3080 /** 3081 * Return data about a user request. 3082 * 3083 * @since 4.9.6 3084 * 3085 * @param int $request_id Request ID to get data about. 3086 * @return array|false 3087 */ 3088 function wp_get_user_request_data( $request_id ) { 3089 $request_id = absint( $request_id ); 3090 $request = get_post( $request_id ); 3091 3092 if ( ! $request || 'user_request' !== $request->post_type ) { 3093 return false; 3094 } 3095 3096 return array( 3097 'request_id' => $request->ID, 3098 'user_id' => $request->post_author, 3099 'email' => get_post_meta( $request->ID, '_wp_user_request_user_email', true ), 3100 'action' => $request->post_title, 3101 'requested_timestamp' => strtotime( $request->post_date_gmt ), 3102 'confirmed_timestamp' => get_post_meta( $request->ID, '_wp_user_request_confirmed_timestamp', true ), 3103 'completed_timestamp' => get_post_meta( $request->ID, '_wp_user_request_completed_timestamp', true ), 3104 'request_data' => json_decode( $request->post_content, true ), 3105 'status' => $request->post_status, 3106 'confirm_key' => get_post_meta( $request_id, '_wp_user_request_confirm_key', true ), 3107 'confirm_key_timestamp' => get_post_meta( $request_id, '_wp_user_request_confirm_key_timestamp', true ), 3108 ); 3109 } -
branches/4.9/src/wp-login.php
r43070 r43083 414 414 415 415 // validate action so as to default to the login screen 416 if ( !in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login', ' verifyaccount' ), true ) && false === has_filter( 'login_form_' . $action ) )416 if ( !in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login', 'confirmaction' ), true ) && false === has_filter( 'login_form_' . $action ) ) 417 417 $action = 'login'; 418 418 … … 839 839 break; 840 840 841 case 'verifyaccount' : 842 if ( isset( $_GET['confirm_action'], $_GET['confirm_key'], $_GET['uid'] ) ) { 843 $key = sanitize_text_field( wp_unslash( $_GET['confirm_key'] ) ); 844 $uid = sanitize_text_field( wp_unslash( $_GET['uid'] ) ); 845 $action_name = sanitize_key( wp_unslash( $_GET['confirm_action'] ) ); 846 $result = wp_check_account_verification_key( $key, $uid, $action_name ); 841 case 'confirmaction' : 842 if ( ! isset( $_GET['request_id'] ) ) { 843 wp_die( __( 'Invalid request' ) ); 844 } 845 846 $request_id = (int) $_GET['request_id']; 847 848 if ( isset( $_GET['confirm_key'] ) ) { 849 $key = sanitize_text_field( wp_unslash( $_GET['confirm_key'] ) ); 850 $result = wp_validate_user_request_key( $request_id, $key ); 847 851 } else { 848 852 $result = new WP_Error( 'invalid_key', __( 'Invalid key' ) ); … … 850 854 851 855 if ( is_wp_error( $result ) ) { 852 /**853 * Fires an action hook when the account action was not confirmed.854 *855 * After running this action hook the page will die.856 *857 * @param WP_Error $result Error object.858 */859 do_action( 'account_action_failed', $result );860 861 856 wp_die( $result ); 862 857 } … … 868 863 * clicking on the link in the confirmation email. 869 864 * 870 * After firing this action hook the page will redirect to wp-login a callback 865 * After firing this action hook the page will redirect to wp-login a callback 871 866 * redirects or exits first. 872 * 873 * @param array $result { 874 * Data about the action which was confirmed. 875 * 876 * @type string $action Name of the action that was confirmed. 877 * @type string $email Email of the user who confirmed the action. 878 * } 879 */ 880 do_action( 'account_action_confirmed', $result ); 881 882 $message = '<p class="message">' . __( 'Action has been confirmed.' ) . '</p>'; 883 login_header( '', $message ); 867 * 868 * @param int $request_id Request ID. 869 */ 870 do_action( 'user_request_action_confirmed', $request_id ); 871 872 $message = apply_filters( 'user_request_action_confirmed_message', '<p class="message">' . __( 'Action has been confirmed.' ) . '</p>', $request_id ); 873 874 login_header( __( 'User action confirmed.' ), $message ); 884 875 login_footer(); 885 876 exit;
Note: See TracChangeset
for help on using the changeset viewer.