Make WordPress Core

Changeset 48300


Ignore:
Timestamp:
07/04/2020 07:51:10 PM (6 years ago)
Author:
TimothyBlynJacobs
Message:

REST API: Only validate the format keyword if the type is a string.

This allows for using multi-type support with a string that has a format. For backwards compatibility support, the format validation will still apply if the type is not specified, or it is invalid.

Two new doing it wrong notices are issued when omitting a type, or using an invalid type.

Props ryotsun.
Fixes #50189.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api.php

    r48273 r48300  
    12821282 */
    12831283function rest_validate_value_from_schema( $value, $args, $param = '' ) {
     1284        $allowed_types = array( 'array', 'object', 'string', 'number', 'integer', 'boolean', 'null' );
     1285
     1286        if ( ! isset( $args['type'] ) ) {
     1287                _doing_it_wrong( __FUNCTION__, __( 'The "type" schema keyword is required.' ), '5.5.0' );
     1288        }
     1289
    12841290        if ( is_array( $args['type'] ) ) {
    12851291                foreach ( $args['type'] as $type ) {
     
    12941300                /* translators: 1: Parameter, 2: List of types. */
    12951301                return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not of type %2$s.' ), $param, implode( ',', $args['type'] ) ) );
     1302        }
     1303
     1304        if ( ! in_array( $args['type'], $allowed_types, true ) ) {
     1305                _doing_it_wrong(
     1306                        __FUNCTION__,
     1307                        /* translators: 1. The list of allowed types. */
     1308                        wp_sprintf( __( 'The "type" schema keyword can only be on of the built-in types: %l.' ), $allowed_types ),
     1309                        '5.5.0'
     1310                );
    12961311        }
    12971312
     
    14501465        }
    14511466
    1452         if ( isset( $args['format'] ) ) {
     1467        // The "format" keyword should only be applied to strings. However, for backwards compatibility,
     1468        // we allow the "format" keyword if the type keyword was not specified, or was set to an invalid value.
     1469        if ( isset( $args['format'] ) && ( ! isset( $args['type'] ) || 'string' === $args['type'] || ! in_array( $args['type'], $allowed_types, true ) ) ) {
    14531470                switch ( $args['format'] ) {
    14541471                        case 'hex-color':
     
    15391556 */
    15401557function rest_sanitize_value_from_schema( $value, $args ) {
     1558        $allowed_types = array( 'array', 'object', 'string', 'number', 'integer', 'boolean', 'null' );
     1559
     1560        if ( ! isset( $args['type'] ) ) {
     1561                _doing_it_wrong( __FUNCTION__, __( 'The "type" schema keyword is required.' ), '5.5.0' );
     1562        }
     1563
    15411564        if ( is_array( $args['type'] ) ) {
    15421565                // Determine which type the value was validated against,
     
    15591582
    15601583                $args['type'] = $validated_type;
     1584        }
     1585
     1586        if ( ! in_array( $args['type'], $allowed_types, true ) ) {
     1587                _doing_it_wrong(
     1588                        __FUNCTION__,
     1589                        /* translators: 1. The list of allowed types. */
     1590                        wp_sprintf( __( 'The "type" schema keyword can only be on of the built-in types: %l.' ), $allowed_types ),
     1591                        '5.5.0'
     1592                );
    15611593        }
    15621594
     
    16201652        }
    16211653
    1622         if ( isset( $args['format'] ) ) {
     1654        // This behavior matches rest_validate_value_from_schema().
     1655        if ( isset( $args['format'] ) && ( ! isset( $args['type'] ) || 'string' === $args['type'] || ! in_array( $args['type'], $allowed_types, true ) ) ) {
    16231656                switch ( $args['format'] ) {
    16241657                        case 'hex-color':
  • trunk/tests/phpunit/tests/rest-api/rest-schema-sanitization.php

    r47753 r48300  
    313313
    314314        public function test_type_unknown() {
     315                $this->setExpectedIncorrectUsage( 'rest_sanitize_value_from_schema' );
     316
    315317                $schema = array(
    316318                        'type' => 'lalala',
     
    322324
    323325        public function test_no_type() {
     326                $this->setExpectedIncorrectUsage( 'rest_sanitize_value_from_schema' );
     327
    324328                $schema = array(
    325329                        'type' => null,
     
    339343                $this->assertEquals( '2019-09-19T18:00:00', rest_sanitize_value_from_schema( '2019-09-19T18:00:00', $schema ) );
    340344                $this->assertNull( rest_sanitize_value_from_schema( 'lalala', $schema ) );
     345        }
     346
     347        /**
     348         * @ticket 50189
     349         */
     350        public function test_format_validation_is_skipped_if_non_string_type() {
     351                $schema = array(
     352                        'type'   => 'array',
     353                        'format' => 'hex-color',
     354                );
     355                $this->assertEquals( array( '#fff' ), rest_sanitize_value_from_schema( '#fff', $schema ) );
     356                $this->assertEquals( array( '#qrst' ), rest_sanitize_value_from_schema( '#qrst', $schema ) );
     357        }
     358
     359        /**
     360         * @ticket 50189
     361         */
     362        public function test_format_validation_is_applied_if_missing_type() {
     363                $this->expectException( 'PHPUnit_Framework_Error_Notice' ); // For the undefined index.
     364                $this->setExpectedIncorrectUsage( 'rest_sanitize_value_from_schema' );
     365
     366                $schema = array( 'format' => 'hex-color' );
     367                $this->assertEquals( '#abc', rest_sanitize_value_from_schema( '#abc', $schema ) );
     368                $this->assertEquals( '', rest_sanitize_value_from_schema( '#jkl', $schema ) );
     369        }
     370
     371        /**
     372         * @ticket 50189
     373         */
     374        public function test_format_validation_is_applied_if_unknown_type() {
     375                $this->setExpectedIncorrectUsage( 'rest_sanitize_value_from_schema' );
     376
     377                $schema = array(
     378                        'format' => 'hex-color',
     379                        'type'   => 'str',
     380                );
     381                $this->assertEquals( '#abc', rest_sanitize_value_from_schema( '#abc', $schema ) );
     382                $this->assertEquals( '', rest_sanitize_value_from_schema( '#jkl', $schema ) );
    341383        }
    342384
  • trunk/tests/phpunit/tests/rest-api/rest-schema-validation.php

    r48190 r48300  
    138138        }
    139139
     140        /**
     141         * @ticket 50189
     142         */
     143        public function test_format_validation_is_skipped_if_non_string_type() {
     144                $schema = array(
     145                        'type'   => 'array',
     146                        'items'  => array(
     147                                'type' => 'string',
     148                        ),
     149                        'format' => 'email',
     150                );
     151                $this->assertTrue( rest_validate_value_from_schema( 'email@example.com', $schema ) );
     152                $this->assertTrue( rest_validate_value_from_schema( 'email', $schema ) );
     153        }
     154
     155        /**
     156         * @ticket 50189
     157         */
     158        public function test_format_validation_is_applied_if_missing_type() {
     159                $this->expectException( 'PHPUnit_Framework_Error_Notice' ); // For the undefined index.
     160                $this->setExpectedIncorrectUsage( 'rest_validate_value_from_schema' );
     161
     162                $schema = array( 'format' => 'email' );
     163                $this->assertTrue( rest_validate_value_from_schema( 'email@example.com', $schema ) );
     164                $this->assertWPError( rest_validate_value_from_schema( 'email', $schema ) );
     165        }
     166
     167        /**
     168         * @ticket 50189
     169         */
     170        public function test_format_validation_is_applied_if_unknown_type() {
     171                $this->setExpectedIncorrectUsage( 'rest_validate_value_from_schema' );
     172
     173                $schema = array(
     174                        'format' => 'email',
     175                        'type'   => 'str',
     176                );
     177                $this->assertTrue( rest_validate_value_from_schema( 'email@example.com', $schema ) );
     178                $this->assertWPError( rest_validate_value_from_schema( 'email', $schema ) );
     179        }
     180
    140181        public function test_type_array() {
    141182                $schema = array(
     
    323364
    324365        public function test_type_unknown() {
     366                $this->setExpectedIncorrectUsage( 'rest_validate_value_from_schema' );
     367
    325368                $schema = array(
    326369                        'type' => 'lalala',
Note: See TracChangeset for help on using the changeset viewer.