Make WordPress Core

Changeset 48300


Ignore:
Timestamp:
07/04/2020 07:51:10 PM (4 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.