Make WordPress Core

Changeset 38982


Ignore:
Timestamp:
10/27/2016 04:07:06 PM (8 years ago)
Author:
rachelbaker
Message:

REST API: Return WP_Error when a client is attempting to update an option with a non-scalar value to null.

A null value is returned in the response for any option that has a non-scalar value.

To protect clients from accidentally including the null values from a response object in a request, we do not allow options with non-scalar values to be updated to null. Without this added protection a client could mistakenly delete all options that have non-scalar values from the database.

Props joehoyle, rachelbaker.
Fixes #38527.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php

    r38954 r38982  
    9696     */
    9797    protected function prepare_value( $value, $schema ) {
     98        // If the value is not a scalar, it's not possible to cast it to
     99        // anything.
     100        if ( ! is_scalar( $value ) ) {
     101            return null;
     102        }
     103
    98104        switch ( $schema['type'] ) {
    99105            case 'string':
     
    142148            }
    143149
    144             // A null value means reset the option, which is essentially deleting it
    145             // from the database and then relying on the default value.
     150            /**
     151            * A `null` value for an option would have the same effect as
     152            * deleting the option from the database, and relying on the
     153            * default value.
     154            */
    146155            if ( is_null( $request[ $name ] ) ) {
     156                /**
     157                 * A `null` value is returned in the response for any option
     158                 * that has a non-scalar value.
     159                 *
     160                 * To protect clients from accidentally including the `null`
     161                 * values from a response object in a request, we do not allow
     162                 * options with non-scalar values to be updated to `null`.
     163                 * Without this added protection a client could mistakenly
     164                 * delete all options that have non-scalar values from the
     165                 * database.
     166                 */
     167                if ( ! is_scalar( get_option( $args['option_name'], false ) ) ) {
     168                    return new WP_Error(
     169                        'rest_invalid_stored_value', sprintf( __( 'The %s property has an invalid stored value, and cannot be updated to null.' ), $name ), array( 'status' => 500 )
     170                    );
     171                }
     172
    147173                delete_option( $args['option_name'] );
    148174            } else {
  • trunk/tests/phpunit/tests/rest-api/rest-settings-controller.php

    r38975 r38982  
    160160    }
    161161
     162    public function test_get_item_with_invalid_value_array_in_options() {
     163        wp_set_current_user( self::$administrator );
     164
     165        register_setting( 'somegroup', 'mycustomsetting', array(
     166            'show_in_rest' => array(
     167                'name'   => 'mycustomsettinginrest',
     168                'schema' => array(
     169                    'enum'    => array( 'validvalue1', 'validvalue2' ),
     170                    'default' => 'validvalue1',
     171                ),
     172            ),
     173            'type'         => 'string',
     174        ) );
     175
     176        update_option( 'mycustomsetting', array( 'A sneaky array!' ) );
     177
     178        $request = new WP_REST_Request( 'GET', '/wp/v2/settings' );
     179        $response = $this->server->dispatch( $request );
     180        $data = $response->get_data();
     181        $this->assertEquals( null, $data['mycustomsettinginrest'] );
     182    }
     183
     184    public function test_get_item_with_invalid_object_array_in_options() {
     185        wp_set_current_user( self::$administrator );
     186
     187        register_setting( 'somegroup', 'mycustomsetting', array(
     188            'show_in_rest' => array(
     189                'name'   => 'mycustomsettinginrest',
     190                'schema' => array(
     191                    'enum'    => array( 'validvalue1', 'validvalue2' ),
     192                    'default' => 'validvalue1',
     193                ),
     194            ),
     195            'type'         => 'string',
     196        ) );
     197
     198        update_option( 'mycustomsetting', (object) array( 'A sneaky array!' ) );
     199
     200        $request = new WP_REST_Request( 'GET', '/wp/v2/settings' );
     201        $response = $this->server->dispatch( $request );
     202        $data = $response->get_data();
     203        $this->assertEquals( null, $data['mycustomsettinginrest'] );
     204    }
     205
     206
    162207    public function test_create_item() {
    163208    }
     
    249294    }
    250295
     296    public function test_update_item_with_invalid_stored_value_in_options() {
     297        wp_set_current_user( self::$administrator );
     298
     299        register_setting( 'somegroup', 'mycustomsetting', array(
     300            'show_in_rest' => true,
     301            'type'         => 'string',
     302        ) );
     303        update_option( 'mycustomsetting', array( 'A sneaky array!' ) );
     304
     305        wp_set_current_user( self::$administrator );
     306        $request = new WP_REST_Request( 'PUT', '/wp/v2/settings' );
     307        $request->set_param( 'mycustomsetting', null );
     308        $response = $this->server->dispatch( $request );
     309
     310        $this->assertErrorResponse( 'rest_invalid_stored_value', $response, 500 );
     311    }
     312
    251313    public function test_delete_item() {
    252314    }
Note: See TracChangeset for help on using the changeset viewer.