From 7866eb465d7443cc294786ce3ae0ce6d9a4df61c Mon Sep 17 00:00:00 2001 From: Alex Kirk Date: Fri, 6 Dec 2024 19:08:38 +0100 Subject: [PATCH] Move permissions checks into a dedicated permission_callback (#408) --- includes/class-messages.php | 33 +++++++++- includes/class-rest.php | 119 +++++++++++++++++++++++++++++++----- 2 files changed, 137 insertions(+), 15 deletions(-) diff --git a/includes/class-messages.php b/includes/class-messages.php index f0335bc5..3d54d7a1 100644 --- a/includes/class-messages.php +++ b/includes/class-messages.php @@ -132,11 +132,42 @@ public function add_rest_routes() { array( 'methods' => 'POST', 'callback' => array( $this, 'rest_receive_message' ), - 'permission_callback' => Friends::authenticated_for_posts(), + 'permission_callback' => array( $this, 'permission_check_receive_message' ), ) ); } + public function permission_check_receive_message( \WP_REST_Request $request ) { + if ( Friends::authenticated_for_posts() ) { + return true; + } + + $tokens = explode( '-', $request->get_param( 'auth' ) ); + $user_id = $this->friends->access_control->verify_token( $tokens[0], isset( $tokens[1] ) ? $tokens[1] : null, isset( $tokens[2] ) ? $tokens[2] : null ); + if ( ! $user_id ) { + return new \WP_Error( + 'friends_request_failed', + __( 'Could not respond to the request.', 'friends' ), + array( + 'status' => 403, + ) + ); + } + + $friend_user = new User( $user_id ); + if ( ! $friend_user->has_cap( self::get_minimum_cap( $friend_user ) ) ) { + return new \WP_Error( + 'friends_request_failed', + __( 'Could not respond to the request.', 'friends' ), + array( + 'status' => 403, + ) + ); + } + + return true; + } + /** * Receive a message via REST * diff --git a/includes/class-rest.php b/includes/class-rest.php index 54d2cbe1..01128be7 100644 --- a/includes/class-rest.php +++ b/includes/class-rest.php @@ -56,7 +56,7 @@ public function add_rest_routes() { array( 'methods' => 'POST', 'callback' => array( $this, 'rest_friend_request' ), - 'permission_callback' => '__return_true', + 'permission_callback' => array( $this, 'permission_check_friend_request' ), 'args' => array( 'url' => array( 'type' => 'string', @@ -96,7 +96,7 @@ public function add_rest_routes() { array( 'methods' => 'GET', 'callback' => array( $this, 'rest_friendship_requested' ), - 'permission_callback' => '__return_true', + 'permission_callback' => '__return_true', // Unauthenticated is ok. 'args' => array( 'url' => array( 'type' => 'string', @@ -112,7 +112,7 @@ public function add_rest_routes() { array( 'methods' => 'POST', 'callback' => array( $this, 'rest_accept_friend_request' ), - 'permission_callback' => '__return_true', + 'permission_callback' => array( $this, 'permssion_check_accept_friend_request' ), 'args' => array( 'url' => array( 'type' => 'string', @@ -144,7 +144,7 @@ public function add_rest_routes() { array( 'methods' => 'POST', 'callback' => array( $this, 'rest_friend_post_deleted' ), - 'permission_callback' => '__return_true', + 'permission_callback' => array( $this, 'permission_check_friends_only' ), ) ); register_rest_route( @@ -153,7 +153,9 @@ public function add_rest_routes() { array( 'methods' => 'GET', 'callback' => array( $this, 'rest_embed_friend_post' ), - 'permission_callback' => '__return_true', + 'permission_callback' => function () { + return current_user_can( Friends::REQUIRED_ROLE ); + }, ) ); @@ -188,6 +190,58 @@ public function add_rest_routes() { ); } + public function permssion_check_accept_friend_request( \WP_REST_Request $request ) { + $url = $request->get_param( 'url' ); + + $friend_user = false; + $pending_friend_requests = User_Query::all_pending_friend_requests(); + foreach ( $pending_friend_requests->get_results() as $pending_friend_request ) { + if ( $pending_friend_request->user_url === $url ) { + $friend_user = $pending_friend_request; + break; + } + } + + if ( ! $friend_user ) { + // Maybe they are already friends from the other side. + $potential_friends = User_Query::all_friends(); + foreach ( $potential_friends->get_results() as $potential_friend ) { + if ( $potential_friend->user_url === $url ) { + $friend_user = $potential_friend; + break; + } + } + + if ( ! $friend_user ) { + return new \WP_Error( + 'friends_invalid_parameters', + 'Not all necessary parameters were provided.', + array( + 'status' => 403, + ) + ); + } + } + + $their_key = $request->get_param( 'key' ); + $our_key = $request->get_param( 'your_key' ); + + if ( + $friend_user->get_user_option( 'friends_out_token' ) !== $our_key + || $friend_user->get_user_option( 'friends_in_token' ) !== $their_key + ) { + return new \WP_Error( + 'friends_invalid_parameters', + 'Not all necessary parameters were provided.', + array( + 'status' => 403, + ) + ); + } + return true; + } + + /** * Receive a notification via REST that a friend request was accepted * @@ -219,7 +273,7 @@ public function rest_accept_friend_request( \WP_REST_Request $request ) { if ( ! $friend_user ) { return new \WP_Error( 'friends_invalid_parameters', - 'Not all necessary parameters were provided1.', + 'Not all necessary parameters were provided.', array( 'status' => 403, ) @@ -236,7 +290,7 @@ public function rest_accept_friend_request( \WP_REST_Request $request ) { ) { return new \WP_Error( 'friends_invalid_parameters', - 'Not all necessary parameters were provided2.', + 'Not all necessary parameters were provided.', array( 'status' => 403, ) @@ -341,13 +395,7 @@ public function rest_friendship_requested( \WP_REST_Request $request ) { ); } - /** - * Receive a friend request via REST - * - * @param \WP_REST_Request $request The incoming request. - * @return array The array to be returned via the REST API. - */ - public function rest_friend_request( \WP_REST_Request $request ) { + public function permission_check_friend_request( \WP_REST_Request $request ) { $version = $request->get_param( 'version' ); if ( 3 !== intval( $version ) ) { return new \WP_Error( @@ -401,6 +449,18 @@ public function rest_friend_request( \WP_REST_Request $request ) { ); } + return true; + } + + /** + * Receive a friend request via REST + * + * @param \WP_REST_Request $request The incoming request. + * @return array The array to be returned via the REST API. + */ + public function rest_friend_request( \WP_REST_Request $request ) { + $url = $request->get_param( 'url' ); + $user_login = User::get_user_login_for_url( $url ); $friend_user = User::create( $user_login, 'friend_request', $url, $request->get_param( 'name' ), $request->get_param( 'icon_url' ) ); if ( $friend_user->has_cap( 'friend' ) ) { @@ -422,6 +482,37 @@ public function rest_friend_request( \WP_REST_Request $request ) { ); } + public function permission_check_friends_only( \WP_REST_Request $request ) { + if ( Friends::authenticated_for_posts() ) { + return true; + } + + $tokens = explode( '-', $request->get_param( 'auth' ) ); + $user_id = $this->friends->access_control->verify_token( $tokens[0], isset( $tokens[1] ) ? $tokens[1] : null, isset( $tokens[2] ) ? $tokens[2] : null ); + if ( ! $user_id ) { + return new \WP_Error( + 'friends_request_failed', + __( 'Could not respond to the request.', 'friends' ), + array( + 'status' => 403, + ) + ); + } + + $friend_user = new User( $user_id ); + if ( ! $friend_user->has_cap( 'friend' ) ) { + return new \WP_Error( + 'friends_request_failed', + __( 'Could not respond to the request.', 'friends' ), + array( + 'status' => 403, + ) + ); + } + + return true; + } + /** * Notify friends of a deleted post *