diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index 741e76837f..ffc691916f 100644 --- a/src/wp-includes/rest-api.php +++ b/src/wp-includes/rest-api.php @@ -869,23 +869,23 @@ function rest_parse_request_arg( $value, $request, $param ) { } /** - * Determines if a IPv4 address is valid. + * Determines if an IP address is valid. * - * Does not handle IPv6 addresses. + * Handles both IPv4 and IPv6 addresses. * * @since 4.7.0 * - * @param string $ipv4 IP 32-bit address. - * @return string|false The valid IPv4 address, otherwise false. + * @param string $ip IP address. + * @return string|false The valid IP address, otherwise false. */ -function rest_is_ip_address( $ipv4 ) { - $pattern = '/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/'; +function rest_is_ip_address( $ip ) { + $ipv4_pattern = '/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/'; - if ( ! preg_match( $pattern, $ipv4 ) ) { + if ( ! preg_match( $ipv4_pattern, $ip ) && ! Requests_IPv6::check_ipv6( $ip ) ) { return false; } - return $ipv4; + return $ip; } /** @@ -1053,9 +1053,9 @@ function rest_validate_value_from_schema( $value, $args, $param = '' ) { return new WP_Error( 'rest_invalid_email', __( 'Invalid email address.' ) ); } break; - case 'ipv4' : + case 'ip' : if ( ! rest_is_ip_address( $value ) ) { - /* translators: %s: IP address */ + /* translators: %s: IP address */ return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not a valid IP address.' ), $value ) ); } break; @@ -1156,7 +1156,7 @@ function rest_sanitize_value_from_schema( $value, $args ) { case 'uri' : return esc_url_raw( $value ); - case 'ipv4' : + case 'ip' : return sanitize_text_field( $value ); } } diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php index bfa3159bf1..09223c06b9 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php @@ -1115,7 +1115,7 @@ class WP_REST_Comments_Controller extends WP_REST_Controller { 'author_ip' => array( 'description' => __( 'IP address for the object author.' ), 'type' => 'string', - 'format' => 'ipv4', + 'format' => 'ip', 'context' => array( 'edit' ), 'default' => '127.0.0.1', ), diff --git a/tests/phpunit/tests/rest-api/rest-schema-sanitization.php b/tests/phpunit/tests/rest-api/rest-schema-sanitization.php index 4c523df1e3..e1ae29d3fa 100644 --- a/tests/phpunit/tests/rest-api/rest-schema-sanitization.php +++ b/tests/phpunit/tests/rest-api/rest-schema-sanitization.php @@ -65,6 +65,17 @@ class WP_Test_REST_Schema_Sanitization extends WP_UnitTestCase { $this->assertEquals( 'invalid', rest_sanitize_value_from_schema( 'invalid', $schema ) ); } + public function test_format_ip() { + $schema = array( + 'type' => 'string', + 'format' => 'ip', + ); + + $this->assertEquals( '127.0.0.1', rest_sanitize_value_from_schema( '127.0.0.1', $schema ) ); + $this->assertEquals( 'hello', rest_sanitize_value_from_schema( 'hello', $schema ) ); + $this->assertEquals( '2001:DB8:0:0:8:800:200C:417A', rest_sanitize_value_from_schema( '2001:DB8:0:0:8:800:200C:417A', $schema ) ); + } + public function test_type_array() { $schema = array( 'type' => 'array', diff --git a/tests/phpunit/tests/rest-api/rest-schema-validation.php b/tests/phpunit/tests/rest-api/rest-schema-validation.php index 4e4a111018..f504cb7ee1 100644 --- a/tests/phpunit/tests/rest-api/rest-schema-validation.php +++ b/tests/phpunit/tests/rest-api/rest-schema-validation.php @@ -83,14 +83,30 @@ class WP_Test_REST_Schema_Validation extends WP_UnitTestCase { $this->assertWPError( rest_validate_value_from_schema( '2016-06-30', $schema ) ); } - public function test_format_ipv4() { + public function test_format_ip() { $schema = array( 'type' => 'string', - 'format' => 'ipv4', + 'format' => 'ip', ); + + // IPv4. $this->assertTrue( rest_validate_value_from_schema( '127.0.0.1', $schema ) ); $this->assertWPError( rest_validate_value_from_schema( '3333.3333.3333.3333', $schema ) ); $this->assertWPError( rest_validate_value_from_schema( '1', $schema ) ); + + // IPv6. + $this->assertTrue( rest_validate_value_from_schema( '::1', $schema ) ); // Loopback, compressed, non-routable. + $this->assertTrue( rest_validate_value_from_schema( '::', $schema ) ); // Unspecified, compressed, non-routable. + $this->assertTrue( rest_validate_value_from_schema( '0:0:0:0:0:0:0:1', $schema ) ); // Loopback, full. + $this->assertTrue( rest_validate_value_from_schema( '0:0:0:0:0:0:0:0', $schema ) ); // Unspecified, full. + $this->assertTrue( rest_validate_value_from_schema( '2001:DB8:0:0:8:800:200C:417A', $schema ) ); // Unicast, full. + $this->assertTrue( rest_validate_value_from_schema( 'FF01:0:0:0:0:0:0:101', $schema ) ); // Multicast, full. + $this->assertTrue( rest_validate_value_from_schema( '2001:DB8::8:800:200C:417A', $schema ) ); // Unicast, compressed. + $this->assertTrue( rest_validate_value_from_schema( 'FF01::101', $schema ) ); // Multicast, compressed. + $this->assertTrue( rest_validate_value_from_schema( 'fe80::217:f2ff:fe07:ed62', $schema ) ); + $this->assertWPError( rest_validate_value_from_schema( '', $schema ) ); // Empty string. + $this->assertWPError( rest_validate_value_from_schema( '2001:DB8:0:0:8:800:200C:417A:221', $schema ) ); // Unicast, full. + $this->assertWPError( rest_validate_value_from_schema( 'FF01::101::2', $schema ) ); // Multicast, compressed. } public function test_type_array() {