Make WordPress Core


Ignore:
Timestamp:
12/07/2021 08:56:18 PM (5 years ago)
Author:
spacedmonkey
Message:

REST API: Improve permission handling in global style endpoint.

The new wp_global_styles post type is registered to use edit_theme_options in the capability settings. The WP_REST_Global_Styles_Controller class's permission checks methods use the capability in a hard coded form rather than looking up the capability via the post type object. Changing the permission callbacks to lookup capabilities via the post type object, allows theme and plugin developers to modify the capability used for editing global styles via a filter and these values to be respected via the Global Styles REST API.

Props Spacedmonkey, peterwilsoncc, hellofromTonya , antonvlasenko, TimothyBlynJacobs, costdev, zieladam.
Fixes #54516.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php

    r52332 r52342  
    1212 */
    1313class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
     14
     15        /**
     16         * Post type.
     17         *
     18         * @since 5.9.0
     19         * @var string
     20         */
     21        protected $post_type;
     22
    1423        /**
    1524         * Constructor.
     
    1928                $this->namespace = 'wp/v2';
    2029                $this->rest_base = 'global-styles';
     30                $this->post_type = 'wp_global_styles';
    2131        }
    2232
     
    7686
    7787        /**
    78          * Checks if the user has permissions to make the request.
    79          *
    80          * @since 5.9.0
    81          *
     88         * Checks if a given request has access to read a single global style.
     89         *
     90         * @since 5.9.0
     91         *
     92         * @param WP_REST_Request $request Full details about the request.
    8293         * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
    8394         */
    84         protected function permissions_check() {
    85                 // Verify if the current user has edit_theme_options capability.
    86                 // This capability is required to edit/view/delete templates.
    87                 if ( ! current_user_can( 'edit_theme_options' ) ) {
     95        public function get_item_permissions_check( $request ) {
     96                $post = $this->get_post( $request['id'] );
     97                if ( is_wp_error( $post ) ) {
     98                        return $post;
     99                }
     100
     101                if ( 'edit' === $request['context'] && $post && ! $this->check_update_permission( $post ) ) {
    88102                        return new WP_Error(
    89                                 'rest_cannot_manage_global_styles',
    90                                 __( 'Sorry, you are not allowed to access the global styles on this site.' ),
    91                                 array(
    92                                         'status' => rest_authorization_required_code(),
    93                                 )
     103                                'rest_forbidden_context',
     104                                __( 'Sorry, you are not allowed to edit this global style.' ),
     105                                array( 'status' => rest_authorization_required_code() )
    94106                        );
    95107                }
    96108
     109                if ( ! $this->check_read_permission( $post ) ) {
     110                        return new WP_Error(
     111                                'rest_cannot_view',
     112                                __( 'Sorry, you are not allowed to view this global style.' ),
     113                                array( 'status' => rest_authorization_required_code() )
     114                        );
     115                }
     116
    97117                return true;
    98118        }
    99119
    100120        /**
    101          * Checks if a given request has access to read a single global styles config.
    102          *
    103          * @param WP_REST_Request $request Full details about the request.
    104          * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
    105          */
    106         public function get_item_permissions_check( $request ) {
    107                 return $this->permissions_check( $request );
     121         * Checks if a global style can be read.
     122         *
     123         * @since 5.9.0
     124         *
     125         * @param WP_Post $post Post object.
     126         * @return bool Whether the post can be read.
     127         */
     128        protected function check_read_permission( $post ) {
     129                return current_user_can( 'read_post', $post->ID );
    108130        }
    109131
     
    118140         */
    119141        public function get_item( $request ) {
    120                 $post = get_post( $request['id'] );
    121                 if ( ! $post || 'wp_global_styles' !== $post->post_type ) {
    122                         return new WP_Error( 'rest_global_styles_not_found', __( 'No global styles config exist with that id.' ), array( 'status' => 404 ) );
     142                $post = $this->get_post( $request['id'] );
     143                if ( is_wp_error( $post ) ) {
     144                        return $post;
    123145                }
    124146
     
    135157         */
    136158        public function update_item_permissions_check( $request ) {
    137                 return $this->permissions_check( $request );
     159                $post = $this->get_post( $request['id'] );
     160                if ( is_wp_error( $post ) ) {
     161                        return $post;
     162                }
     163
     164                if ( $post && ! $this->check_update_permission( $post ) ) {
     165                        return new WP_Error(
     166                                'rest_cannot_edit',
     167                                __( 'Sorry, you are not allowed to edit this global style.' ),
     168                                array( 'status' => rest_authorization_required_code() )
     169                        );
     170                }
     171
     172                return true;
     173        }
     174
     175        /**
     176         * Checks if a global style can be edited.
     177         *
     178         * @since 5.9.0
     179         *
     180         * @param WP_Post $post Post object.
     181         * @return bool Whether the post can be edited.
     182         */
     183        protected function check_update_permission( $post ) {
     184                return current_user_can( 'edit_post', $post->ID );
    138185        }
    139186
     
    147194         */
    148195        public function update_item( $request ) {
    149                 $post_before = get_post( $request['id'] );
    150                 if ( ! $post_before || 'wp_global_styles' !== $post_before->post_type ) {
    151                         return new WP_Error( 'rest_global_styles_not_found', __( 'No global styles config exist with that id.' ), array( 'status' => 404 ) );
     196                $post_before = $this->get_post( $request['id'] );
     197                if ( is_wp_error( $post_before ) ) {
     198                        return $post_before;
    152199                }
    153200
     
    290337        }
    291338
     339        /**
     340         * Get the post, if the ID is valid.
     341         *
     342         * @since 5.9.0
     343         *
     344         * @param int $id Supplied ID.
     345         * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
     346         */
     347        protected function get_post( $id ) {
     348                $error = new WP_Error(
     349                        'rest_global_styles_not_found',
     350                        __( 'No global styles config exist with that id.' ),
     351                        array( 'status' => 404 )
     352                );
     353
     354                $id = (int) $id;
     355                if ( $id <= 0 ) {
     356                        return $error;
     357                }
     358
     359                $post = get_post( $id );
     360                if ( empty( $post ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
     361                        return $error;
     362                }
     363
     364                return $post;
     365        }
     366
    292367
    293368        /**
     
    324399                $rels = array();
    325400
    326                 $post_type = get_post_type_object( 'wp_global_styles' );
     401                $post_type = get_post_type_object( $this->post_type );
    327402                if ( current_user_can( $post_type->cap->publish_posts ) ) {
    328403                        $rels[] = 'https://api.w.org/action-publish';
     
    372447                $schema = array(
    373448                        '$schema'    => 'http://json-schema.org/draft-04/schema#',
    374                         'title'      => 'wp_global_styles',
     449                        'title'      => $this->post_type,
    375450                        'type'       => 'object',
    376451                        'properties' => array(
     
    427502         */
    428503        public function get_theme_item_permissions_check( $request ) {
    429                 return $this->permissions_check( $request );
     504                // Verify if the current user has edit_theme_options capability.
     505                // This capability is required to edit/view/delete templates.
     506                if ( ! current_user_can( 'edit_theme_options' ) ) {
     507                        return new WP_Error(
     508                                'rest_cannot_manage_global_styles',
     509                                __( 'Sorry, you are not allowed to access the global styles on this site.' ),
     510                                array(
     511                                        'status' => rest_authorization_required_code(),
     512                                )
     513                        );
     514                }
     515
     516                return true;
    430517        }
    431518
Note: See TracChangeset for help on using the changeset viewer.