Skip to content

Commit 8c58df2

Browse files
committed
Grouped backports to the 4.3 branch.
- Comments: Prevent users who can not see a post from seeing comments on it. - Shortcodes: Restrict ajax handler for media shortcode. - Prevent unintended behavior when certain objects are unserialized. Merges [56835], [56836], and [56838] to the 4.1 branch. Props xknown, jorbin, joehoyle, peterwilsoncc, ehtis, tykoted, antpb. git-svn-id: https://develop.svn.wordpress.org/branches/4.3@56852 602fd350-edb4-49c9-b593-d223f7449a82
1 parent a3b484b commit 8c58df2

File tree

7 files changed

+151
-5
lines changed

7 files changed

+151
-5
lines changed

src/wp-admin/includes/ajax-actions.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2869,13 +2869,29 @@ function wp_ajax_parse_media_shortcode() {
28692869

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

2872+
// Only process previews for media related shortcodes:
2873+
$found_shortcodes = get_shortcode_tags_in_content( $shortcode );
2874+
$media_shortcodes = array(
2875+
'audio',
2876+
'embed',
2877+
'playlist',
2878+
'video',
2879+
'gallery',
2880+
);
2881+
2882+
$other_shortcodes = array_diff( $found_shortcodes, $media_shortcodes );
2883+
2884+
if ( ! empty( $other_shortcodes ) ) {
2885+
wp_send_json_error();
2886+
}
2887+
28722888
if ( ! empty( $_POST['post_ID'] ) ) {
28732889
$post = get_post( (int) $_POST['post_ID'] );
28742890
}
28752891

28762892
// the embed shortcode requires a post
28772893
if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) {
2878-
if ( 'embed' === $shortcode ) {
2894+
if ( in_array( 'embed', $found_shortcodes, true ) ) {
28792895
wp_send_json_error();
28802896
}
28812897
} else {

src/wp-admin/includes/class-wp-comments-list-table.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,19 @@ public function single_row( $a_comment ) {
445445

446446
$this->user_can = current_user_can( 'edit_comment', $comment->comment_ID );
447447

448+
$edit_post_cap = $post ? 'edit_post' : 'edit_posts';
449+
if (
450+
current_user_can( $edit_post_cap, $comment->comment_post_ID ) ||
451+
(
452+
empty( $post->post_password ) &&
453+
current_user_can( 'read_post', $comment->comment_post_ID )
454+
)
455+
) {
456+
// The user has access to the post
457+
} else {
458+
return false;
459+
}
460+
448461
echo "<tr id='comment-$comment->comment_ID' class='$the_comment_class'>";
449462
$this->single_row_columns( $comment );
450463
echo "</tr>\n";

src/wp-admin/includes/class-wp-list-table.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,20 @@ protected function comments_bubble( $post_id, $pending_comments ) {
623623
$approved_phrase = sprintf( _n( '%s approved comment', '%s approved comments', $approved_comments ), $approved_comments_number );
624624
$pending_phrase = sprintf( _n( '%s pending comment', '%s pending comments', $pending_comments ), $pending_comments_number );
625625

626-
// No comments at all.
626+
$post_object = get_post( $post_id );
627+
$edit_post_cap = $post_object ? 'edit_post' : 'edit_posts';
628+
if (
629+
current_user_can( $edit_post_cap, $post_id ) ||
630+
(
631+
empty( $post_object->post_password ) &&
632+
current_user_can( 'read_post', $post_id )
633+
)
634+
) {
635+
// The user has access to the post and thus can see comments
636+
} else {
637+
return false;
638+
}
639+
627640
if ( ! $approved_comments && ! $pending_comments ) {
628641
printf( '<span aria-hidden="true">—</span><span class="screen-reader-text">%s</span>',
629642
__( 'No comments' )

src/wp-admin/includes/dashboard.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -821,8 +821,18 @@ function wp_dashboard_recent_comments( $total_items = 5 ) {
821821
echo '<h4>' . __( 'Comments' ) . '</h4>';
822822

823823
echo '<div id="the-comment-list" data-wp-lists="list:comment">';
824-
foreach ( $comments as $comment )
825-
_wp_dashboard_recent_comments_row( $comment );
824+
foreach ( $comments as $comment ) {
825+
$comment_post = get_post( $comment->comment_post_ID );
826+
if (
827+
current_user_can( 'edit_post', $comment->comment_post_ID ) ||
828+
(
829+
empty( $comment_post->post_password ) &&
830+
current_user_can( 'read_post', $comment->comment_post_ID )
831+
)
832+
) {
833+
_wp_dashboard_recent_comments_row( $comment );
834+
}
835+
}
826836
echo '</div>';
827837

828838
if ( current_user_can('edit_posts') )

src/wp-includes/class-wp-theme.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,28 @@ public function parent() {
506506
return isset( $this->parent ) ? $this->parent : false;
507507
}
508508

509+
/**
510+
* Perform reinitialization tasks.
511+
*
512+
* Prevents a callback from being injected during unserialization of an object.
513+
*
514+
* @return void
515+
*/
516+
public function __wakeup() {
517+
if ( $this->parent && ! $this->parent instanceof self ) {
518+
throw new UnexpectedValueException();
519+
}
520+
if ( $this->headers && ! is_array( $this->headers ) ) {
521+
throw new UnexpectedValueException();
522+
}
523+
foreach ( $this->headers as $value ) {
524+
if ( ! is_string( $value ) ) {
525+
throw new UnexpectedValueException();
526+
}
527+
}
528+
$this->headers_sanitized = array();
529+
}
530+
509531
/**
510532
* Adds theme data to cache.
511533
*
@@ -1303,4 +1325,16 @@ private static function _name_sort_i18n( $a, $b ) {
13031325
// Don't mark up; Do translate.
13041326
return strnatcasecmp( $a->display( 'Name', false, true ), $b->display( 'Name', false, true ) );
13051327
}
1328+
1329+
private static function _check_headers_property_has_correct_type( $headers ) {
1330+
if ( ! is_array( $headers ) ) {
1331+
return false;
1332+
}
1333+
foreach ( $headers as $key => $value ) {
1334+
if ( ! is_string( $key ) || ! is_string( $value ) ) {
1335+
return false;
1336+
}
1337+
}
1338+
return true;
1339+
}
13061340
}

src/wp-includes/media.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,11 +1028,24 @@ function gallery_shortcode( $attr ) {
10281028
$attachments[$val->ID] = $_attachments[$key];
10291029
}
10301030
} elseif ( ! empty( $atts['exclude'] ) ) {
1031+
$post_parent_id = $id;
10311032
$attachments = get_children( array( 'post_parent' => $id, 'exclude' => $atts['exclude'], 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
10321033
} else {
1034+
$post_parent_id = $id;
10331035
$attachments = get_children( array( 'post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
10341036
}
10351037

1038+
if ( ! empty( $post_parent_id ) ) {
1039+
$post_parent = get_post( $post_parent_id );
1040+
1041+
// terminate the shortcode execution if user cannot read the post or password-protected
1042+
if (
1043+
( ! is_post_publicly_viewable( $post_parent->ID ) && ! current_user_can( 'read_post', $post_parent->ID ) )
1044+
|| post_password_required( $post_parent ) ) {
1045+
return '';
1046+
}
1047+
}
1048+
10361049
if ( empty( $attachments ) ) {
10371050
return '';
10381051
}
@@ -1326,6 +1339,15 @@ function wp_playlist_shortcode( $attr ) {
13261339
$attachments = get_children( $args );
13271340
}
13281341

1342+
if ( ! empty( $args['post_parent'] ) ) {
1343+
$post_parent = get_post( $id );
1344+
1345+
// terminate the shortcode execution if user cannot read the post or password-protected
1346+
if ( ! current_user_can( 'read_post', $post_parent->ID ) || post_password_required( $post_parent ) ) {
1347+
return '';
1348+
}
1349+
}
1350+
13291351
if ( empty( $attachments ) ) {
13301352
return '';
13311353
}

src/wp-includes/shortcodes.php

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,45 @@ function has_shortcode( $content, $tag ) {
171171
}
172172

173173
/**
174-
* Search content for shortcodes and filter shortcodes through their hooks.
174+
* Returns a list of registered shortcode names found in the given content.
175+
*
176+
* Example usage:
177+
*
178+
* get_shortcode_tags_in_content( '[audio src="file.mp3"][/audio] [foo] [gallery ids="1,2,3"]' );
179+
* // array( 'audio', 'gallery' )
180+
*
181+
* @since 6.3.2
182+
*
183+
* @param string $content The content to check.
184+
* @return string[] An array of registered shortcode names found in the content.
185+
*/
186+
function get_shortcode_tags_in_content( $content ) {
187+
if ( false === strpos( $content, '[' ) ) {
188+
return array();
189+
}
190+
191+
preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER );
192+
if ( empty( $matches ) ) {
193+
return array();
194+
}
195+
196+
$tags = array();
197+
foreach ( $matches as $shortcode ) {
198+
$tags[] = $shortcode[2];
199+
200+
if ( ! empty( $shortcode[5] ) ) {
201+
$deep_tags = get_shortcode_tags_in_content( $shortcode[5] );
202+
if ( ! empty( $deep_tags ) ) {
203+
$tags = array_merge( $tags, $deep_tags );
204+
}
205+
}
206+
}
207+
208+
return $tags;
209+
}
210+
211+
/**
212+
* Searches content for shortcodes and filter shortcodes through their hooks.
175213
*
176214
* If there are no shortcode tags defined, then the content will be returned
177215
* without any filtering. This might cause issues when plugins are disabled but

0 commit comments

Comments
 (0)