WordPress.org

Make WordPress Core

Ticket #43545: 43545.4.diff

File 43545.4.diff, 8.8 KB (added by azaozz, 18 months ago)
  • src/wp-admin/includes/class-wp-community-events.php

     
    265265                        return false;
    266266                }
    267267
    268                 // Detect what kind of IP address this is.
    269                 $is_ipv6 = substr_count( $client_ip, ':' ) > 1;
    270                 $is_ipv4 = ( 3 === substr_count( $client_ip, '.' ) );
     268                $anon_ip = wp_privacy_anonymize_ip( $client_ip, true );
    271269
    272                 if ( $is_ipv6 && $is_ipv4 ) {
    273                         // IPv6 compatibility mode, temporarily strip the IPv6 part, and treat it like IPv4.
    274                         $ip_prefix = '::ffff:';
    275                         $client_ip = preg_replace( '/^\[?[0-9a-f:]*:/i', '', $client_ip );
    276                         $client_ip = str_replace( ']', '', $client_ip );
    277                         $is_ipv6   = false;
    278                 }
    279 
    280                 if ( $is_ipv6 ) {
    281                         // IPv6 addresses will always be enclosed in [] if there's a port.
    282                         $left_bracket  = strpos( $client_ip, '[' );
    283                         $right_bracket = strpos( $client_ip, ']' );
    284                         $percent       = strpos( $client_ip, '%' );
    285                         $netmask       = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000';
    286 
    287                         // Strip the port (and [] from IPv6 addresses), if they exist.
    288                         if ( false !== $left_bracket && false !== $right_bracket ) {
    289                                 $client_ip = substr( $client_ip, $left_bracket + 1, $right_bracket - $left_bracket - 1 );
    290                         } elseif ( false !== $left_bracket || false !== $right_bracket ) {
    291                                 // The IP has one bracket, but not both, so it's malformed.
    292                                 return false;
    293                         }
    294 
    295                         // Strip the reachability scope.
    296                         if ( false !== $percent ) {
    297                                 $client_ip = substr( $client_ip, 0, $percent );
    298                         }
    299 
    300                         // No invalid characters should be left.
    301                         if ( preg_match( '/[^0-9a-f:]/i', $client_ip ) ) {
    302                                 return false;
    303                         }
    304 
    305                         // Partially anonymize the IP by reducing it to the corresponding network ID.
    306                         if ( function_exists( 'inet_pton' ) && function_exists( 'inet_ntop' ) ) {
    307                                 $client_ip = inet_ntop( inet_pton( $client_ip ) & inet_pton( $netmask ) );
    308                         }
    309                 } elseif ( $is_ipv4 ) {
    310                         // Strip any port and partially anonymize the IP.
    311                         $last_octet_position = strrpos( $client_ip, '.' );
    312                         $client_ip           = substr( $client_ip, 0, $last_octet_position ) . '.0';
    313                 } else {
     270                if ( '0.0.0.0' === $anon_ip || '::' === $anon_ip ) {
    314271                        return false;
    315272                }
    316273
    317                 // Restore the IPv6 prefix to compatibility mode addresses.
    318                 return $ip_prefix . $client_ip;
     274                return $anon_ip;
    319275        }
    320276
    321277        /**
  • src/wp-includes/functions.php

     
    61276127                ), $email_change_email['message'], $email_change_email['headers']
    61286128        );
    61296129}
     6130
     6131/**
     6132 * Return an anonymized IPV4 or IPV6 address.
     6133 *
     6134 * @since 5.0.0
     6135 *
     6136 * @param string $ip_addr       The IPv4 or IPv6 address to be anonymized.
     6137 * @param bool   $ipv6_fallback Optional. Whether to return the original IPv6 address if the needed functions
     6138 *                              to anonymize it are not present. Default false, return `::` (unspecified address).
     6139 * @return string The anonymized IP address.
     6140 */
     6141function wp_privacy_anonymize_ip( $ip_addr, $ipv6_fallback = false ) {
     6142        // Detect what kind of IP address this is.
     6143        $is_ipv6 = substr_count( $ip_addr, ':' ) > 1;
     6144        $is_ipv4 = ( 3 === substr_count( $ip_addr, '.' ) );
     6145
     6146        if ( $is_ipv6 && $is_ipv4 ) {
     6147                // IPv6 compatibility mode, temporarily strip the IPv6 part, and treat it like IPv4.
     6148                $ip_prefix = '::ffff:';
     6149                $ip_addr = preg_replace( '/^\[?[0-9a-f:]*:/i', '', $ip_addr );
     6150                $ip_addr = str_replace( ']', '', $ip_addr );
     6151                $is_ipv6   = false;
     6152        }
     6153
     6154        if ( $is_ipv6 ) {
     6155                // IPv6 addresses will always be enclosed in [] if there's a port.
     6156                $left_bracket  = strpos( $ip_addr, '[' );
     6157                $right_bracket = strpos( $ip_addr, ']' );
     6158                $percent       = strpos( $ip_addr, '%' );
     6159                $netmask       = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000';
     6160
     6161                // Strip the port (and [] from IPv6 addresses), if they exist.
     6162                if ( false !== $left_bracket && false !== $right_bracket ) {
     6163                        $ip_addr = substr( $ip_addr, $left_bracket + 1, $right_bracket - $left_bracket - 1 );
     6164                } elseif ( false !== $left_bracket || false !== $right_bracket ) {
     6165                        // The IP has one bracket, but not both, so it's malformed.
     6166                        return '::';
     6167                }
     6168
     6169                // Strip the reachability scope.
     6170                if ( false !== $percent ) {
     6171                        $ip_addr = substr( $ip_addr, 0, $percent );
     6172                }
     6173
     6174                // No invalid characters should be left.
     6175                if ( preg_match( '/[^0-9a-f:]/i', $ip_addr ) ) {
     6176                        return '::';
     6177                }
     6178
     6179                // Partially anonymize the IP by reducing it to the corresponding network ID.
     6180                if ( function_exists( 'inet_pton' ) && function_exists( 'inet_ntop' ) ) {
     6181                        $ip_addr = inet_ntop( inet_pton( $ip_addr ) & inet_pton( $netmask ) );
     6182                } elseif ( ! $ipv6_fallback ) {
     6183                        return '::';
     6184                }
     6185        } elseif ( $is_ipv4 ) {
     6186                // Strip any port and partially anonymize the IP.
     6187                $last_octet_position = strrpos( $ip_addr, '.' );
     6188                $ip_addr           = substr( $ip_addr, 0, $last_octet_position ) . '.0';
     6189        } else {
     6190                return '0.0.0.0';
     6191        }
     6192
     6193        // Restore the IPv6 prefix to compatibility mode addresses.
     6194        return $ip_prefix . $ip_addr;
     6195}
     6196
     6197/**
     6198 * Return uniform "anonymous" data by type.
     6199 *
     6200 * @since 5.0.0
     6201 *
     6202 * @param  string $type The type of data to be anonymized.
     6203 * @param  string $data Optional The data to be anonymized.
     6204 * @return string The anonymous data for the requested type.
     6205 */
     6206function wp_privacy_anonymize_data( $type, $data = '' ) {
     6207
     6208        switch ( $type ) {
     6209                case 'email':
     6210                        $anonymous = 'deleted@site.invalid';
     6211                        break;
     6212                case 'url':
     6213                        $anonymous = 'https://site.invalid';
     6214                        break;
     6215                case 'ip':
     6216                        $anonymous = wp_privacy_anonymize_ip( $data );
     6217                        break;
     6218                case 'date':
     6219                        $anonymous = '0000-00-00 00:00:00';
     6220                        break;
     6221                case 'text':
     6222                        /* translators: deleted text */
     6223                        $anonymous = __( '[deleted]' );
     6224                        break;
     6225                case 'longtext':
     6226                        /* translators: deleted long text */
     6227                        $anonymous = __( 'This content was deleted by the author.' );
     6228                        break;
     6229                default:
     6230                        $anonymous = '';
     6231        }
     6232
     6233        /**
     6234         * Filters the anonymous data for each type.
     6235         *
     6236         * @since 5.0.0
     6237         *
     6238         * @param string $anonymous Anonymized data.
     6239         * @param string $type      Type of the data.   
     6240         * @param string $data      Original data.
     6241         */
     6242        return apply_filters( 'wp_privacy_anonymize_data', $anonymous, $type, $data );
     6243}
  • tests/phpunit/tests/functions/anonymization.php

     
     1<?php
     2
     3/**
     4 * @group functions.php
     5 * @group privacy
     6 */
     7class Tests_Functions_Anonymization extends WP_UnitTestCase {
     8        function test_anonymize_invalid_ip() {
     9                $ip_addrs = array( '', 'invalid', '0.0.0.0.0' );
     10
     11                foreach ( (array) $ip_addrs as $ip_addr ) {
     12                        $this->assertEquals( '0.0.0.0', wp_privacy_anonymize_data( $ip_addr, 'ip' ) );
     13                }
     14        }
     15
     16        function test_anonymize_ipv4() {
     17                $ip_addrs = array(
     18                        '198.143.164.252' => '198.143.164.0',
     19                        '127.0.0.1'                      => '127.0.0.0',
     20                );
     21
     22                foreach ( (array) $ip_addrs as $ip_addr => $anonymized_ip_addr ) {
     23                        $this->assertEquals( $anonymized_ip_addr, wp_privacy_anonymize_data( $ip_addr, 'ip' ) );
     24                }
     25        }
     26
     27        function test_anonymize_ipv6() {
     28                $ip_addrs = array(
     29                        '2001:0db8:0a0b:12f0:0000:0000:0000:0001' => '2001:db8:a0b:12f0::',
     30                        '2001:db8:a0b:12f0::1'                    => '2001:db8:a0b:12f0::',
     31                        '2001:db8::1'                             => '2001:db8::',
     32                        '::ffff:10.0.0.3'                         => '::ffff:10.0.0.0',
     33                        '[2001:db8:a0b:12f0::1]'                  => '2001:db8:a0b:12f0::',
     34                        '[2001:db8:a0b:12f0::1]:21'               => '2001:db8:a0b:12f0::',
     35                        '::1'                                     => '::',
     36                );
     37
     38                foreach ( (array) $ip_addrs as $ip_addr => $anonymized_ip_addr ) {
     39                        $this->assertEquals( $anonymized_ip_addr, wp_privacy_anonymize_data( $ip_addr, 'ip' ) );
     40                }
     41        }
     42
     43        function test_anonymize_email() {
     44                $this->assertEquals( 'deleted@site.invalid', wp_privacy_anonymize_data( 'bar@example.com', 'email' ) );
     45        }
     46
     47        function test_anonymize_url() {
     48                $this->assertEquals( 'https://site.invalid', wp_privacy_anonymize_data( 'https://example.com/author/username', 'url' ) );
     49        }
     50
     51        function test_anonymize_date() {
     52                $this->assertEquals( '0000-00-00 00:00:00', wp_privacy_anonymize_data( '2003-12-25 12:34:56', 'date' ) );
     53        }
     54
     55        function test_anonymize_text() {
     56                $text = __( 'Four score and seven years ago' );
     57                $this->assertNotEquals( $text, wp_privacy_anonymize_data( $text, 'text' ) );
     58        }
     59
     60        function test_anonymize_long_text() {
     61                $text = __( 'Four score and seven years ago' );
     62                $this->assertNotEquals( $text, wp_privacy_anonymize_data( $text, 'longtext' ) );
     63        }
     64}