From aa1e377edea1173f53b707c72045b4efabf17eab Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 14 Sep 2009 13:57:48 +0000 Subject: [PATCH] Filter fields through kses upon display. Introduce sanitize_user_object() and sanitize_user_field(). see #10751 git-svn-id: http://svn.automattic.com/wordpress/trunk@11929 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/includes/template.php | 1 + wp-admin/includes/user.php | 105 +++++++++++++--------------- wp-admin/user-edit.php | 13 ++-- wp-admin/users.php | 8 --- wp-includes/capabilities.php | 9 +++ wp-includes/default-filters.php | 30 +++++--- wp-includes/formatting.php | 56 ++++++++++++++- wp-includes/registration.php | 7 +- wp-includes/user.php | 117 ++++++++++++++++++++++++++++++++ 9 files changed, 260 insertions(+), 86 deletions(-) diff --git a/wp-admin/includes/template.php b/wp-admin/includes/template.php index e3db22a30..364c703e4 100644 --- a/wp-admin/includes/template.php +++ b/wp-admin/includes/template.php @@ -1892,6 +1892,7 @@ function user_row( $user_object, $style = '', $role = '' ) { if ( !( is_object( $user_object) && is_a( $user_object, 'WP_User' ) ) ) $user_object = new WP_User( (int) $user_object ); + $user_object = sanitize_user_object($user_object, 'display'); $email = $user_object->user_email; $url = $user_object->user_url; $short_url = str_replace( 'http://', '', $url ); diff --git a/wp-admin/includes/user.php b/wp-admin/includes/user.php index 789d26d8d..588370323 100644 --- a/wp-admin/includes/user.php +++ b/wp-admin/includes/user.php @@ -25,15 +25,16 @@ function add_user() { $user_id = (int) func_get_arg( 0 ); if ( isset( $_POST['role'] ) ) { + $new_role = sanitize_text_field( $_POST['role'] ); // Don't let anyone with 'edit_users' (admins) edit their own role to something without it. - if( $user_id != $current_user->id || $wp_roles->role_objects[$_POST['role']]->has_cap( 'edit_users' ) ) { + if ( $user_id != $current_user->id || $wp_roles->role_objects[$new_role]->has_cap( 'edit_users' ) ) { // If the new role isn't editable by the logged-in user die with error $editable_roles = get_editable_roles(); - if (!$editable_roles[$_POST['role']]) + if ( !$editable_roles[$new_role] ) wp_die(__('You can’t give users that role.')); $user = new WP_User( $user_id ); - $user->set_role( $_POST['role'] ); + $user->set_role( $new_role ); } } } else { @@ -64,8 +65,8 @@ function edit_user( $user_id = 0 ) { $user = ''; } - if ( isset( $_POST['user_login'] )) - $user->user_login = esc_html( trim( $_POST['user_login'] )); + if ( !$update && isset( $_POST['user_login'] ) ) + $user->user_login = sanitize_user($userdata['user_login'], true); $pass1 = $pass2 = ''; if ( isset( $_POST['pass1'] )) @@ -74,62 +75,55 @@ function edit_user( $user_id = 0 ) { $pass2 = $_POST['pass2']; if ( isset( $_POST['role'] ) && current_user_can( 'edit_users' ) ) { - + $new_role = sanitize_text_field( $_POST['role'] ); // Don't let anyone with 'edit_users' (admins) edit their own role to something without it. - if( $user_id != $current_user->id || $wp_roles->role_objects[$_POST['role']]->has_cap( 'edit_users' )) - $user->role = $_POST['role']; + if( $user_id != $current_user->id || $wp_roles->role_objects[$new_role]->has_cap( 'edit_users' )) + $user->role = $new_role; // If the new role isn't editable by the logged-in user die with error $editable_roles = get_editable_roles(); - if (!$editable_roles[$_POST['role']]) + if ( !$editable_roles[$new_role] ) wp_die(__('You can’t give users that role.')); } if ( isset( $_POST['email'] )) - $user->user_email = esc_html( trim( $_POST['email'] )); + $user->user_email = sanitize_text_field( $_POST['email'] ); if ( isset( $_POST['url'] ) ) { if ( empty ( $_POST['url'] ) || $_POST['url'] == 'http://' ) { $user->user_url = ''; } else { - $user->user_url = esc_url( trim( $_POST['url'] )); + $user->user_url = sanitize_url( $_POST['url'] ); $user->user_url = preg_match('/^(https?|ftps?|mailto|news|irc|gopher|nntp|feed|telnet):/is', $user->user_url) ? $user->user_url : 'http://'.$user->user_url; } } - if ( isset( $_POST['first_name'] )) - $user->first_name = esc_html( trim( $_POST['first_name'] )); - if ( isset( $_POST['last_name'] )) - $user->last_name = esc_html( trim( $_POST['last_name'] )); - if ( isset( $_POST['nickname'] )) - $user->nickname = esc_html( trim( $_POST['nickname'] )); - if ( isset( $_POST['display_name'] )) - $user->display_name = esc_html( trim( $_POST['display_name'] )); - if ( isset( $_POST['description'] )) - $user->description = trim( $_POST['description'] ); - $user_contactmethods = _wp_get_user_contactmethods(); - foreach ($user_contactmethods as $method => $name) { - if ( isset( $_POST[$method] )) - $user->$method = esc_html( trim( $_POST[$method] ) ); - } - if ( !$update ) - $user->rich_editing = 'true'; // Default to true for new users. - else if ( isset( $_POST['rich_editing'] ) ) - $user->rich_editing = $_POST['rich_editing']; - else - $user->rich_editing = 'true'; + if ( isset( $_POST['first_name'] ) ) + $user->first_name = sanitize_text_field( $_POST['first_name'] ); + if ( isset( $_POST['last_name'] ) ) + $user->last_name = sanitize_text_field( $_POST['last_name'] ); + if ( isset( $_POST['nickname'] ) ) + $user->nickname = sanitize_text_field( $_POST['nickname'] ); + if ( isset( $_POST['display_name'] ) ) + $user->display_name = sanitize_text_field( $_POST['display_name'] ); - $user->comment_shortcuts = isset( $_POST['comment_shortcuts'] )? $_POST['comment_shortcuts'] : ''; + if ( isset( $_POST['description'] ) ) + $user->description = trim( $_POST['description'] ); + + foreach ( _wp_get_user_contactmethods() as $method => $name ) { + if ( isset( $_POST[$method] )) + $user->$method = sanitize_text_field( $_POST[$method] ); + } + + if ( $update ) { + $user->rich_editing = isset( $_POST['rich_editing'] ) && 'false' == $_POST['rich_editing'] ? 'false' : 'true'; + $user->admin_color = isset( $_POST['admin_color'] ) ? sanitize_text_field( $_POST['admin_color'] ) : 'fresh'; + } + + $user->comment_shortcuts = isset( $_POST['comment_shortcuts'] ) && 'true' == $_POST['comment_shortcuts'] ? 'true' : ''; $user->use_ssl = 0; if ( !empty($_POST['use_ssl']) ) $user->use_ssl = 1; - if ( !$update ) - $user->admin_color = 'fresh'; // Default to fresh for new users. - else if ( isset( $_POST['admin_color'] ) ) - $user->admin_color = $_POST['admin_color']; - else - $user->admin_color = 'fresh'; - $errors = new WP_Error(); /* checking that username has been typed */ @@ -159,34 +153,34 @@ function edit_user( $user_id = 0 ) { if ( $pass1 != $pass2 ) $errors->add( 'pass', __( 'ERROR: Please enter the same password in the two password fields.' ), array( 'form-field' => 'pass1' ) ); - if (!empty ( $pass1 )) + if ( !empty( $pass1 ) ) $user->user_pass = $pass1; if ( !$update && !validate_username( $user->user_login ) ) $errors->add( 'user_login', __( 'ERROR: This username is invalid. Please enter a valid username.' )); - if (!$update && username_exists( $user->user_login )) + if ( !$update && username_exists( $user->user_login ) ) $errors->add( 'user_login', __( 'ERROR: This username is already registered. Please choose another one.' )); /* checking e-mail address */ - if ( empty ( $user->user_email ) ) { + if ( empty( $user->user_email ) ) { $errors->add( 'empty_email', __( 'ERROR: Please enter an e-mail address.' ), array( 'form-field' => 'email' ) ); - } elseif (!is_email( $user->user_email ) ) { + } elseif ( !is_email( $user->user_email ) ) { $errors->add( 'invalid_email', __( 'ERROR: The e-mail address isn’t correct.' ), array( 'form-field' => 'email' ) ); } elseif ( ( $owner_id = email_exists($user->user_email) ) && $owner_id != $user->ID ) { $errors->add( 'email_exists', __('ERROR: This email is already registered, please choose another one.'), array( 'form-field' => 'email' ) ); } - // Allow plugins to return there own errors. + // Allow plugins to return their own errors. do_action_ref_array('user_profile_update_errors', array ( &$errors, $update, &$user ) ); if ( $errors->get_error_codes() ) return $errors; if ( $update ) { - $user_id = wp_update_user( get_object_vars( $user )); + $user_id = wp_update_user( get_object_vars( $user ) ); } else { - $user_id = wp_insert_user( get_object_vars( $user )); + $user_id = wp_insert_user( get_object_vars( $user ) ); wp_new_user_notification( $user_id, isset($_POST['send_password']) ? $pass1 : '' ); } return $user_id; @@ -370,20 +364,17 @@ function get_others_pending($user_id) { */ function get_user_to_edit( $user_id ) { $user = new WP_User( $user_id ); - $user->user_login = esc_attr($user->user_login); - $user->user_email = esc_attr($user->user_email); - $user->user_url = esc_url($user->user_url); - $user->first_name = esc_attr($user->first_name); - $user->last_name = esc_attr($user->last_name); - $user->display_name = esc_attr($user->display_name); - $user->nickname = esc_attr($user->nickname); $user_contactmethods = _wp_get_user_contactmethods(); foreach ($user_contactmethods as $method => $name) { - $user->{$method} = isset( $user->{$method} ) && !empty( $user->{$method} ) ? esc_attr($user->{$method}) : ''; + if ( empty( $user->{$method} ) ) + $user->{$method} = ''; } - - $user->description = isset( $user->description ) && !empty( $user->description ) ? esc_html($user->description) : ''; + + if ( empty($user->description) ) + $user->description = ''; + + $user = sanitize_user_object($user, 'edit'); return $user; } diff --git a/wp-admin/user-edit.php b/wp-admin/user-edit.php index 260868e8f..a8173a504 100644 --- a/wp-admin/user-edit.php +++ b/wp-admin/user-edit.php @@ -284,7 +284,7 @@ else - @@ -311,16 +311,17 @@ if ( $show_password_fields ) : } ?> -caps) > count($profileuser->roles) && apply_filters('additional_capabilities_display', true, $profileuser)): ?> +caps) > count($profileuser->roles) && apply_filters('additional_capabilities_display', true, $profileuser) ) { ?>

