Changeset 43082 for branches/4.9
- Timestamp:
- 05/02/2018 12:48:23 AM (6 years ago)
- Location:
- branches/4.9
- Files:
-
- 1 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/4.9
- Property svn:mergeinfo changed
/trunk merged: 42971,43081
- Property svn:mergeinfo changed
-
branches/4.9/src/wp-admin/includes/class-wp-community-events.php
r42016 r43082 235 235 public static function get_unsafe_client_ip() { 236 236 $client_ip = $netmask = false; 237 $ip_prefix = '';238 237 239 238 // In order of preference, with the best ones for this purpose first. … … 266 265 } 267 266 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, '.' ) ); 271 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 $ip_start = 1; 283 $ip_end = (int) strpos( $client_ip, ']' ) - 1; 284 $netmask = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000'; 285 286 // Strip the port (and [] from IPv6 addresses), if they exist. 287 if ( $ip_end > 0 ) { 288 $client_ip = substr( $client_ip, $ip_start, $ip_end ); 289 } 290 291 // Partially anonymize the IP by reducing it to the corresponding network ID. 292 if ( function_exists( 'inet_pton' ) && function_exists( 'inet_ntop' ) ) { 293 $client_ip = inet_ntop( inet_pton( $client_ip ) & inet_pton( $netmask ) ); 294 } 295 } elseif ( $is_ipv4 ) { 296 // Strip any port and partially anonymize the IP. 297 $last_octet_position = strrpos( $client_ip, '.' ); 298 $client_ip = substr( $client_ip, 0, $last_octet_position ) . '.0'; 299 } else { 267 $anon_ip = wp_privacy_anonymize_ip( $client_ip, true ); 268 269 if ( '0.0.0.0' === $anon_ip || '::' === $anon_ip ) { 300 270 return false; 301 271 } 302 272 303 // Restore the IPv6 prefix to compatibility mode addresses. 304 return $ip_prefix . $client_ip; 273 return $anon_ip; 305 274 } 306 275 -
branches/4.9/src/wp-includes/functions.php
r42811 r43082 5817 5817 ), $email_change_email['message'], $email_change_email['headers'] ); 5818 5818 } 5819 5820 /** 5821 * Return an anonymized IPv4 or IPv6 address. 5822 * 5823 * @since 4.9.6 Abstracted from `WP_Community_Events::get_unsafe_client_ip()`. 5824 * 5825 * @param string $ip_addr The IPv4 or IPv6 address to be anonymized. 5826 * @param bool $ipv6_fallback Optional. Whether to return the original IPv6 address if the needed functions 5827 * to anonymize it are not present. Default false, return `::` (unspecified address). 5828 * @return string The anonymized IP address. 5829 */ 5830 function wp_privacy_anonymize_ip( $ip_addr, $ipv6_fallback = false ) { 5831 // Detect what kind of IP address this is. 5832 $ip_prefix = ''; 5833 $is_ipv6 = substr_count( $ip_addr, ':' ) > 1; 5834 $is_ipv4 = ( 3 === substr_count( $ip_addr, '.' ) ); 5835 5836 if ( $is_ipv6 && $is_ipv4 ) { 5837 // IPv6 compatibility mode, temporarily strip the IPv6 part, and treat it like IPv4. 5838 $ip_prefix = '::ffff:'; 5839 $ip_addr = preg_replace( '/^\[?[0-9a-f:]*:/i', '', $ip_addr ); 5840 $ip_addr = str_replace( ']', '', $ip_addr ); 5841 $is_ipv6 = false; 5842 } 5843 5844 if ( $is_ipv6 ) { 5845 // IPv6 addresses will always be enclosed in [] if there's a port. 5846 $left_bracket = strpos( $ip_addr, '[' ); 5847 $right_bracket = strpos( $ip_addr, ']' ); 5848 $percent = strpos( $ip_addr, '%' ); 5849 $netmask = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000'; 5850 5851 // Strip the port (and [] from IPv6 addresses), if they exist. 5852 if ( false !== $left_bracket && false !== $right_bracket ) { 5853 $ip_addr = substr( $ip_addr, $left_bracket + 1, $right_bracket - $left_bracket - 1 ); 5854 } elseif ( false !== $left_bracket || false !== $right_bracket ) { 5855 // The IP has one bracket, but not both, so it's malformed. 5856 return '::'; 5857 } 5858 5859 // Strip the reachability scope. 5860 if ( false !== $percent ) { 5861 $ip_addr = substr( $ip_addr, 0, $percent ); 5862 } 5863 5864 // No invalid characters should be left. 5865 if ( preg_match( '/[^0-9a-f:]/i', $ip_addr ) ) { 5866 return '::'; 5867 } 5868 5869 // Partially anonymize the IP by reducing it to the corresponding network ID. 5870 if ( function_exists( 'inet_pton' ) && function_exists( 'inet_ntop' ) ) { 5871 $ip_addr = inet_ntop( inet_pton( $ip_addr ) & inet_pton( $netmask ) ); 5872 if ( false === $ip_addr) { 5873 return '::'; 5874 } 5875 } elseif ( ! $ipv6_fallback ) { 5876 return '::'; 5877 } 5878 } elseif ( $is_ipv4 ) { 5879 // Strip any port and partially anonymize the IP. 5880 $last_octet_position = strrpos( $ip_addr, '.' ); 5881 $ip_addr = substr( $ip_addr, 0, $last_octet_position ) . '.0'; 5882 } else { 5883 return '0.0.0.0'; 5884 } 5885 5886 // Restore the IPv6 prefix to compatibility mode addresses. 5887 return $ip_prefix . $ip_addr; 5888 } 5889 5890 /** 5891 * Return uniform "anonymous" data by type. 5892 * 5893 * @since 4.9.6 5894 * 5895 * @param string $type The type of data to be anonymized. 5896 * @param string $data Optional The data to be anonymized. 5897 * @return string The anonymous data for the requested type. 5898 */ 5899 function wp_privacy_anonymize_data( $type, $data = '' ) { 5900 5901 switch ( $type ) { 5902 case 'email': 5903 $anonymous = 'deleted@site.invalid'; 5904 break; 5905 case 'url': 5906 $anonymous = 'https://site.invalid'; 5907 break; 5908 case 'ip': 5909 $anonymous = wp_privacy_anonymize_ip( $data ); 5910 break; 5911 case 'date': 5912 $anonymous = '0000-00-00 00:00:00'; 5913 break; 5914 case 'text': 5915 /* translators: deleted text */ 5916 $anonymous = __( '[deleted]' ); 5917 break; 5918 case 'longtext': 5919 /* translators: deleted long text */ 5920 $anonymous = __( 'This content was deleted by the author.' ); 5921 break; 5922 default: 5923 $anonymous = ''; 5924 } 5925 5926 /** 5927 * Filters the anonymous data for each type. 5928 * 5929 * @since 4.9.6 5930 * 5931 * @param string $anonymous Anonymized data. 5932 * @param string $type Type of the data. 5933 * @param string $data Original data. 5934 */ 5935 return apply_filters( 'wp_privacy_anonymize_data', $anonymous, $type, $data ); 5936 } -
branches/4.9/tests/phpunit/tests/admin/includesCommunityEvents.php
r42016 r43082 260 260 * Test that get_unsafe_client_ip() properly anonymizes all possible address formats 261 261 * 262 * @dataProvider data_get_unsafe_client_ip _anonymization262 * @dataProvider data_get_unsafe_client_ip 263 263 * 264 264 * @ticket 41083 265 265 */ 266 public function test_get_unsafe_client_ip_anonymization( $raw_ip, $expected_result ) { 267 $_SERVER['REMOTE_ADDR'] = $raw_ip; 268 $actual_result = WP_Community_Events::get_unsafe_client_ip(); 266 public function test_get_unsafe_client_ip( $raw_ip, $expected_result ) { 267 $_SERVER['REMOTE_ADDR'] = 'this should not be used'; 268 $_SERVER['HTTP_CLIENT_IP'] = $raw_ip; 269 $actual_result = WP_Community_Events::get_unsafe_client_ip(); 269 270 270 271 $this->assertEquals( $expected_result, $actual_result ); 271 272 } 272 273 273 public function data_get_unsafe_client_ip_anonymization() { 274 return array( 275 // Invalid IP. 274 /** 275 * Provide test cases for `test_get_unsafe_client_ip()`. 276 * 277 * @return array 278 */ 279 public function data_get_unsafe_client_ip() { 280 return array( 281 // Handle '::' returned from `wp_privacy_anonymize_ip()`. 276 282 array( 277 '', // Raw IP address 278 false, // Expected result 279 ), 280 // Invalid IP. Sometimes proxies add things like this, or other arbitrary strings. 283 'or=\"[1000:0000:0000:0000:0000:0000:0000:0001', 284 false, 285 ), 286 287 // Handle '0.0.0.0' returned from `wp_privacy_anonymize_ip()`. 281 288 array( 282 289 'unknown', 283 290 false, 284 291 ), 285 // IPv4, no port 292 293 // Valid IPv4. 286 294 array( 287 '10.20.30.45', 288 '10.20.30.0', 289 ), 290 // IPv4, port 291 array( 292 '10.20.30.45:20000', 293 '10.20.30.0', 294 ), 295 // IPv6, no port 295 '198.143.164.252', 296 '198.143.164.0', 297 ), 298 299 // Valid IPv6. 296 300 array( 297 301 '2a03:2880:2110:df07:face:b00c::1', 298 302 '2a03:2880:2110:df07::', 299 303 ), 300 // IPv6, port301 array(302 '[2a03:2880:2110:df07:face:b00c::1]:20000',303 '2a03:2880:2110:df07::',304 ),305 // IPv6, no port, reducible representation306 array(307 '0000:0000:0000:0000:0000:0000:0000:0001',308 '::',309 ),310 // IPv6, no port, partially reducible representation311 array(312 '1000:0000:0000:0000:0000:0000:0000:0001',313 '1000::',314 ),315 // IPv6, port, reducible representation316 array(317 '[0000:0000:0000:0000:0000:0000:0000:0001]:1234',318 '::',319 ),320 // IPv6, port, partially reducible representation321 array(322 '[1000:0000:0000:0000:0000:0000:0000:0001]:5678',323 '1000::',324 ),325 // IPv6, no port, reduced representation326 array(327 '::',328 '::',329 ),330 // IPv6, no port, reduced representation331 array(332 '::1',333 '::',334 ),335 // IPv6, port, reduced representation336 array(337 '[::]:20000',338 '::',339 ),340 // IPv6, address brackets without port delimiter and number, reduced representation341 array(342 '[::1]',343 '::',344 ),345 // IPv6, no port, compatibility mode346 array(347 '::ffff:10.15.20.25',348 '::ffff:10.15.20.0',349 ),350 // IPv6, port, compatibility mode351 array(352 '[::ffff:10.15.20.25]:30000',353 '::ffff:10.15.20.0',354 ),355 // IPv6, no port, compatibility mode shorthand356 array(357 '::127.0.0.1',358 '::ffff:127.0.0.0',359 ),360 // IPv6, port, compatibility mode shorthand361 array(362 '[::127.0.0.1]:30000',363 '::ffff:127.0.0.0',364 ),365 304 ); 366 305 }
Note: See TracChangeset
for help on using the changeset viewer.