Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move permissions checks into a dedicated permission_callback #408

Merged
merged 2 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### 3.2.2
- Add more checks around friendships ([#407])
- Hoping that this hardening will bring back the plugin to the WordPress.org directory. In my opinion [the issue](https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/friends/friends-321-missing-authorization) was vastly exaggerated and didn't qualify to get the plugin taken down. Also it was not reported in a way that it could be patched in time. If you have a security issue to report, please follow the instructions on https://github.com/akirk/friends/blob/main/SECURITY.md and/or report through https://github.com/akirk/friends/security.

### 3.2.1
- OPML Import: Support OPMLs without nesting ([#403])

Expand Down Expand Up @@ -303,6 +307,7 @@
- PHP: Introduced a namespace, changed the plugin hooks to friends_loaded and friends_load_parsers
- Add checks for diagnosing the correct functioning to Site Health

[#407]: https://github.com/akirk/friends/pull/407
[#403]: https://github.com/akirk/friends/pull/403
[#401]: https://github.com/akirk/friends/pull/401
[#400]: https://github.com/akirk/friends/pull/400
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
- Requires PHP: 7.2
- Tested up to: 6.7
- License: GPL-2.0-or-later
- Stable tag: 3.2.1
- Stable tag: 3.2.2

Your own WordPress at the center of your online activity. Follow friends and other websites and establish friendship relationships between blogs.

Expand Down Expand Up @@ -96,6 +96,10 @@ There is a cache of your friends post in form of a Custom Post Type friend_post

## Changelog

### 3.2.2
- Add more checks around friendships ([#407])
- Hoping that this hardening will bring back the plugin to the WordPress.org directory. In my opinion [the issue](https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/friends/friends-321-missing-authorization) was vastly exaggerated and didn't qualify to get the plugin taken down. Also it was not reported in a way that it could be patched in time. If you have a security issue to report, please follow the instructions on https://github.com/akirk/friends/blob/main/SECURITY.md and/or report through https://github.com/akirk/friends/security.

### 3.2.1
- OPML Import: Support OPMLs without nesting ([#403])

Expand Down Expand Up @@ -157,6 +161,7 @@ There is a cache of your friends post in form of a Custom Post Type friend_post
- Fix 404 on the New private post widget props @liviacarolgouvea ([#361])
- Improve ghost.org ActivityPub compatibility ([#356])

[#407]: https://github.com/akirk/friends/pull/407
[#403]: https://github.com/akirk/friends/pull/403
[#401]: https://github.com/akirk/friends/pull/401
[#400]: https://github.com/akirk/friends/pull/400
Expand Down
4 changes: 2 additions & 2 deletions friends.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Plugin name: Friends
* Plugin author: Alex Kirk
* Plugin URI: https://github.com/akirk/friends
* Version: 3.2.1
* Version: 3.2.2
* Requires PHP: 5.6

* Description: A social network between WordPresses. Privacy focused, by itself a self-hosted RSS++ reader with notifications.
Expand All @@ -25,7 +25,7 @@
define( 'FRIENDS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'FRIENDS_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
define( 'FRIENDS_PLUGIN_FILE', plugin_dir_path( __FILE__ ) . '/' . basename( __FILE__ ) );
define( 'FRIENDS_VERSION', '3.2.1' );
define( 'FRIENDS_VERSION', '3.2.2' );

require_once __DIR__ . '/libs/Mf2/Parser.php';

Expand Down
33 changes: 32 additions & 1 deletion includes/class-messages.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down
119 changes: 105 additions & 14 deletions includes/class-rest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand All @@ -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',
Expand Down Expand Up @@ -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(
Expand All @@ -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 );
},
)
);

Expand Down Expand Up @@ -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
*
Expand Down Expand Up @@ -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,
)
Expand All @@ -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,
)
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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' ) ) {
Expand All @@ -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
*
Expand Down
Loading