+

caps as $cap => $value) { - if(!$wp_roles->is_role($cap)) { - if($output != '') $output .= ', '; + foreach ( $profileuser->caps as $cap => $value ) { + if ( !$wp_roles->is_role($cap) ) { + if ( $output != '' ) + $output .= ', '; $output .= $value ? $cap : "Denied: {$cap}"; } } @@ -328,7 +329,7 @@ if ( $show_password_fields ) : ?>
- +

diff --git a/wp-admin/users.php b/wp-admin/users.php index d32e298d5..c8d749716 100644 --- a/wp-admin/users.php +++ b/wp-admin/users.php @@ -385,14 +385,6 @@ foreach ( $wp_user_search->get_results() as $userid ) { - 'user_login', 'first_name' => 'user_firstname', 'last_name' => 'user_lastname', 'email' => 'user_email', 'url' => 'user_uri', 'role' => 'user_role') as $formpost => $var ) { - $var = 'new_' . $var; - $$var = isset($_REQUEST[$formpost]) ? esc_attr(stripslashes($_REQUEST[$formpost])) : ''; - } - unset($name); -?> -
]*?>.*?@si', '', $string ); + $string = strip_tags($string); + + if ( $remove_breaks ) + $string = preg_replace('/\s+/', ' ', $string); + + return trim($string); +} + +/** + * Sanitize a string from user input or from the db + * + * check for invalid UTF-8, + * Convert single < characters to entity, + * strip all tags, + * remove line breaks, tabs and extra whitre space, + * strip octets. + * + * @since 2.9 + * + * @param string $str + * @return string + */ +function sanitize_text_field($str) { + $filtered = wp_check_invalid_utf8( $str ); + + if ( strpos($filtered, '<') !== false ) { + $filtered = wp_pre_kses_less_than( $filtered ); + $filtered = wp_strip_all_tags( $filtered, true ); + } else { + $filtered = trim( preg_replace('/\s+/', ' ', $filtered) ); + } + + $match = array(); + while ( preg_match('/%[a-f0-9]{2}/i', $filtered, $match) ) + $filtered = str_replace($match[0], '', $filtered); + + return apply_filters('sanitize_text_field', $filtered, $str); +} + ?> diff --git a/wp-includes/registration.php b/wp-includes/registration.php index c71708a09..359885373 100644 --- a/wp-includes/registration.php +++ b/wp-includes/registration.php @@ -169,7 +169,7 @@ function wp_insert_user($userdata) { $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $user_nicename, $user_login)); - if ($user_nicename_check) { + if ( $user_nicename_check ) { $suffix = 2; while ($user_nicename_check) { $alt_user_nicename = $user_nicename . "-$suffix"; @@ -198,10 +198,11 @@ function wp_insert_user($userdata) { update_usermeta( $user_id, 'comment_shortcuts', $comment_shortcuts); update_usermeta( $user_id, 'admin_color', $admin_color); update_usermeta( $user_id, 'use_ssl', $use_ssl); - foreach (_wp_get_user_contactmethods() as $method => $name) { + + foreach ( _wp_get_user_contactmethods() as $method => $name ) { if ( empty($$method) ) $$method = ''; - + update_usermeta( $user_id, $method, $$method ); } diff --git a/wp-includes/user.php b/wp-includes/user.php index 9454b4ac7..8e971c11f 100644 --- a/wp-includes/user.php +++ b/wp-includes/user.php @@ -617,4 +617,121 @@ function _fill_user( &$user ) { wp_cache_add($user->user_nicename, $user->ID, 'userslugs'); } +/** + * Sanitize every user field. + * + * If the context is 'raw', then the user object or array will get minimal santization of the int fields. + * + * @since 2.3.0 + * @uses sanitize_user_field() Used to sanitize the fields. + * + * @param object|array $user The User Object or Array + * @param string $context Optional, default is 'display'. How to sanitize user fields. + * @return object|array The now sanitized User Object or Array (will be the same type as $user) + */ +function sanitize_user_object($user, $context = 'display') { + if ( is_object($user) ) { + if ( !isset($user->ID) ) + $user->ID = 0; + if ( isset($user->data) ) + $vars = get_object_vars( $user->data ); + else + $vars = get_object_vars($user); + foreach ( array_keys($vars) as $field ) { + if ( is_array($user->$field) ) + continue; + $user->$field = sanitize_user_field($field, $user->$field, $user->ID, $context); + } + $user->filter = $context; + } else { + if ( !isset($user['ID']) ) + $user['ID'] = 0; + foreach ( array_keys($user) as $field ) + $user[$field] = sanitize_user_field($field, $user[$field], $user['ID'], $context); + $user['filter'] = $context; + } + + return $user; +} + +/** + * Sanitize user field based on context. + * + * Possible context values are: 'raw', 'edit', 'db', 'display', 'attribute' and 'js'. The + * 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display' + * when calling filters. + * + * @since 2.3.0 + * @uses apply_filters() Calls 'edit_$field' and '${field_no_prefix}_edit_pre' passing $value and + * $user_id if $context == 'edit' and field name prefix == 'user_'. + * + * @uses apply_filters() Calls 'edit_user_$field' passing $value and $user_id if $context == 'db'. + * @uses apply_filters() Calls 'pre_$field' passing $value if $context == 'db' and field name prefix == 'user_'. + * @uses apply_filters() Calls '${field}_pre' passing $value if $context == 'db' and field name prefix != 'user_'. + * + * @uses apply_filters() Calls '$field' passing $value, $user_id and $context if $context == anything + * other than 'raw', 'edit' and 'db' and field name prefix == 'user_'. + * @uses apply_filters() Calls 'user_$field' passing $value if $context == anything other than 'raw', + * 'edit' and 'db' and field name prefix != 'user_'. + * + * @param string $field The user Object field name. + * @param mixed $value The user Object value. + * @param int $user_id user ID. + * @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display', + * 'attribute' and 'js'. + * @return mixed Sanitized value. + */ +function sanitize_user_field($field, $value, $user_id, $context) { + $int_fields = array('ID'); + if ( in_array($field, $int_fields) ) + $value = (int) $value; + + if ( 'raw' == $context ) + return $value; + + if ( is_array($value) ) + return $value; + + $prefixed = false; + if ( false !== strpos($field, 'user_') ) { + $prefixed = true; + $field_no_prefix = str_replace('user_', '', $field); + } + + if ( 'edit' == $context ) { + if ( $prefixed ) { + $value = apply_filters("edit_$field", $value, $user_id); + } else { + $value = apply_filters("edit_user_$field", $value, $user_id); + } + + if ( 'description' == $field ) + $value = esc_html($value); + else + $value = esc_attr($value); + } else if ( 'db' == $context ) { + if ( $prefixed ) { + $value = apply_filters("pre_$field", $value); + } else { + $value = apply_filters("pre_user_$field", $value); + } + } else { + // Use display filters by default. + if ( $prefixed ) + $value = apply_filters($field, $value, $user_id, $context); + else + $value = apply_filters("user_$field", $value, $user_id, $context); + } + + if ( 'user_url' == $field ) + $value = esc_url($value); + + if ( 'attribute' == $context ) + $value = esc_attr($value); + else if ( 'js' == $context ) + $value = esc_js($value); + + return $value; +} + ?>