-
Notifications
You must be signed in to change notification settings - Fork 800
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ensure block comments are always sanitized on save and render (#35246)
- Loading branch information
1 parent
ea54fd3
commit cd15410
Showing
5 changed files
with
210 additions
and
86 deletions.
There are no files selected for viewing
4 changes: 4 additions & 0 deletions
4
projects/packages/jetpack-mu-wpcom/changelog/fix-sanitize-block-comments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Significance: patch | ||
Type: security | ||
|
||
|
112 changes: 112 additions & 0 deletions
112
...ackages/jetpack-mu-wpcom/src/features/verbum-comments/assets/class-verbum-block-utils.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
<?php | ||
/** | ||
* Verbum Block Utils | ||
* | ||
* @package automattic/jetpack-mu-plugins | ||
*/ | ||
|
||
/** | ||
* Verbum_Block_Utils offer utility functions for sanitizing and parsing blocks. | ||
*/ | ||
class Verbum_Block_Utils { | ||
/** | ||
* Remove blocks that aren't allowed | ||
* | ||
* @param string $content - Text of the comment. | ||
* @return string | ||
*/ | ||
public static function remove_blocks( $content ) { | ||
if ( ! has_blocks( $content ) ) { | ||
return $content; | ||
} | ||
|
||
$allowed_blocks = self::get_allowed_blocks(); | ||
// The block attributes come slashed and `parse_blocks` won't be able to parse them. | ||
$content = wp_unslash( $content ); | ||
$blocks = parse_blocks( $content ); | ||
$output = ''; | ||
|
||
foreach ( $blocks as $block ) { | ||
if ( in_array( $block['blockName'], $allowed_blocks, true ) ) { | ||
$output .= serialize_block( $block ); | ||
} | ||
} | ||
|
||
return ltrim( $output ); | ||
} | ||
|
||
/** | ||
* Filter blocks from content according to our allowed blocks | ||
* | ||
* @param string $content - The content to be processed. | ||
* @return array | ||
*/ | ||
private static function filter_blocks( $content ) { | ||
$registry = new WP_Block_Type_Registry(); | ||
$allowed_blocks = self::get_allowed_blocks(); | ||
|
||
foreach ( $allowed_blocks as $allowed_block ) { | ||
$registry->register( $allowed_block ); | ||
} | ||
|
||
$filtered_blocks = array(); | ||
$blocks = parse_blocks( $content ); | ||
|
||
foreach ( $blocks as $block ) { | ||
$filtered_blocks[] = new WP_Block( $block, array(), $registry ); | ||
} | ||
|
||
return $filtered_blocks; | ||
} | ||
|
||
/** | ||
* Render blocks in the comment content | ||
* Filters blocks that aren't allowed | ||
* | ||
* @param string $comment_content - Text of the comment. | ||
* @return string | ||
*/ | ||
public static function render_verbum_blocks( $comment_content ) { | ||
if ( ! has_blocks( $comment_content ) ) { | ||
return $comment_content; | ||
} | ||
|
||
$blocks = self::filter_blocks( $comment_content ); | ||
$comment_content = ''; | ||
|
||
foreach ( $blocks as $block ) { | ||
$comment_content .= $block->render(); | ||
} | ||
|
||
return $comment_content; | ||
} | ||
|
||
/** | ||
* Get a list of allowed blocks by looking at the allowed comment tags | ||
* | ||
* @return string[] | ||
*/ | ||
public static function get_allowed_blocks() { | ||
global $allowedtags; | ||
|
||
$allowed_blocks = array( 'core/paragraph', 'core/list', 'core/code', 'core/list-item', 'core/quote', 'core/image', 'core/embed' ); | ||
$convert = array( | ||
'blockquote' => 'core/quote', | ||
'h1' => 'core/heading', | ||
'h2' => 'core/heading', | ||
'h3' => 'core/heading', | ||
'img' => 'core/image', | ||
'ul' => 'core/list', | ||
'ol' => 'core/list', | ||
'pre' => 'core/code', | ||
); | ||
|
||
foreach ( array_keys( $allowedtags ) as $tag ) { | ||
if ( isset( $convert[ $tag ] ) ) { | ||
$allowed_blocks[] = $convert[ $tag ]; | ||
} | ||
} | ||
|
||
return $allowed_blocks; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
...ges/jetpack-mu-wpcom/tests/php/features/verbum-comments/class-verbum-block-utils-test.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
<?php | ||
/** | ||
* Test class for Verbum_Block_Utils. | ||
* | ||
* @package automattic/jetpack-mu-wpcom | ||
*/ | ||
|
||
use Automattic\Jetpack\Jetpack_Mu_Wpcom; | ||
require_once Jetpack_Mu_Wpcom::PKG_DIR . 'src/features/verbum-comments/assets/class-verbum-block-utils.php'; | ||
|
||
/** | ||
* Test class for Verbum_Block_Utils. | ||
* | ||
* @coversDefaultClass Verbum_Block_Utils | ||
*/ | ||
class Verbum_Block_Utils_Test extends \WorDBless\BaseTestCase { | ||
/** | ||
* Ensure string comments are not modified when 'render_verbum_blocks' is applied | ||
* | ||
* @covers Verbum_Block_Utils::render_verbum_blocks | ||
*/ | ||
public function test_comment_text_string_comment() { | ||
$comment_content = 'This is a test comment'; | ||
$filtered_content = Verbum_Block_Utils::render_verbum_blocks( $comment_content ); | ||
$this->assertEquals( $comment_content, $filtered_content ); | ||
} | ||
|
||
/** | ||
* Ensure blocks are filtered when 'render_verbum_blocks' is applied | ||
* | ||
* @covers Verbum_Block_Utils::render_verbum_blocks | ||
*/ | ||
public function test_comment_text_block_sanitization() { | ||
$comment_content = '<!-- wp:paragraph -->Testing<!-- /wp:paragraph --><!-- wp:latest-posts -->'; | ||
$filtered_content = Verbum_Block_Utils::render_verbum_blocks( $comment_content ); | ||
$this->assertEquals( 'Testing', $filtered_content ); | ||
} | ||
|
||
/** | ||
* Ensure blocks are rendered properly | ||
* | ||
* @covers Verbum_Block_Utils::render_verbum_blocks | ||
*/ | ||
public function test_comment_text_block_sanitization_sanity_check() { | ||
$comment_content = '<!-- wp:paragraph --><p>test</p><!-- /wp:paragraph --><!-- wp:list --><ul><!-- wp:list-item --><li>1</li><!-- /wp:list-item --><!-- wp:list-item --><li>2</li><!-- /wp:list-item --><!-- wp:list-item --><li>3</li><!-- /wp:list-item --></ul><!-- /wp:list --><!-- wp:quote --><blockquote class="wp-block-quote"><!-- wp:paragraph --><p>something</p><!-- /wp:paragraph --><cite>someone</cite></blockquote><!-- /wp:quote -->'; | ||
$filtered_content = preg_replace( '/\R+/', '', Verbum_Block_Utils::render_verbum_blocks( $comment_content ) ); | ||
|
||
$expected_content = '<p>test</p><ul><li>1</li><li>2</li><li>3</li></ul><blockquote class="wp-block-quote"><p>something</p><cite>someone</cite></blockquote>'; | ||
$this->assertEquals( $expected_content, $filtered_content ); | ||
} | ||
|
||
/** | ||
* Ensure innerBlocks are filtered when 'render_verbum_blocks' is applied | ||
* | ||
* @covers Verbum_Block_Utils::render_verbum_blocks | ||
*/ | ||
public function test_comment_text_block_sanitization_inner_blocks() { | ||
$comment_content = '<!-- wp:paragraph {} --><!-- wp:latest-posts --><!-- /wp:paragraph -->'; | ||
$filtered_content = Verbum_Block_Utils::render_verbum_blocks( $comment_content ); | ||
$this->assertSame( '', $filtered_content ); | ||
} | ||
|
||
/** | ||
* Ensure string comments are not modified when 'pre_comment_content' is applied | ||
* | ||
* @covers Verbum_Block_Utils::remove_blocks | ||
*/ | ||
public function test_pre_comment_content_string_comment() { | ||
$comment_content = 'This is a test comment'; | ||
$filtered_content = Verbum_Block_Utils::remove_blocks( $comment_content ); | ||
$this->assertEquals( $comment_content, $filtered_content ); | ||
} | ||
|
||
/** | ||
* Ensure blocks are filtered when 'pre_comment_content' is applied | ||
* | ||
* @covers Verbum_Block_Utils::remove_blocks | ||
*/ | ||
public function test_pre_comment_content__block_sanitization() { | ||
$comment_content = '<!-- wp:paragraph -->Testing<!-- /wp:paragraph --><!-- wp:latest-posts -->'; | ||
$filtered_content = Verbum_Block_Utils::remove_blocks( $comment_content ); | ||
$this->assertEquals( '<!-- wp:paragraph -->Testing<!-- /wp:paragraph -->', $filtered_content ); | ||
} | ||
} |