WordPress.org

Make WordPress Core

Ticket #41083: 41083.3.diff

File 41083.3.diff, 5.6 KB (added by iandunn, 2 years ago)

Iteration on 2.diff

  • src/wp-admin/includes/class-wp-community-events.php

    diff --git src/wp-admin/includes/class-wp-community-events.php src/wp-admin/includes/class-wp-community-events.php
    index 053d92db1a..7f6d331190 100644
    class WP_Community_Events { 
    224224         *                      or false on failure.
    225225         */
    226226        public static function get_unsafe_client_ip() {
    227                 $client_ip = false;
     227                $client_ip = $netmask = false;
    228228
    229229                // In order of preference, with the best ones for this purpose first.
    230230                $address_headers = array(
    class WP_Community_Events { 
    251251                        }
    252252                }
    253253
    254                 // These functions are not available on Windows until PHP 5.3.
    255                 if ( function_exists( 'inet_pton' ) && function_exists( 'inet_ntop' ) ) {
    256                         if ( 4 === strlen( inet_pton( $client_ip ) ) ) {
    257                                 $netmask = '255.255.255.0'; // ipv4.
    258                         } else {
    259                                 $netmask = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000'; // ipv6.
    260                         }
     254                $address_format = self::detect_ip_address_format( (string) $client_ip );
     255                if ( ! $address_format ) {
     256                        $client_ip = false;
     257                }
    261258
     259                if ( $client_ip ) {
     260                        $client_ip = self::strip_port_from_ip_address( $client_ip, $address_format );
     261                        $netmask   = 4 === $address_format ? '255.255.255.0' : 'ffff:ffff:ffff:ffff:0000:0000:0000:0000';
     262                }
     263
     264                // Partially anonymize the IP by reducing it to the corresponding network ID
     265                // These functions are not available on Windows until PHP 5.3.
     266                if ( $client_ip && $netmask && function_exists( 'inet_pton' ) && function_exists( 'inet_ntop' ) ) {
    262267                        $client_ip = inet_ntop( inet_pton( $client_ip ) & inet_pton( $netmask ) );
    263268                }
    264269
    class WP_Community_Events { 
    266271        }
    267272
    268273        /**
     274         * Detect the format of an IP address.
     275         *
     276         * `filter_var()` is avoided because it can be disabled in PHP builds, and
     277         * `WP_Http::is_ip_address()` is avoided because it will return false if the address
     278         * contains a port number.
     279         *
     280         * A valid IPv6 address must have at least two colons (because
     281         * addresses like `0:0:0:0:0:0:0:0` can be reduced to `::`). It can contain a valid
     282         * IPv4 address incompatibility mode (e.g., ::ffff:10.10.1.1).
     283         * A valid IPv4 address must have exactly 3 periods and at most 1 colon.
     284         *
     285         * @param string $address
     286         *
     287         * @return false|int todo document false if couldn't determine (probably not valid ip), 4, 6
     288         */
     289        protected static function detect_ip_address_format( $address ) {
     290                $format = false;
     291
     292                if ( substr_count( $address, ':' ) > 1 ) {
     293                        $format = 6;
     294                } elseif ( 3 === substr_count( $address, '.' ) ) {
     295                        $format = 4;
     296                }
     297
     298                return $format;
     299        }
     300
     301
     302        // todo document
     303        protected static function strip_port_from_ip_address( $ip_address, $address_format ) {
     304                if ( 4 === $address_format ) {
     305                        $port_delimiter = strpos( $ip_address, ':' );
     306
     307                        if ( false !== $port_delimiter ) {
     308                                $ip_address = substr( $ip_address, 0, $port_delimiter );
     309                        }
     310                } elseif ( 6 === $address_format ) {
     311                        $port_delimiter = strpos( $ip_address, ']' );
     312
     313                        if ( false !== $port_delimiter ) {
     314                                $ip_address = substr( $ip_address, 1, $port_delimiter - 1 );
     315                                // todo verify it always has the brackets when there's a port
     316                        }
     317                }
     318
     319                return $ip_address;
     320        }
     321
     322
     323        /**
    269324         * Test if two pairs of latitude/longitude coordinates match each other.
    270325         *
    271326         * @since 4.8.0
  • tests/phpunit/tests/admin/includesCommunityEvents.php

    diff --git tests/phpunit/tests/admin/includesCommunityEvents.php tests/phpunit/tests/admin/includesCommunityEvents.php
    index ed5cc2caee..fefd4a4822 100644
    class Test_WP_Community_Events extends WP_UnitTestCase { 
    255255                        'filename' => '',
    256256                );
    257257        }
     258
     259        /**
     260         * Test that get_unsafe_client_ip() properly anonymizes all possible address formats
     261         *
     262         * @ticket 41083
     263         * @since 4.8.1
     264         */
     265        public function test_get_unsafe_client_ip_anonymization() {
     266                // todo cases that are commented out are failing and need to be fixed
     267
     268                $test_cases = array(
     269                        ''                                         => false,                    // Invalid IP.
     270                        'unknown'                                  => false,                    // Invalid IP. Sometimes proxies add things like this, or other arbitrary strings.
     271                        '10.20.30.45'                              => '10.20.30.0',             // IPv4, no port
     272                        '10.20.30.45:20000'                        => '10.20.30.0',             // IPv4, port
     273                        '2a03:2880:2110:df07:face:b00c::1'         => '2a03:2880:2110:df07::',  // IPv6, no port
     274                        '[2a03:2880:2110:df07:face:b00c::1]:20000' => '2a03:2880:2110:df07::',  // IPv6, port
     275                        '0000:0000:0000:0000:0000:0000:0000:0001'  => '::',                     // IPv6, no port, reducible representation
     276                        '::'                                       => '::',                     // IPv6, no port, reduced representation
     277                        '::1'                                      => '::',                     // IPv6, no port, reduced representation
     278                        '[::]:20000'                               => '::',                     // IPv6, port, reduced representation
     279                        '[::1]'                                    => '::',                     // IPv6, address brackets without port delimiter and number, reduced representation
     280                        //'::127.0.0.1'                              => '::127.0.0.0',            // IPv6, no port, compatibility mode
     281                        //'[::ffff:10.10.1.1]:30000'                 => '::ffff:10.10.1.0',       // IPv6, port, compatibility mode
     282                );
     283
     284                foreach ( $test_cases as $raw_ip => $expected_result ) {
     285                        $_SERVER['REMOTE_ADDR'] = $raw_ip;
     286                        $actual_result          = WP_Community_Events::get_unsafe_client_ip();
     287
     288                        $this->assertEquals( $expected_result, $actual_result );
     289                }
     290        }
    258291}