Skip to content

Commit

Permalink
Grouped backports to the 5.1 branch.
Browse files Browse the repository at this point in the history
- Media: Prevent CSRF setting attachment thumbnails.
- Embeds: Add protocol validation for WordPress Embed code.
- I18N: Introduce sanitization function for locale.
- Editor: Ensure block comments are of a valid form.

Merges [55760-55764] to the 5.1 branch.
Props dd32, isabel_brison, martinkrcho, matveb, ocean90, paulkevan, peterwilsoncc, timothyblynjacobs, xknown, youknowriad.



git-svn-id: https://develop.svn.wordpress.org/branches/5.1@55790 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
audrasjb committed May 16, 2023
1 parent e2e1419 commit 96938e4
Show file tree
Hide file tree
Showing 13 changed files with 217 additions and 5 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "WordPress",
"version": "5.1.15",
"version": "5.1.16",
"description": "WordPress is open source software you can use to create a beautiful website, blog, or app.",
"repository": {
"type": "svn",
Expand Down
6 changes: 6 additions & 0 deletions src/js/_enqueues/wp/embed.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

var iframes = document.querySelectorAll( 'iframe[data-secret="' + data.secret + '"]' ),
blockquotes = document.querySelectorAll( 'blockquote[data-secret="' + data.secret + '"]' ),
allowedProtocols = new RegExp( '^https?:$', 'i' ),
i, source, height, sourceURL, targetURL;

for ( i = 0; i < blockquotes.length; i++ ) {
Expand Down Expand Up @@ -79,6 +80,11 @@
sourceURL.href = source.getAttribute( 'src' );
targetURL.href = data.value;

/* Only follow link if the protocol is in the allow list. */
if ( ! allowedProtocols.test( targetURL.protocol ) ) {
continue;
}

/* Only continue if link hostname matches iframe's hostname. */
if ( targetURL.host === sourceURL.host ) {
if ( document.activeElement === source ) {
Expand Down
1 change: 1 addition & 0 deletions src/js/media/views/frame/video-details.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ VideoDetails = MediaDetails.extend(/** @lends wp.media.view.MediaFrame.VideoDeta

wp.ajax.send( 'set-attachment-thumbnail', {
data : {
_ajax_nonce: wp.media.view.settings.nonce.setAttachmentThumbnail,
urls: urls,
thumbnail_id: attachment.get( 'id' )
}
Expand Down
20 changes: 20 additions & 0 deletions src/wp-admin/about.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,26 @@

<div class="changelog point-releases">
<h3><?php _e( 'Maintenance and Security Releases' ); ?></h3>
<p>
<?php
printf(
/* translators: %s: WordPress version number */
__( '<strong>Version %s</strong> addressed some security issues.' ),
'5.1.16'
);
?>
<?php
printf(
/* translators: %s: HelpHub URL */
__( 'For more information, see <a href="%s">the release notes</a>.' ),
sprintf(
/* translators: %s: WordPress version */
esc_url( __( 'https://wordpress.org/support/wordpress-version/version-%s/' ) ),
sanitize_title( '5.1.16' )
)
);
?>
</p>
<p>
<?php
printf(
Expand Down
4 changes: 4 additions & 0 deletions src/wp-admin/includes/ajax-actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -2507,6 +2507,10 @@ function wp_ajax_set_attachment_thumbnail() {
wp_send_json_error();
}

if ( false === check_ajax_referer( 'set-attachment-thumbnail', '_ajax_nonce', false ) ) {
wp_send_json_error();
}

$post_ids = array();
// For each URL, try to find its corresponding post ID.
foreach ( $_POST['urls'] as $url ) {
Expand Down
17 changes: 17 additions & 0 deletions src/wp-includes/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@ function serialize_blocks( $blocks ) {
function filter_block_content( $text, $allowed_html = 'post', $allowed_protocols = array() ) {
$result = '';

if ( false !== strpos( $text, '<!--' ) && false !== strpos( $text, '--->' ) ) {
$text = preg_replace_callback( '%<!--(.*?)--->%', '_filter_block_content_callback', $text );
}

$blocks = parse_blocks( $text );
foreach ( $blocks as $block ) {
$block = filter_block_kses( $block, $allowed_html, $allowed_protocols );
Expand All @@ -280,6 +284,19 @@ function filter_block_content( $text, $allowed_html = 'post', $allowed_protocols
return $result;
}

/**
* Callback used for regular expression replacement in filter_block_content().
*
* @private
* @since 6.2.1
*
* @param array $matches Array of preg_replace_callback matches.
* @return string Replacement string.
*/
function _filter_block_content_callback( $matches ) {
return '<!--' . rtrim( $matches[1], '-' ) . '-->';
}

/**
* Filters and sanitizes a parsed block to remove non-allowable HTML from block
* attribute values.
Expand Down
23 changes: 23 additions & 0 deletions src/wp-includes/formatting.php
Original file line number Diff line number Diff line change
Expand Up @@ -2365,6 +2365,29 @@ function sanitize_html_class( $class, $fallback = '' ) {
return apply_filters( 'sanitize_html_class', $sanitized, $class, $fallback );
}

/**
* Strips out all characters not allowed in a locale name.
*
* @since 6.2.1
*
* @param string $locale_name The locale name to be sanitized.
* @return string The sanitized value.
*/
function sanitize_locale_name( $locale_name ) {
// Limit to A-Z, a-z, 0-9, '_', '-'.
$sanitized = preg_replace( '/[^A-Za-z0-9_-]/', '', $locale_name );

/**
* Filters a sanitized locale name string.
*
* @since 6.2.1
*
* @param string $sanitized The sanitized locale name.
* @param string $locale_name The locale name before sanitization.
*/
return apply_filters( 'sanitize_locale_name', $sanitized, $locale_name );
}

/**
* Converts lone & characters into `&#038;` (a.k.a. `&amp;`)
*
Expand Down
2 changes: 1 addition & 1 deletion src/wp-includes/l10n.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ function determine_locale() {
}

if ( ! empty( $_GET['wp_lang'] ) && ! empty( $GLOBALS['pagenow'] ) && 'wp-login.php' === $GLOBALS['pagenow'] ) {
$determined_locale = sanitize_text_field( $_GET['wp_lang'] );
$determined_locale = sanitize_locale_name( wp_unslash( $_GET['wp_lang'] ) );
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/wp-includes/media.php
Original file line number Diff line number Diff line change
Expand Up @@ -3583,7 +3583,8 @@ function wp_enqueue_media( $args = array() ) {
/** This filter is documented in wp-admin/includes/media.php */
'captions' => ! apply_filters( 'disable_captions', '' ),
'nonce' => array(
'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
'setAttachmentThumbnail' => wp_create_nonce( 'set-attachment-thumbnail' ),
),
'post' => array(
'id' => 0,
Expand Down
2 changes: 1 addition & 1 deletion src/wp-includes/version.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
* @global string $wp_version
*/
$wp_version = '5.1.15-src';
$wp_version = '5.1.16-src';

/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
Expand Down
91 changes: 91 additions & 0 deletions tests/phpunit/tests/ajax/Attachments.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,95 @@ public function test_wp_ajax_send_attachment_to_editor_should_return_a_link() {
$this->assertTrue( $response['success'] );
$this->assertEquals( $expected, $response['data'] );
}

public function test_wp_ajax_set_attachment_thumbnail_success() {
// Become an administrator.
$post = $_POST;
$user_id = self::factory()->user->create(
array(
'role' => 'administrator',
'user_login' => 'user_36578_administrator',
'user_email' => '[email protected]',
)
);
wp_set_current_user( $user_id );
$_POST = array_merge( $_POST, $post );

// Upload the attachment itself.
$filename = DIR_TESTDATA . '/uploads/small-audio.mp3';
$contents = file_get_contents( $filename );

$upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
$attachment = $this->_make_attachment( $upload );

// Upload the thumbnail.
$filename = DIR_TESTDATA . '/images/waffles.jpg';
$contents = file_get_contents( $filename );

$upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
$thumbnail = $this->_make_attachment( $upload );

// Set up a default request.
$_POST['_ajax_nonce'] = wp_create_nonce( 'set-attachment-thumbnail' );
$_POST['thumbnail_id'] = $thumbnail;
$_POST['urls'] = array( wp_get_attachment_url( $attachment ) );

// Make the request.
try {
$this->_handleAjax( 'set-attachment-thumbnail' );
} catch ( WPAjaxDieContinueException $e ) {
unset( $e );
}

// Get the response.
$response = json_decode( $this->_last_response, true );

// Ensure everything is correct.
$this->assertTrue( $response['success'] );
}

public function test_wp_ajax_set_attachment_thumbnail_missing_nonce() {
// Become an administrator.
$post = $_POST;
$user_id = self::factory()->user->create(
array(
'role' => 'administrator',
'user_login' => 'user_36578_administrator',
'user_email' => '[email protected]',
)
);
wp_set_current_user( $user_id );
$_POST = array_merge( $_POST, $post );

// Upload the attachment itself.
$filename = DIR_TESTDATA . '/uploads/small-audio.mp3';
$contents = file_get_contents( $filename );

$upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
$attachment = $this->_make_attachment( $upload );

// Upload the thumbnail.
$filename = DIR_TESTDATA . '/images/waffles.jpg';
$contents = file_get_contents( $filename );

$upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
$thumbnail = $this->_make_attachment( $upload );

// Set up a default request.
$_POST['thumbnail_id'] = $thumbnail;
$_POST['urls'] = array( wp_get_attachment_url( $attachment ) );

// Make the request.
try {
$this->_handleAjax( 'set-attachment-thumbnail' );
} catch ( WPAjaxDieContinueException $e ) {
unset( $e );
}

// Get the response.
$response = json_decode( $this->_last_response, true );

// Check that success is false without sending nonce.
$this->assertFalse( $response['success'] );
}
}
49 changes: 49 additions & 0 deletions tests/phpunit/tests/formatting/sanitizeLocaleName.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

/**
* @group formatting
*
* @covers ::sanitize_locale_name
*/
class Tests_Formatting_SanitizeLocaleName extends WP_UnitTestCase {
/**
* @dataProvider data_sanitize_locale_name_returns_non_empty_string
*/
public function test_sanitize_locale_name_returns_non_empty_string( $expected, $input ) {
$this->assertSame( $expected, sanitize_locale_name( $input ) );
}

public function data_sanitize_locale_name_returns_non_empty_string() {
return array(
// array( expected, input )
array( 'en_US', 'en_US' ),
array( 'en', 'en' ),
array( 'fr_FR', 'fr_FR' ),
array( 'fr_FR', 'fr_FR' ),
array( 'fr_FR-e2791ba830489d23043be8650a22a22b', 'fr_FR-e2791ba830489d23043be8650a22a22b' ),
array( '-fr_FRmo', '-fr_FR.mo' ),
array( '12324', '$12324' ),
array( '4124FRRa', '/4124$$$%%FRRa' ),
array( 'FR', '<FR' ),
array( 'FR_FR', 'FR_FR' ),
array( '--__', '--__' ),
);
}

/**
* @dataProvider data_sanitize_locale_name_returns_empty_string
*/
public function test_sanitize_locale_name_returns_empty_string( $input ) {
$this->assertSame( '', sanitize_locale_name( $input ) );
}

public function data_sanitize_locale_name_returns_empty_string() {
return array(
// array( input )
array( '$<>' ),
array( '/$$$%%\\)' ),
array( '....' ),
array( '@///' ),
);
}
}

0 comments on commit 96938e4

Please sign in to comment.