From 8f39f8ebb7102a49c88cee450c23d67e0dd49e24 Mon Sep 17 00:00:00 2001 From: Timothy Jacobs Date: Sat, 11 Jul 2020 20:32:19 +0000 Subject: [PATCH] REST API: Sanitize block renderer attributes. In [48069] the Block Renderer was changed to register a single route for all dynamic blocks. Validation was dynamically applied based on the requested block, but sanitization was not. This commit adds the same sanitization back to the block attributes. Props manooweb. Fixes #50620. See #48079. git-svn-id: https://develop.svn.wordpress.org/trunk@48437 602fd350-edb4-49c9-b593-d223f7449a82 --- package-lock.json | 9 ++- ...lass-wp-rest-block-renderer-controller.php | 16 +++++ .../rest-block-renderer-controller.php | 62 +++++++++++++++++++ 3 files changed, 84 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 49acf29c3b..582ae772a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5939,7 +5939,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } @@ -10566,7 +10567,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } @@ -23584,7 +23586,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php index 3388078d05..07a389e794 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php @@ -70,6 +70,22 @@ class WP_REST_Block_Renderer_Controller extends WP_REST_Controller { return rest_validate_value_from_schema( $value, $schema ); }, + 'sanitize_callback' => static function ( $value, $request ) { + $block = WP_Block_Type_Registry::get_instance()->get_registered( $request['name'] ); + + if ( ! $block ) { + // This will get rejected in ::get_item(). + return true; + } + + $schema = array( + 'type' => 'object', + 'properties' => $block->get_attributes(), + 'additionalProperties' => false, + ); + + return rest_sanitize_value_from_schema( $value, $schema ); + }, ), 'post_id' => array( 'description' => __( 'ID of the post context.' ), diff --git a/tests/phpunit/tests/rest-api/rest-block-renderer-controller.php b/tests/phpunit/tests/rest-api/rest-block-renderer-controller.php index 423d4a4947..94c7cf8103 100644 --- a/tests/phpunit/tests/rest-api/rest-block-renderer-controller.php +++ b/tests/phpunit/tests/rest-api/rest-block-renderer-controller.php @@ -55,6 +55,15 @@ class REST_Block_Renderer_Controller_Test extends WP_Test_REST_Controller_Testca */ protected static $non_dynamic_block_name = 'core/non-dynamic'; + /** + * Dynamic block with boolean attributes block name. + * + * @since 5.5.0 + * + * @var string + */ + protected static $dynamic_block_with_boolean_attributes_block_name = 'core/dynamic-block-with-boolean-attributes'; + /** * Test API user's ID. * @@ -127,6 +136,7 @@ class REST_Block_Renderer_Controller_Test extends WP_Test_REST_Controller_Testca $this->register_test_block(); $this->register_post_context_test_block(); $this->register_non_dynamic_block(); + $this->register_dynamic_block_with_boolean_attributes(); parent::setUp(); } @@ -139,6 +149,7 @@ class REST_Block_Renderer_Controller_Test extends WP_Test_REST_Controller_Testca WP_Block_Type_Registry::get_instance()->unregister( self::$block_name ); WP_Block_Type_Registry::get_instance()->unregister( self::$context_block_name ); WP_Block_Type_Registry::get_instance()->unregister( self::$non_dynamic_block_name ); + WP_Block_Type_Registry::get_instance()->unregister( self::$dynamic_block_with_boolean_attributes_block_name ); parent::tearDown(); } @@ -195,6 +206,30 @@ class REST_Block_Renderer_Controller_Test extends WP_Test_REST_Controller_Testca register_block_type( self::$non_dynamic_block_name ); } + /** + * Registers the dynamic with boolean attributes block name. + * + * @since 5.5.0 + */ + protected function register_dynamic_block_with_boolean_attributes() { + register_block_type( + self::$dynamic_block_with_boolean_attributes_block_name, + array( + 'attributes' => array( + 'boolean_true_attribute' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'boolean_false_attribute' => array( + 'type' => 'boolean', + 'default' => false, + ), + ), + 'render_callback' => array( $this, 'render_test_block' ), + ) + ); + } + /** * Test render callback. * @@ -522,6 +557,33 @@ class REST_Block_Renderer_Controller_Test extends WP_Test_REST_Controller_Testca $this->assertErrorResponse( 'block_invalid', $response, 404 ); } + /** + * @ticket 50620 + */ + public function test_get_sanitized_attributes_for_dynamic_block_with_boolean_attributes() { + wp_set_current_user( self::$user_id ); + + $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$dynamic_block_with_boolean_attributes_block_name ); + + $attributes = array( + 'boolean_true_attribute' => 'true', + 'boolean_false_attribute' => 'false', + ); + + $expected = array( + 'boolean_true_attribute' => true, + 'boolean_false_attribute' => false, + ); + + $request->set_param( 'context', 'edit' ); + $request->set_param( 'attributes', $attributes ); + $response = rest_get_server()->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + $data = $response->get_data(); + + $this->assertSame( $expected, json_decode( $data['rendered'], true ) ); + } + /** * Get item schema. *