Skip to content

Commit

Permalink
Shortcodes: Restrict ajax handler for media shortcode.
Browse files Browse the repository at this point in the history
Props tykoted, xknown, peterwilsoncc, antpb, jorbin.





git-svn-id: https://develop.svn.wordpress.org/trunk@56838 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
audrasjb committed Oct 12, 2023
1 parent ffba0d1 commit 1077af7
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 1 deletion.
18 changes: 17 additions & 1 deletion src/wp-admin/includes/ajax-actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -3882,13 +3882,29 @@ function wp_ajax_parse_media_shortcode() {

$shortcode = wp_unslash( $_POST['shortcode'] );

// Only process previews for media related shortcodes:
$found_shortcodes = get_shortcode_tags_in_content( $shortcode );
$media_shortcodes = array(
'audio',
'embed',
'playlist',
'video',
'gallery',
);

$other_shortcodes = array_diff( $found_shortcodes, $media_shortcodes );

if ( ! empty( $other_shortcodes ) ) {
wp_send_json_error();
}

if ( ! empty( $_POST['post_ID'] ) ) {
$post = get_post( (int) $_POST['post_ID'] );
}

// The embed shortcode requires a post.
if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) {
if ( 'embed' === $shortcode ) {
if ( in_array( 'embed', $found_shortcodes, true ) ) {
wp_send_json_error();
}
} else {
Expand Down
22 changes: 22 additions & 0 deletions src/wp-includes/media.php
Original file line number Diff line number Diff line change
Expand Up @@ -2607,6 +2607,7 @@ function gallery_shortcode( $attr ) {
$attachments[ $val->ID ] = $_attachments[ $key ];
}
} elseif ( ! empty( $atts['exclude'] ) ) {
$post_parent_id = $id;
$attachments = get_children(
array(
'post_parent' => $id,
Expand All @@ -2619,6 +2620,7 @@ function gallery_shortcode( $attr ) {
)
);
} else {
$post_parent_id = $id;
$attachments = get_children(
array(
'post_parent' => $id,
Expand All @@ -2631,6 +2633,17 @@ function gallery_shortcode( $attr ) {
);
}

if ( ! empty( $post_parent_id ) ) {
$post_parent = get_post( $post_parent_id );

// terminate the shortcode execution if user cannot read the post or password-protected
if (
( ! is_post_publicly_viewable( $post_parent->ID ) && ! current_user_can( 'read_post', $post_parent->ID ) )
|| post_password_required( $post_parent ) ) {
return '';
}
}

if ( empty( $attachments ) ) {
return '';
}
Expand Down Expand Up @@ -2963,6 +2976,15 @@ function wp_playlist_shortcode( $attr ) {
$attachments = get_children( $args );
}

if ( ! empty( $args['post_parent'] ) ) {
$post_parent = get_post( $id );

// terminate the shortcode execution if user cannot read the post or password-protected
if ( ! current_user_can( 'read_post', $post_parent->ID ) || post_password_required( $post_parent ) ) {
return '';
}
}

if ( empty( $attachments ) ) {
return '';
}
Expand Down
38 changes: 38 additions & 0 deletions src/wp-includes/shortcodes.php
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,44 @@ function has_shortcode( $content, $tag ) {
return false;
}

/**
* Returns a list of registered shortcode names found in the given content.
*
* Example usage:
*
* get_shortcode_tags_in_content( '[audio src="file.mp3"][/audio] [foo] [gallery ids="1,2,3"]' );
* // array( 'audio', 'gallery' )
*
* @since 6.3.2
*
* @param string $content The content to check.
* @return string[] An array of registered shortcode names found in the content.
*/
function get_shortcode_tags_in_content( $content ) {
if ( false === strpos( $content, '[' ) ) {
return array();
}

preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER );
if ( empty( $matches ) ) {
return array();
}

$tags = array();
foreach ( $matches as $shortcode ) {
$tags[] = $shortcode[2];

if ( ! empty( $shortcode[5] ) ) {
$deep_tags = get_shortcode_tags_in_content( $shortcode[5] );
if ( ! empty( $deep_tags ) ) {
$tags = array_merge( $tags, $deep_tags );
}
}
}

return $tags;
}

/**
* Searches content for shortcodes and filter shortcodes through their hooks.
*
Expand Down
85 changes: 85 additions & 0 deletions tests/phpunit/tests/ajax/wpAjaxParseMediaShortcode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

/**
* Admin Ajax functions to be tested.
*/
require_once ABSPATH . 'wp-admin/includes/ajax-actions.php';

/**
* Testing Ajax save draft functionality.
*
* @package WordPress
* @subpackage UnitTests
* @since 6.3.2
*
* @group ajax
*
* @covers ::wp_ajax_parse-media-shortcode
*/
class Tests_Ajax_wpAjaxParseMediaShortcode extends WP_Ajax_UnitTestCase {
const SHORTCODE_RETURN_VALUE = 'TEST';
private static $media_id;
public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
self::$media_id = self::factory()->attachment->create_object(
get_temp_dir() . 'canola.jpg',
0,
array(
'post_mime_type' => 'image/jpeg',
'post_excerpt' => 'A sample caption',
'post_name' => 'restapi-client-fixture-attachment',
'post_title' => 'REST API Client Fixture: Attachment',
'post_date' => '2017-02-14 00:00:00',
'post_date_gmt' => '2017-02-14 00:00:00',
'post_author' => 0,
)
);
}
/**
* @dataProvider shortcode_provider
*/
public function test_parse_shortcode( array $payload, $expected ) {
add_shortcode( 'test', array( $this, 'shortcode_test' ) );

$_POST = array_merge(
array(
'action' => 'paser-media-shortcode',
'type' => '',
),
$payload
);
// Make the request.
try {
$this->_handleAjax( 'parse-media-shortcode' );
} catch ( WPAjaxDieContinueException $e ) {
unset( $e );
}
// Get the response, it is in heartbeat's response.
$response = json_decode( $this->_last_response, true );
$body = $response['data']['body'] ?? '';
if ( $body ) {
$this->assertStringNotContainsString( self::SHORTCODE_RETURN_VALUE, $body );
}
$this->assertSame( $expected['success'], $response['success'] );
}

public function shortcode_test() {
return self::SHORTCODE_RETURN_VALUE;
}

public function shortcode_provider() {
return array(
'gallery_shortcode_is_allowed' => array(
'payload' => array( 'shortcode' => '[gallery ids=" ' . self::$media_id . '"]' ),
'expected' => array( 'success' => true ),
),
'gallery_and_custom_test_shortcode_is_not_allowed' => array(
'payload' => array( 'shortcode' => '[gallery ids=" ' . self::$media_id . '"] [test]' ),
'expected' => array( 'success' => false ),
),
'custom_test_shortcode_is_not_allowed' => array(
'payload' => array( 'shortcode' => '[test]' ),
'expected' => array( 'success' => false ),
),
);
}
}

0 comments on commit 1077af7

Please sign in to comment.