WordPress.org

Make WordPress Core

Ticket #17904: 17904.4.diff

File 17904.4.diff, 17.4 KB (added by ericlewis, 4 years ago)
  • src/wp-admin/includes/user.php

     
    2020/**
    2121 * Edit user settings based on contents of $_POST
    2222 *
    23  * Used on user-edit.php and profile.php to manage and process user options, passwords etc.
     23 * Used on user-edit.php, user-new.php, and profile.php to manage and process user options, passwords etc.
    2424 *
    2525 * @since 2.0.0
    2626 *
     
    3939                $update = false;
    4040        }
    4141
    42         if ( !$update && isset( $_POST['user_login'] ) )
    43                 $user->user_login = sanitize_user($_POST['user_login'], true);
    44 
    4542        $pass1 = $pass2 = '';
    4643        if ( isset( $_POST['pass1'] ) )
    4744                $pass1 = $_POST['pass1'];
     
    104101
    105102        $errors = new WP_Error();
    106103
    107         /* checking that username has been typed */
    108         if ( $user->user_login == '' )
    109                 $errors->add( 'user_login', __( '<strong>ERROR</strong>: Please enter a username.' ) );
     104        /* Validate the user_login when not updating the user */
     105        if ( ! $update ) {
     106                $user_login = '';
    110107
     108                if ( isset( $_POST['user_login'] ) ) {
     109                        $user_login = $_POST['user_login'];
     110                }
     111
     112                $user->user_login = wp_validate_user_login( $user_login, $errors );
     113        }
     114
    111115        /* checking that nickname has been typed */
    112116        if ( $update && empty( $user->nickname ) ) {
    113117                $errors->add( 'nickname', __( '<strong>ERROR</strong>: Please enter a nickname.' ) );
     
    142146        if ( !empty( $pass1 ) )
    143147                $user->user_pass = $pass1;
    144148
    145         if ( !$update && isset( $_POST['user_login'] ) && !validate_username( $_POST['user_login'] ) )
    146                 $errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ));
    147 
    148         if ( !$update && username_exists( $user->user_login ) )
    149                 $errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ));
    150 
    151149        /** This filter is documented in wp-includes/user.php */
    152150        $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
    153151
  • src/wp-includes/ms-functions.php

     
    400400 *
    401401 * @global wpdb $wpdb WordPress database abstraction object.
    402402 *
    403  * @param string $user_name The login name provided by the user.
     403 * @param string $user_login The login name provided by the user.
    404404 * @param string $user_email The email provided by the user.
    405405 * @return array Contains username, email, and error messages.
    406406 */
    407 function wpmu_validate_user_signup($user_name, $user_email) {
     407function wpmu_validate_user_signup( $user_login, $user_email ) {
    408408        global $wpdb;
    409409
    410410        $errors = new WP_Error();
    411 
    412         $orig_username = $user_name;
    413         $user_name = preg_replace( '/\s+/', '', sanitize_user( $user_name, true ) );
    414 
    415         if ( $user_name != $orig_username || preg_match( '/[^a-z0-9]/', $user_name ) ) {
    416                 $errors->add( 'user_name', __( 'Usernames can only contain lowercase letters (a-z) and numbers.' ) );
    417                 $user_name = $orig_username;
    418         }
    419 
     411        $orig_userlogin = $user_login;
     412        $user_login = wp_validate_user_login( $user_login, $errors );
    420413        $user_email = sanitize_email( $user_email );
    421414
    422         if ( empty( $user_name ) )
    423                 $errors->add('user_name', __( 'Please enter a username.' ) );
    424 
    425         $illegal_names = get_site_option( 'illegal_names' );
    426         if ( ! is_array( $illegal_names ) ) {
    427                 $illegal_names = array(  'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' );
    428                 add_site_option( 'illegal_names', $illegal_names );
    429         }
    430         if ( in_array( $user_name, $illegal_names ) ) {
    431                 $errors->add( 'user_name',  __( 'Sorry, that username is not allowed.' ) );
    432         }
    433 
    434         /** This filter is documented in wp-includes/user.php */
    435         $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
    436 
    437         if ( in_array( strtolower( $user_name ), array_map( 'strtolower', $illegal_logins ) ) ) {
    438                 $errors->add( 'user_name',  __( 'Sorry, that username is not allowed.' ) );
    439         }
    440 
    441415        if ( is_email_address_unsafe( $user_email ) )
    442416                $errors->add('user_email',  __('You cannot use that email address to signup. We are having problems with them blocking some of our email. Please use another email provider.'));
    443417
    444         if ( strlen( $user_name ) < 4 )
    445                 $errors->add('user_name',  __( 'Username must be at least 4 characters.' ) );
    446 
    447         if ( strlen( $user_name ) > 60 ) {
    448                 $errors->add( 'user_name', __( 'Username may not be longer than 60 characters.' ) );
    449         }
    450 
    451         // all numeric?
    452         if ( preg_match( '/^[0-9]*$/', $user_name ) )
    453                 $errors->add('user_name', __('Sorry, usernames must have letters too!'));
    454 
    455418        if ( !is_email( $user_email ) )
    456419                $errors->add('user_email', __( 'Please enter a valid email address.' ) );
    457420
     
    463426                }
    464427        }
    465428
    466         // Check if the username has been used already.
    467         if ( username_exists($user_name) )
    468                 $errors->add( 'user_name', __( 'Sorry, that username already exists!' ) );
    469 
    470429        // Check if the email address has been used already.
    471430        if ( email_exists($user_email) )
    472431                $errors->add( 'user_email', __( 'Sorry, that email address is already used!' ) );
    473432
    474433        // Has someone already signed up for this username?
    475         $signup = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->signups WHERE user_login = %s", $user_name) );
     434        $signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE user_login = %s", $user_login ) );
    476435        if ( $signup != null ) {
    477436                $registered_at =  mysql2date('U', $signup->registered);
    478437                $now = current_time( 'timestamp', true );
     
    479438                $diff = $now - $registered_at;
    480439                // If registered more than two days ago, cancel registration and let this signup go through.
    481440                if ( $diff > 2 * DAY_IN_SECONDS )
    482                         $wpdb->delete( $wpdb->signups, array( 'user_login' => $user_name ) );
     441                        $wpdb->delete( $wpdb->signups, array( 'user_login' => $user_login ) );
    483442                else
    484443                        $errors->add('user_name', __('That username is currently reserved but may be available in a couple of days.'));
    485444        }
     
    494453                        $errors->add('user_email', __('That email address has already been used. Please check your inbox for an activation email. It will become available in a couple of days if you do nothing.'));
    495454        }
    496455
    497         $result = array('user_name' => $user_name, 'orig_username' => $orig_username, 'user_email' => $user_email, 'errors' => $errors);
     456        $result = array( 'user_name' => $user_login, 'orig_username' => $orig_userlogin, 'user_email' => $user_email, 'errors' => $errors );
    498457
    499458        /**
    500459         * Filter the validated user registration details.
  • src/wp-includes/user.php

     
    22252225}
    22262226
    22272227/**
     2228 * Validate a provided user_login
     2229 *
     2230 * user_login requirements:
     2231 *     - minimum of 4 characters
     2232 *     - maximum of 60 characters
     2233 *     - only contains (case-insensitive) characters: a-z 0-9 _ . - @
     2234 *     - no whitespace
     2235 *     - not on blacklist of illegal names
     2236 *     - contains at least one letter
     2237 *     - must be unique
     2238 *     - not pending signup already
     2239 *
     2240 * @since TBD
     2241 *
     2242 * @param string $user_login The user_login value to be be validated.
     2243 *
     2244 * @return array Contains user_login, original_user_login, and any generated errors
     2245 */
     2246function wp_validate_user_login( $user_login = '', $errors = null ) {
     2247        $original_user_login = $user_login;
     2248
     2249        if ( ! is_wp_error( $errors ) ) {
     2250                $errors = new WP_Error();
     2251        }
     2252
     2253        // User login cannot be empty
     2254        if ( empty( $user_login ) ) {
     2255                $errors->add( 'user_name', __( 'Please enter a username.' ) );
     2256        }
     2257
     2258        // User login must be less than 60 characters
     2259        if ( strlen( $user_login ) > 60 ) {
     2260                $errors->add( 'user_name', __( 'Username may not be longer than 60 characters.' ) );
     2261        }
     2262
     2263        // Strip any whitespace and then match against case insensitive characters a-z 0-9 _ . - @
     2264        $user_login = preg_replace( '/\s+/', '', sanitize_user( $user_login, true ) );
     2265
     2266        // If the previous operation generated a different value, the username is invalid
     2267        if ( $user_login !== $original_user_login ) {
     2268                $errors->add( 'user_name', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
     2269        }
     2270
     2271        if ( is_multisite() ) {
     2272                // Check the user_login against an array of illegal names
     2273                $illegal_logins = get_site_option( 'illegal_names' );
     2274                if ( false == is_array( $illegal_logins ) ) {
     2275                        $illegal_logins = array( 'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' );
     2276                        add_site_option( 'illegal_names', $illegal_logins );
     2277                }
     2278                if ( in_array( $user_login, $illegal_logins ) ) {
     2279                        $errors->add( 'user_name',  __( 'Sorry, that username is not allowed.' ) );
     2280                }
     2281        }
     2282
     2283        /** This filter is documented in wp-includes/user.php */
     2284        $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
     2285
     2286        if ( in_array( strtolower( $user_login ), array_map( 'strtolower', $illegal_logins ) ) ) {
     2287                $errors->add( 'user_name',  __( 'Sorry, that username is not allowed.' ) );
     2288        }
     2289
     2290        if ( is_multisite() ) {
     2291                // User login must have at least one letter
     2292                if ( ! preg_match( '/[a-zA-Z]+/', $user_login ) ) {
     2293                        $errors->add( 'user_name', __( 'Sorry, usernames must have letters too!' ) );
     2294                }
     2295        }
     2296
     2297        // Check if the username has been used already.
     2298        if ( username_exists( $user_login ) ) {
     2299                $errors->add( 'user_name', __( 'Sorry, that username already exists!' ) );
     2300        }
     2301
     2302        /**
     2303         * Filter a user's login after it has been validated for creation.
     2304         *
     2305         * @since TBD
     2306         *
     2307         * @param string   $user_login          The user's login.
     2308         * @param string   $original_user_login The original user login.
     2309         * @param WP_Error $errors              User's feedback error messages.
     2310         * }
     2311         */
     2312        $user_login = apply_filters_ref_array( 'wp_validate_user_login', array( $user_login, $original_user_login, &$errors ) );
     2313
     2314        if ( $errors->errors ) {
     2315                return $errors;
     2316        }
     2317
     2318        return $user_login;
     2319}
     2320
     2321/**
    22282322 * Handles registering a new user.
    22292323 *
    22302324 * @since 2.5.0
     
    22362330function register_new_user( $user_login, $user_email ) {
    22372331        $errors = new WP_Error();
    22382332
    2239         $sanitized_user_login = sanitize_user( $user_login );
    22402333        /**
    22412334         * Filter the email address of a user being registered.
    22422335         *
     
    22462339         */
    22472340        $user_email = apply_filters( 'user_registration_email', $user_email );
    22482341
    2249         // Check the username
    2250         if ( $sanitized_user_login == '' ) {
    2251                 $errors->add( 'empty_username', __( '<strong>ERROR</strong>: Please enter a username.' ) );
    2252         } elseif ( ! validate_username( $user_login ) ) {
    2253                 $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
    2254                 $sanitized_user_login = '';
    2255         } elseif ( username_exists( $sanitized_user_login ) ) {
    2256                 $errors->add( 'username_exists', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ) );
     2342        // Validate the username
     2343        $sanitized_user_login = wp_validate_user_login( $user_login, $errors );
    22572344
    2258         } else {
    2259                 /** This filter is documented in wp-includes/user.php */
    2260                 $illegal_user_logins = array_map( 'strtolower', (array) apply_filters( 'illegal_user_logins', array() ) );
    2261                 if ( in_array( strtolower( $sanitized_user_login ), $illegal_user_logins ) ) {
    2262                         $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: Sorry, that username is not allowed.' ) );
    2263                 }
    2264         }
    2265 
    22662345        // Check the email address
    22672346        if ( $user_email == '' ) {
    22682347                $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please type your email address.' ) );
  • src/wp-signup.php

     
    639639        $errors = $filtered_results['errors'];
    640640
    641641        if ( empty($blogname) )
    642                 $blogname = $user_name;
     642                $blogname = preg_replace( '|[ _.\-@]|i', '', $user_name );
    643643        ?>
    644644        <form id="setupform" method="post" action="wp-signup.php">
    645645                <input type="hidden" name="stage" value="validate-blog-signup" />
  • tests/phpunit/includes/install.php

     
    5555// Prefill a permalink structure so that WP doesn't try to determine one itself.
    5656add_action( 'populate_options', '_set_default_permalink_structure_for_tests' );
    5757
    58 wp_install( WP_TESTS_TITLE, 'admin', WP_TESTS_EMAIL, true, null, 'password' );
     58wp_install( WP_TESTS_TITLE, 'some-admin', WP_TESTS_EMAIL, true, null, 'password' );
    5959
    6060// Delete dummy permalink structure, as prefilled above.
    6161if ( ! is_multisite() ) {
  • tests/phpunit/tests/multisite/wpmuValidateUserSignup.php

     
    99        /**
    1010         * @dataProvider data_user_name
    1111         */
    12         public function test_user_name( $user_name, $error_message ) {
    13                 $v = wpmu_validate_user_signup( $user_name, 'foo@example.com' );
     12        public function test_user_name( $user_login, $error_message ) {
     13                $v = wpmu_validate_user_signup( $user_login, 'foo@example.com' );
    1414                $this->assertContains( 'user_name', $v['errors']->get_error_codes(), $error_message );
    1515        }
    1616
     
    1818                return array(
    1919                        array( 'contains spaces', 'User names with spaces are not allowed.' ),
    2020                        array( 'ContainsCaps', 'User names with capital letters are not allowed.'  ),
    21                         array( 'contains_underscores', 'User names with underscores are not allowed.'  ),
    2221                        array( 'contains%^*()junk', 'User names with non-alphanumeric characters are not allowed.'  ),
    2322                        array( '', 'Empty user names are not allowed.'  ),
    2423                        array( 'foo', 'User names of 3 characters are not allowed.'  ),
  • tests/phpunit/tests/user/wpValidateUserLogin.php

     
     1<?php
     2
     3/**
     4 * @group user
     5 */
     6class Tests_User_WpValidateUserLogin extends WP_UnitTestCase {
     7
     8        /**
     9         * A function to filter add an illegal user login.
     10         *
     11         * @param  array $illegal_logins
     12         * @return array
     13         */
     14        public function illegal_user_logins( $illegal_logins ) {
     15                $illegal_logins[] = 'adm1n';
     16                return $illegal_logins;
     17        }
     18
     19        /**
     20         * A function to filter and invalidate a login.
     21         *
     22         * @param  array $illegal_logins
     23         * @return array
     24         */
     25        public function invalidate_login( $user_login, $original_user_login, $errors ) {
     26                $errors->add( 'user_name',  __( 'Sorry, that username is not allowed.' ) );
     27                return $user_login;
     28        }
     29
     30        public function test_user_login_is_valid() {
     31                $this->assertSame( 'jonsnow', wp_validate_user_login( 'jonsnow' ) );
     32        }
     33
     34        public function test_user_login_can_be_less_than_three_characters() {
     35                $validated = wp_validate_user_login( 'tom' );
     36                $this->assertSame( 'tom', $validated );
     37        }
     38
     39        public function test_user_login_cannot_be_more_than_sixty_characters() {
     40                $validated = wp_validate_user_login( 'john-jacob-jingleheimer-david-marcus-castro-manuel-andrew-schmidt' );
     41                $this->assertTrue( is_wp_error( $validated ) );
     42        }
     43
     44        public function allowed_usernames_with_special_characters() {
     45                        return array(
     46                                array( 'arya.stark' ),
     47                                array( 'arya_stark' ),
     48                                array( 'arya-stark' ),
     49                                array( 'arya.stark@hotmail.com' ),
     50                        );
     51        }
     52
     53        /**
     54         * @dataProvider allowed_usernames_with_special_characters
     55         */
     56        public function test_user_login_can_contain_some_special_characters( $user_login ) {
     57                $this->assertEquals( $user_login, wp_validate_user_login( $user_login ) );
     58        }
     59
     60        public function test_user_login_cannot_contain_illegal_characters() {
     61                $validated = wp_validate_user_login( 'cer$ei' );
     62                $this->assertTrue( is_wp_error( $validated ) );
     63        }
     64
     65        public function illegal_logins_in_multisite() {
     66                        return array(
     67                                array( 'www' ),
     68                                array( 'web' ),
     69                                array( 'root' ),
     70                                array( 'admin' ),
     71                                array( 'main' ),
     72                                array( 'invite' ),
     73                                array( 'administrator' ),
     74                        );
     75        }
     76
     77        /**
     78         * @dataProvider illegal_logins_in_multisite
     79         */
     80        public function test_user_login_cannot_contain_illegal_login_in_multisite( $user_login ) {
     81                $validated = wp_validate_user_login( $user_login );
     82                if ( is_multisite() ) {
     83                        $this->assertTrue( is_wp_error( $validated ) );
     84                } else {
     85                        $this->assertEquals( $user_login, $validated );
     86                }
     87        }
     88
     89        public function test_user_login_must_contain_letter_in_multisite() {
     90                $validated = wp_validate_user_login( '.' );
     91                if ( is_multisite() ) {
     92                        $this->assertTrue( is_wp_error( $validated ) );
     93                } else {
     94                        $this->assertEquals( '.', $validated );
     95                }
     96        }
     97
     98        public function test_illegal_login_filter_should_invalidate_user_logins() {
     99                add_filter( 'illegal_user_logins', array( $this, 'illegal_user_logins' ) );
     100                $validated = wp_validate_user_login( 'adm1n' );
     101                $this->assertTrue( is_wp_error( $validated ) );
     102                remove_filter( 'illegal_user_logins', array( $this, 'illegal_user_logins' ) );
     103        }
     104
     105        public function test_additional_validation_can_invalidate() {
     106                add_filter( 'wp_validate_user_login', array( $this, 'invalidate_login' ), 10, 3 );
     107                $validated = wp_validate_user_login( 'glerf' );
     108                $this->assertTrue( is_wp_error( $validated ) );
     109                remove_filter( 'wp_validate_user_login', array( $this, 'invalidate_login'), 10, 3  );
     110        }
     111
     112}