Make WordPress Core

Changeset 38982


Ignore:
Timestamp:
10/27/2016 04:07:06 PM (10 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.