PluginProbe
bbPress / 2.6.19
bbPress v2.6.19
2.6.19 2.6.18 2.6.17 trunk 2.0 2.0-beta-1 2.0-beta-2b 2.0-beta-3 2.0-beta-3b 2.0-rc-2 2.0-rc-3 2.0-rc-4 2.0-rc-5 2.0.1 2.0.2 2.0.3 2.1 2.1-beta-1 2.1-rc1 2.1-rc2 2.1-rc3 2.1-rc4 2.1.1 2.1.2 2.1.3 All 74 releases
← All changes | includes/common/rest.php +280 -13 2.6.18 → 2.6.19 View file →
@@ -10,18 +10,88 @@
10 10 // Exit if accessed directly
11 11 defined( 'ABSPATH' ) || exit;
12 12
13 13 /**
14 + * Check single-user REST reads against non-forum published posts.
15 + *
16 + * WordPress counts all published REST post types without checking whether
17 + * bbPress topics and replies belong to restricted forums.
18 + *
19 + * @since 2.6.19 bbPress (r7710)
20 + *
21 + * @param mixed $response Current REST response.
22 + * @param array $handler Matched route handler.
23 + * @param WP_REST_Request $request REST request.
24 + * @return mixed REST response or error.
25 + */
26 +function bbp_filter_rest_user_discovery( $response, $handler, $request ) {
27 + $callback = isset( $handler['callback'] ) ? $handler['callback'] : null;
28 +
29 + if ( null !== $response || ! is_array( $callback ) || ! isset( $callback[0], $callback[1] ) ) {
30 + return $response;
31 + }
32 +
33 + if ( ! $callback[0] instanceof WP_REST_Users_Controller || 'get_item' !== $callback[1] || ! in_array( $request->get_method(), array( 'GET', 'HEAD' ), true ) ) {
34 + return $response;
35 + }
36 +
37 + $user_id = (int) $request->get_param( 'id' );
38 +
39 + if ( $user_id <= 0 || get_current_user_id() === $user_id || current_user_can( 'list_users' ) || current_user_can( 'edit_user', $user_id ) ) {
40 + return $response;
41 + }
42 +
43 + $post_types = array_values( array_diff( get_post_types( array( 'show_in_rest' => true ), 'names' ), bbp_get_post_types() ) );
44 +
45 + if ( ! empty( $post_types ) && count_user_posts( $user_id, $post_types ) ) {
46 + return $response;
47 + }
48 +
49 + return new WP_Error(
50 + 'rest_user_cannot_view',
51 + esc_html__( 'Sorry, you are not allowed to list users.', 'bbpress' ),
52 + array( 'status' => rest_authorization_required_code() )
53 + );
54 +}
55 +
56 +/**
14 57 * REST API controller for bbPress post types.
15 58 *
16 - * @since 2.6.17
59 + * @since 2.6.17 bbPress (r7482)
17 60 */
18 61 class BBP_REST_Posts_Controller extends WP_REST_Posts_Controller {
19 62
20 63 /**
64 + * Apply bbPress's strict block list before creating a topic or reply.
65 + *
66 + * @since 2.6.19 bbPress (r7624)
67 + *
68 + * @param WP_REST_Request $request Full details about the request.
69 + * @return true|WP_Error True if the request has access, WP_Error otherwise.
70 + */
71 + public function create_item_permissions_check( $request ) {
72 + $retval = parent::create_item_permissions_check( $request );
73 +
74 + if ( is_wp_error( $retval ) || ! $retval || ! in_array( $this->post_type, array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ), true ) ) {
75 + return $retval;
76 + }
77 +
78 + if ( ! bbp_check_for_moderation( array(), bbp_get_current_user_id(), $this->get_moderation_title( $request, null ), $this->get_moderation_content( $request, null ), true ) ) {
79 + return new WP_Error(
80 + 'bbp_rest_disallowed_content',
81 + esc_html__( 'This forum content cannot be created at this time.', 'bbpress' ),
82 + array( 'status' => 400 )
83 + );
84 + }
85 +
86 + return $retval;
87 + }
88 +
89 + /**
21 90 * Checks if a post can be updated.
22 91 *
23 - * @since 2.6.17
92 + * @since 2.6.17 bbPress (r7490)
93 + * @since 2.6.19 bbPress (r7684) Check the topic forum on edits.
24 94 *
25 95 * @param WP_REST_Request $request Full details about the request.
26 96 * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise.
27 97 */
@@ -40,8 +110,67 @@
40 110 array( 'status' => rest_authorization_required_code() )
41 111 );
42 112 }
43 113
114 + // Match the front-end topic edit checks for category and closed forums.
115 + if ( ! empty( $post ) && ( bbp_get_topic_post_type() === $post->post_type ) ) {
116 + $topic_forum_id = bbp_get_topic_forum_id( $post->ID );
117 +
118 + if ( bbp_is_forum_category( $topic_forum_id ) || ( bbp_is_forum_closed( $topic_forum_id ) && ! current_user_can( 'edit_forum', $topic_forum_id ) ) ) {
119 + return new WP_Error(
120 + 'bbp_rest_cannot_edit_topic_forum',
121 + esc_html__( 'You are not allowed to edit this topic in its forum.', 'bbpress' ),
122 + array( 'status' => rest_authorization_required_code() )
123 + );
124 + }
125 + }
126 +
127 + // REST requests do not use the front-end edit query flags that enforce
128 + // bbPress's edit lock in the topic and reply capability mappings.
129 + if ( ! empty( $post ) && $this->is_forum_content( $post ) ) {
130 + $can_moderate = current_user_can( 'moderate', $post->ID );
131 +
132 + if ( ! $can_moderate ) {
133 + // Only moderators may change status or move the edit window.
134 + if ( $request->has_param( 'status' ) && ( $request['status'] !== $post->post_status ) ) {
135 + return new WP_Error(
136 + 'bbp_rest_cannot_change_status',
137 + esc_html__( 'You are not allowed to change this forum content status.', 'bbpress' ),
138 + array( 'status' => rest_authorization_required_code() )
139 + );
140 + }
141 +
142 + if ( $this->is_post_date_changed( $request, $post ) ) {
143 + return new WP_Error(
144 + 'bbp_rest_cannot_change_date',
145 + esc_html__( 'You are not allowed to change this forum content date.', 'bbpress' ),
146 + array( 'status' => rest_authorization_required_code() )
147 + );
148 + }
149 +
150 + // Pending posts may have a zero GMT date even when they are recent.
151 + $post_date_gmt = ( '0000-00-00 00:00:00' === $post->post_date_gmt )
152 + ? get_gmt_from_date( $post->post_date )
153 + : $post->post_date_gmt;
154 +
155 + if ( ( bbp_get_current_user_id() === (int) $post->post_author ) && bbp_past_edit_lock( $post_date_gmt ) ) {
156 + return new WP_Error(
157 + 'bbp_rest_edit_lock',
158 + esc_html__( 'You can no longer edit this forum content.', 'bbpress' ),
159 + array( 'status' => rest_authorization_required_code() )
160 + );
161 + }
162 + }
163 +
164 + if ( ! bbp_check_for_moderation( array(), (int) $post->post_author, $this->get_moderation_title( $request, $post ), $this->get_moderation_content( $request, $post ), true ) ) {
165 + return new WP_Error(
166 + 'bbp_rest_disallowed_content',
167 + esc_html__( 'This forum content cannot be edited at this time.', 'bbpress' ),
168 + array( 'status' => 400 )
169 + );
170 + }
171 + }
172 +
44 173 $forum_id = ! empty( $post ) ? bbp_get_forum_id( $post->ID ) : 0;
45 174 $forum = bbp_get_forum( $forum_id );
46 175
47 176 if ( empty( $forum ) ) {
@@ -71,14 +200,123 @@
71 200 return $retval;
72 201 }
73 202
74 203 /**
204 + * Apply bbPress moderation to REST edits before WordPress saves the post.
205 + *
206 + * @since 2.6.19 bbPress (r7614)
207 + *
208 + * @param WP_REST_Request $request Full details about the request.
209 + * @return WP_REST_Response|WP_Error Response or error from WordPress.
210 + */
211 + public function update_item( $request ) {
212 + $post = isset( $request['id'] ) ? get_post( $request['id'] ) : null;
213 +
214 + if ( ! empty( $post ) && $this->is_forum_content( $post ) && in_array( $post->post_status, bbp_get_public_topic_statuses(), true ) ) {
215 + $title = $this->get_moderation_title( $request, $post );
216 + $content = $this->get_moderation_content( $request, $post );
217 +
218 + if ( ! bbp_check_for_moderation( array(), (int) $post->post_author, $title, $content ) ) {
219 + $request->set_param( 'status', bbp_get_pending_status_id() );
220 + }
221 + }
222 +
223 + return parent::update_item( $request );
224 + }
225 +
226 + /**
227 + * Whether a post is a topic or reply.
228 + *
229 + * @since 2.6.19 bbPress (r7614)
230 + *
231 + * @param WP_Post $post Post to check.
232 + * @return bool Whether this is forum content.
233 + */
234 + private function is_forum_content( $post ) {
235 + return in_array( $post->post_type, array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ), true );
236 + }
237 +
238 + /**
239 + * Whether a REST request changes a topic or reply publication date.
240 + *
241 + * @since 2.6.19 bbPress (r7614)
242 + *
243 + * @param WP_REST_Request $request Full details about the request.
244 + * @param WP_Post $post Existing post.
245 + * @return bool Whether the date would change.
246 + */
247 + private function is_post_date_changed( $request, $post ) {
248 + $post_date_gmt = ( '0000-00-00 00:00:00' === $post->post_date_gmt )
249 + ? get_gmt_from_date( $post->post_date )
250 + : $post->post_date_gmt;
251 +
252 + foreach ( array(
253 + 'date' => false,
254 + 'date_gmt' => true,
255 + ) as $field => $is_gmt ) {
256 + if ( ! $request->has_param( $field ) ) {
257 + continue;
258 + }
259 +
260 + $dates = is_string( $request[ $field ] ) ? rest_get_date_with_gmt( $request[ $field ], $is_gmt ) : false;
261 +
262 + if ( empty( $dates ) || ( $post->post_date !== $dates[0] ) || ( $post_date_gmt !== $dates[1] ) ) {
263 + return true;
264 + }
265 + }
266 +
267 + return false;
268 + }
269 +
270 + /**
271 + * Get the title that bbPress moderation should check.
272 + *
273 + * @since 2.6.19 bbPress (r7614)
274 + *
275 + * @param WP_REST_Request $request Full details about the request.
276 + * @param WP_Post|null $post Existing post, or null when creating.
277 + * @return string Title to check.
278 + */
279 + private function get_moderation_title( $request, $post ) {
280 + if ( ! $request->has_param( 'title' ) ) {
281 + return empty( $post ) ? '' : $post->post_title;
282 + }
283 +
284 + $title = $request['title'];
285 +
286 + return is_string( $title )
287 + ? $title
288 + : ( ! empty( $title['raw'] ) ? $title['raw'] : ( empty( $post ) ? '' : $post->post_title ) );
289 + }
290 +
291 + /**
292 + * Get the content that bbPress moderation should check.
293 + *
294 + * @since 2.6.19 bbPress (r7614)
295 + *
296 + * @param WP_REST_Request $request Full details about the request.
297 + * @param WP_Post|null $post Existing post, or null when creating.
298 + * @return string Content to check.
299 + */
300 + private function get_moderation_content( $request, $post ) {
301 + if ( ! $request->has_param( 'content' ) ) {
302 + return empty( $post ) ? '' : $post->post_content;
303 + }
304 +
305 + $content = $request['content'];
306 +
307 + return is_string( $content )
308 + ? $content
309 + : ( isset( $content['raw'] ) ? $content['raw'] : ( empty( $post ) ? '' : $post->post_content ) );
310 + }
311 +
312 + /**
75 313 * Checks if a post type is allowed for permission checks.
76 314 *
77 315 * bbPress posts may be attachment parents even when their own REST routes
78 316 * are disabled.
79 317 *
80 - * @since 2.6.17
318 + * @since 2.6.17 bbPress (r7482)
81 319 *
82 320 * @param WP_Post_Type|string $post_type Post type object or name.
83 321 * @return bool Whether the post type is allowed.
84 322 */
@@ -98,9 +336,10 @@
98 336
99 337 /**
100 338 * Checks if a post can be read.
101 339 *
102 - * @since 2.6.17
340 + * @since 2.6.17 bbPress (r7482)
341 + * @since 2.6.19 bbPress (r7682) Check the parent topic for replies.
103 342 *
104 343 * @param WP_Post $post Post object.
105 344 * @return bool Whether the post can be read.
106 345 */
@@ -109,23 +348,27 @@
109 348 if ( ! $this->check_is_post_type_allowed( $post_type ) ) {
110 349 return false;
111 350 }
112 351
113 - $can_read = parent::check_read_permission( $post );
114 - $user_id = bbp_get_current_user_id();
352 + $can_read = parent::check_read_permission( $post );
353 + $user_id = bbp_get_current_user_id();
354 + $password_parent_id = 0;
115 355
116 356 // Get the forum ID for this post
117 357 switch ( $post->post_type ) {
118 358 case bbp_get_forum_post_type() :
119 - $forum_id = $post->ID;
359 + $forum_id = $post->ID;
360 + $password_parent_id = bbp_get_forum_parent_id( $post->ID );
120 361 break;
121 362
122 363 case bbp_get_topic_post_type() :
123 - $forum_id = bbp_get_topic_forum_id( $post->ID );
364 + $forum_id = bbp_get_topic_forum_id( $post->ID );
365 + $password_parent_id = $forum_id;
124 366 break;
125 367
126 368 case bbp_get_reply_post_type() :
127 - $forum_id = bbp_get_reply_forum_id( $post->ID );
369 + $forum_id = bbp_get_reply_forum_id( $post->ID );
370 + $password_parent_id = bbp_get_reply_topic_id( $post->ID );
128 371 break;
129 372
130 373 default :
131 374 $forum_id = 0;
@@ -144,9 +387,29 @@
144 387 if ( ! $can_read && ! $moderator_can_read ) {
145 388 return false;
146 389 }
147 390
148 - return ! bbp_is_forum_restricted_for_user( $forum_id, $user_id );
391 + if ( bbp_is_forum_restricted_for_user( $forum_id, $user_id ) ) {
392 + return false;
393 + }
394 +
395 + // WordPress checks only the requested object's password. bbPress forum
396 + // content also inherits password requirements from its parents.
397 + if ( ! empty( $password_parent_id ) && bbp_get_password_required_id( $password_parent_id ) ) {
398 + return false;
399 + }
400 +
401 + // A public reply cannot expose an unreadable topic
402 + if ( bbp_get_reply_post_type() === $post->post_type ) {
403 + $topic_id = bbp_get_reply_topic_id( $post->ID );
404 + $topic = ! empty( $topic_id ) ? bbp_get_topic( $topic_id ) : null;
405 +
406 + if ( empty( $topic ) || ! $this->check_read_permission( $topic ) ) {
407 + return false;
408 + }
409 + }
410 +
411 + return true;
149 412 }
150 413 }
151 414
152 415 /**
@@ -151,9 +414,9 @@
151 414
152 415 /**
153 416 * REST API controller for attachments to bbPress post types.
154 417 *
155 - * @since 2.6.17
418 + * @since 2.6.17 bbPress (r7482)
156 419 */
157 420 class BBP_REST_Attachments_Controller extends WP_REST_Attachments_Controller {
158 421
159 422 /**
@@ -158,9 +421,9 @@
158 421
159 422 /**
160 423 * Checks if an attachment can be read.
161 424 *
162 - * @since 2.6.17
425 + * @since 2.6.17 bbPress (r7482)
163 426 *
164 427 * @param WP_Post $post Attachment post object.
165 428 * @return bool Whether the attachment can be read.
166 429 */
@@ -175,8 +438,12 @@
175 438 $parent = get_post( $post->post_parent );
176 439 $types = array( bbp_get_forum_post_type(), bbp_get_topic_post_type(), bbp_get_reply_post_type() );
177 440
178 441 if ( ! empty( $parent ) && in_array( $parent->post_type, $types, true ) ) {
442 + if ( bbp_get_password_required_id( $parent->ID ) ) {
443 + return false;
444 + }
445 +
179 446 $controller = new BBP_REST_Posts_Controller( $parent->post_type );
180 447
181 448 return $controller->check_read_permission( $parent );
182 449 }
@@ -188,9 +455,9 @@
188 455
189 456 /**
190 457 * Use the bbPress controller for attachments when Core's is unchanged.
191 458 *
192 - * @since 2.6.17
459 + * @since 2.6.17 bbPress (r7482)
193 460 */
194 461 function bbp_register_rest_attachment_controller() {
195 462 $post_type = get_post_type_object( 'attachment' );
196 463