WordPress.org

Make WordPress Core

Ticket #43545: 43545.diff

File 43545.diff, 5.8 KB (added by allendav, 19 months ago)

Adds IPV4 and IPV6 anonymization functions and unit tests for everything

  • 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. Do not call directly. Use
     6133 * wp_privacy_anonymize_data( $ip_addr, 'ip' ) instead.
     6134 *
     6135 * @since 5.0.0
     6136 *
     6137 * @param  string $ip_addr The IPV4 or IPV6 address to be anonymized.
     6138 * @return string          The anonymized IP address.
     6139 */
     6140function _wp_privacy_anonymize_ip( $ip_addr ) {
     6141        $ip_prefix = '';
     6142        $is_ipv4   = ( 3 === substr_count( $ip_addr, '.' ) );
     6143        $is_ipv6   = substr_count( $ip_addr, ':' ) > 1;
     6144
     6145        if ( $is_ipv6 && $is_ipv4 ) {
     6146                // IPv6 compatibility mode, temporarily strip the IPv6 part, and treat it like IPv4.
     6147                $ip_prefix = '::ffff:';
     6148                $ip_addr   = preg_replace( '/^\[?[0-9a-f:]*:/i', '', $ip_addr );
     6149                $ip_addr   = str_replace( ']', '', $ip_addr );
     6150                $is_ipv6   = false;
     6151        }
     6152
     6153        if ( $is_ipv6 ) {
     6154                // IPv6 addresses will always be enclosed in [] if there's a port.
     6155                $ip_start = 1;
     6156                $ip_end   = (int) strpos( $ip_addr, ']' ) - 1;
     6157                $netmask  = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000';
     6158
     6159                // Strip the port (and [] from IPv6 addresses), if they exist.
     6160                if ( $ip_end > 0 ) {
     6161                        $ip_addr = substr( $ip_addr, $ip_start, $ip_end );
     6162                }
     6163
     6164                // Partially anonymize the IP by reducing it to the corresponding network ID.
     6165                // This basically zeros the last eight octets of an IPV6 address.
     6166                // Note inet_pton and inet_ntop were not available on Windows platforms until PHP 5.3.0.
     6167                if ( function_exists( 'inet_pton' ) && function_exists( 'inet_ntop' ) ) {
     6168                        $ip_addr = inet_ntop( inet_pton( $ip_addr ) & inet_pton( $netmask ) );
     6169                }
     6170        } elseif ( $is_ipv4 ) {
     6171                // Strip any port and partially anonymize the IP.
     6172                $last_octet_position = strrpos( $ip_addr, '.' );
     6173                $ip_addr             = substr( $ip_addr, 0, $last_octet_position ) . '.0';
     6174        } else {
     6175                return '0.0.0.0';
     6176        }
     6177
     6178        // Restore the IPv6 prefix to compatibility mode addresses.
     6179        return $ip_prefix . $ip_addr;
     6180}
     6181
     6182/**
     6183 * Return uniform "anonymous" data by type.
     6184 *
     6185 * @since 5.0.0
     6186 *
     6187 * @param  string $data Optional The data to be anonymized.
     6188 * @param  string $type Optional The type of data to be anonymized.
     6189 * @return string                The anonymous data for the requested type.
     6190 */
     6191function wp_privacy_anonymize_data( $data = '', $type = 'text' ) {
     6192
     6193        switch ( $type ) {
     6194                case 'email':
     6195                        $anonymous = 'deleted@example.com';
     6196                        break;
     6197                case 'url':
     6198                        $anonymous = 'https://example.com';
     6199                        break;
     6200                case 'ip':
     6201                        $anonymous = _wp_privacy_anonymize_ip( $data );
     6202                        break;
     6203                case 'date':
     6204                        $anonymous = '0000-00-00 00:00:00';
     6205                        break;
     6206                case 'text':
     6207                        /* translators: deleted text */
     6208                        $anonymous = __( '[deleted]' );
     6209                        break;
     6210                case 'longtext':
     6211                        /* translators: deleted long text */
     6212                        $anonymous = __( 'This content was deleted by the author.' );
     6213                        break;
     6214                default:
     6215                        $anonymous = '';
     6216        }
     6217
     6218        /**
     6219         * Filters the anonymous data for each type.
     6220         *
     6221         * @since 5.0.0
     6222         *
     6223         * @param string $anonymous Anonymized data.
     6224         * @param string $data      Original data.
     6225         * @param string $type      Type of the data.
     6226         */
     6227        return apply_filters( 'wp_privacy_anonymize_data', $anonymous, $data, $type );
     6228}
  • tests/phpunit/tests/functions/anonymization.php

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