Skip to:
Content

bbPress.org

Changeset 7060


Ignore:
Timestamp:
01/28/2020 10:12:13 PM (4 years ago)
Author:
johnjamesjacoby
Message:

BuddyPress: explicitly validate IDs when editing Group forum topics & replies.

This commit adds methods to validate that the forum IDs and reply-to IDs for topics & replies are within the accepted ranges for the specific Group Forum they are being edited inside of.

In addition, the moderate_forum mapped meta capability is removed, and the broader moderate capability will continue to cover its use case. This capability was not intended to be used directly, and doing so incorrectly would trigger unintended and infinite recursion.

For 2.7, trunk

Location:
trunk/src/includes
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/includes/extend/buddypress/groups.php

    r7057 r7060  
    8686        // Remove group forum cap map when view is done
    8787        add_action( 'bbp_after_group_forum_display',  array( $this, 'remove_group_forum_meta_cap_map' ) );
     88
     89        // Validate group forum IDs when editing topics & replies
     90        add_action( 'bbp_edit_topic_pre_extras',      array( $this, 'validate_topic_forum_id' ) );
     91        add_action( 'bbp_edit_reply_pre_extras',      array( $this, 'validate_reply_to_id'    ) );
    8892
    8993        // Check if group-forum status should be changed
     
    279283
    280284            // If user is a group mod ar admin, map to participate cap.
    281             case 'moderate'     :
    282             case 'edit_topic'   :
    283             case 'edit_reply'   :
    284             case 'view_trash'   :
     285            case 'moderate'            :
     286            case 'edit_topic'          :
     287            case 'edit_reply'          :
     288            case 'view_trash'          :
    285289            case 'edit_others_replies' :
    286290            case 'edit_others_topics'  :
     
    310314    public function remove_group_forum_meta_cap_map() {
    311315        remove_filter( 'bbp_map_meta_caps', array( $this, 'map_group_forum_meta_caps' ), 99, 4 );
     316    }
     317
     318    /**
     319     * Validate the forum ID for a topic in a group forum.
     320     *
     321     * This method ensures that when a topic is saved, it is only allowed to be
     322     * saved to a forum that is either:
     323     *
     324     * - A forum in the current group
     325     * - A forum the current user can moderate outside of this group
     326     *
     327     * If all checks fail, an error gets added to prevent the topic from saving.
     328     *
     329     * @since 2.6.14
     330     *
     331     * @param int $topic_id
     332     */
     333    public function validate_topic_forum_id( $topic_id = 0 ) {
     334
     335        // Bail if no topic
     336        if ( empty( $topic_id ) ) {
     337            return;
     338        }
     339
     340        // Get current forum ID
     341        $forum_id = bbp_get_topic_forum_id( $topic_id );
     342
     343        // Bail if not a group forum
     344        if ( ! bbp_is_forum_group_forum( $forum_id ) ) {
     345            return;
     346        }
     347
     348        // Get current group ID
     349        $group_id = bp_get_current_group_id();
     350
     351        // Bail if unknown group ID
     352        if ( empty( $group_id ) ) {
     353            return;
     354        }
     355
     356        // Get group forum IDs
     357        $forum_ids = bbp_get_group_forum_ids( $group_id );
     358
     359        // Get posted forum ID
     360        $new_forum_id = ! empty( $_POST['bbp_forum_id'] )
     361            ? absint( $_POST['bbp_forum_id'] )
     362            : 0;
     363
     364        // Bail if new forum ID is a forum in this group
     365        if ( in_array( $new_forum_id, $forum_ids, true ) ) {
     366            return;
     367        }
     368
     369        // Get the current user ID
     370        $user_id = bbp_get_current_user_id();
     371
     372        // Bail if current user can moderate the new forum ID
     373        if ( bbp_is_user_forum_moderator( $user_id, $new_forum_id ) ) {
     374            return;
     375        }
     376
     377        // If everything else has failed, then something is wrong and we need
     378        // to add an error to prevent this topic from saving.
     379        bbp_add_error( 'bbp_topic_forum_id', __( '<strong>ERROR</strong>: Forum ID is invalid.', 'bbpress' ) );
     380    }
     381
     382    /**
     383     * Validate the reply to for a reply in a group forum.
     384     *
     385     * This method ensures that when a reply to is saved, it is only allowed to
     386     * be saved to the current topic.
     387     *
     388     * If all checks fail, an error gets added to prevent the reply from saving.
     389     *
     390     * @since 2.6.14
     391     *
     392     * @param int $reply_id
     393     */
     394    public function validate_reply_to_id( $reply_id = 0 ) {
     395
     396        // Bail if no reply
     397        if ( empty( $reply_id ) ) {
     398            return;
     399        }
     400
     401        // Get posted reply to
     402        $new_reply_to = ! empty( $_POST['bbp_reply_to'] )
     403            ? absint( $_POST['bbp_reply_to'] )
     404            : 0;
     405
     406        // Bail if no reply to (assumes topic ID)
     407        if ( empty( $new_reply_to ) ) {
     408            return;
     409        }
     410
     411        // Get current forum ID
     412        $forum_id = bbp_get_reply_forum_id( $reply_id );
     413
     414        // Bail if not a group forum
     415        if ( ! bbp_is_forum_group_forum( $forum_id ) ) {
     416            return;
     417        }
     418
     419        // Get current group ID
     420        $group_id = bp_get_current_group_id();
     421
     422        // Bail if unknown group ID
     423        if ( empty( $group_id ) ) {
     424            return;
     425        }
     426
     427        // Get current topic ID
     428        $topic_id = bbp_get_reply_topic_id( $reply_id );
     429
     430        // Get topic reply IDs
     431        $reply_ids = bbp_get_public_child_ids( $topic_id, bbp_get_reply_post_type() );
     432
     433        // Avoid recursion
     434        unset( $reply_ids[ $reply_id ] );
     435
     436        // Bail if new reply parent ID is in this topic
     437        if ( in_array( $new_reply_to, $reply_ids, true ) ) {
     438            return;
     439        }
     440
     441        // Add an error to prevent this reply from saving.
     442        bbp_add_error( 'bbp_reply_to_id', __( '<strong>ERROR</strong>: Reply To is invalid.', 'bbpress' ) );
    312443    }
    313444
  • trunk/src/includes/forums/capabilities.php

    r6975 r7060  
    109109            break;
    110110
    111         /** Moderating ********************************************************/
    112 
    113         case 'moderate_forum' :
     111        /** Publishing ********************************************************/
     112
     113        case 'publish_forums'  :
     114
     115            // Moderators can always edit
     116            if ( user_can( $user_id, 'moderate' ) ) {
     117                $caps = array( 'moderate' );
     118            }
     119
     120            break;
     121
     122        /** Editing ***********************************************************/
     123
     124        // Used primarily in wp-admin
     125        case 'edit_forums'         :
     126        case 'edit_others_forums'  :
     127
     128            // Moderators can always edit
     129            if ( bbp_is_user_keymaster( $user_id ) ) {
     130                $caps = array( 'spectate' );
     131
     132            // Otherwise, block
     133            } else {
     134                $caps = array( 'do_not_allow' );
     135            }
     136
     137            break;
     138
     139        // Used everywhere
     140        case 'edit_forum' :
    114141
    115142            // Bail if no post ID
     
    120147            // Get the post.
    121148            $_post = get_post( $args[0] );
    122             if ( ! empty( $_post ) && bbp_allow_forum_mods() ) {
    123 
    124                 // Make sure feature is enabled & user is mod on this forum
    125                 if ( bbp_is_object_of_user( $_post->ID, $user_id, '_bbp_moderator_id' ) ) {
     149            if ( ! empty( $_post ) ) {
     150
     151                // Get caps for post type object
     152                $post_type = get_post_type_object( $_post->post_type );
     153
     154                // Add 'do_not_allow' cap if user is spam or deleted
     155                if ( bbp_is_user_inactive( $user_id ) ) {
     156                    $caps = array( 'do_not_allow' );
     157
     158                // Moderators can always read forum content
     159                } elseif ( user_can( $user_id, 'moderate', $_post->ID ) ) {
    126160                    $caps = array( 'spectate' );
    127                 }
    128             }
    129 
    130             break;
    131 
    132         /** Publishing ********************************************************/
    133 
    134         case 'publish_forums'  :
    135 
    136             // Moderators can always edit
    137             if ( user_can( $user_id, 'moderate' ) ) {
    138                 $caps = array( 'moderate' );
    139             }
    140 
    141             break;
    142 
    143         /** Editing ***********************************************************/
    144 
    145         // Used primarily in wp-admin
    146         case 'edit_forums'         :
    147         case 'edit_others_forums'  :
    148 
    149             // Moderators can always edit
    150             if ( bbp_is_user_keymaster( $user_id ) ) {
    151                 $caps = array( 'spectate' );
    152 
    153             // Otherwise, block
    154             } else {
    155                 $caps = array( 'do_not_allow' );
    156             }
    157 
    158             break;
    159 
    160         // Used everywhere
    161         case 'edit_forum' :
     161
     162                // User is author so allow edit if not in admin
     163                } elseif ( ! is_admin() && ( (int) $user_id === (int) $_post->post_author ) ) {
     164                    $caps = array( $post_type->cap->edit_posts );
     165
     166                // Unknown, so map to edit_others_posts
     167                } else {
     168                    $caps = array( $post_type->cap->edit_others_posts );
     169                }
     170            }
     171
     172            break;
     173
     174        /** Deleting **********************************************************/
     175
     176        // Allow forum authors to delete forums (for BuddyPress groups, etc)
     177        case 'delete_forum' :
    162178
    163179            // Bail if no post ID
     
    177193                    $caps = array( 'do_not_allow' );
    178194
    179                 // Moderators can always read forum content
    180                 } elseif ( user_can( $user_id, 'moderate', $_post->ID ) ) {
    181                     $caps = array( 'spectate' );
    182 
    183                 // User is author so allow edit if not in admin
    184                 } elseif ( ! is_admin() && ( (int) $user_id === (int) $_post->post_author ) ) {
    185                     $caps = array( $post_type->cap->edit_posts );
    186 
    187                 // Unknown, so map to edit_others_posts
    188                 } else {
    189                     $caps = array( $post_type->cap->edit_others_posts );
    190                 }
    191             }
    192 
    193             break;
    194 
    195         /** Deleting **********************************************************/
    196 
    197         // Allow forum authors to delete forums (for BuddyPress groups, etc)
    198         case 'delete_forum' :
    199 
    200             // Bail if no post ID
    201             if ( empty( $args[0] ) ) {
    202                 break;
    203             }
    204 
    205             // Get the post.
    206             $_post = get_post( $args[0] );
    207             if ( ! empty( $_post ) ) {
    208 
    209                 // Get caps for post type object
    210                 $post_type = get_post_type_object( $_post->post_type );
    211 
    212                 // Add 'do_not_allow' cap if user is spam or deleted
    213                 if ( bbp_is_user_inactive( $user_id ) ) {
    214                     $caps = array( 'do_not_allow' );
    215 
    216195                // User is author so allow to delete
    217196                } elseif ( (int) $user_id === (int) $_post->post_author ) {
     
    251230    $user_id  = bbp_get_user_id( $user_id, false, empty( $user_id ) );
    252231    $forum_id = bbp_get_forum_id( $forum_id );
    253     $retval   = user_can( $user_id, 'moderate_forum', $forum_id );
     232    $retval   = user_can( $user_id, 'moderate', $forum_id );
    254233
    255234    // Filter & return
  • trunk/src/includes/users/capabilities.php

    r7056 r7060  
    5656                $caps = array( 'do_not_allow' );
    5757
    58             // Keymasters can always moderate
     58            // Keymasters can always moderate.
    5959            } elseif ( bbp_is_user_keymaster( $user_id ) ) {
    6060                $caps = array( 'spectate' );
    6161
    62             // Default to the current cap.
    63             } else {
     62            // Check if user can moderate forum.
     63            } elseif ( bbp_allow_forum_mods() ) {
    6464                $caps = array( $cap );
    6565
     
    104104                }
    105105
    106                 // If user is a per-forum moderator, make sure they can spectate.
    107                 if ( bbp_is_user_forum_moderator( $user_id, $forum_id ) ) {
     106                // User is mod of this forum
     107                if ( bbp_is_object_of_user( $forum_id, $user_id, '_bbp_moderator_id' ) ) {
    108108                    $caps = array( 'spectate' );
    109109                }
Note: See TracChangeset for help on using the changeset viewer.