check_reader_capability(); if ( \is_wp_error( $permission ) ) { return $permission; } $permission = parent::get_item_permissions_check( $request ); if ( \is_wp_error( $permission ) || ! $permission ) { return $permission; } $post = $this->get_post( $request['id'] ); if ( \is_wp_error( $post ) ) { return $post; } $related_user_ids = \array_merge( \get_post_meta( $post->ID, Followers::FOLLOWER_META_KEY, false ), \get_post_meta( $post->ID, Following::FOLLOWING_META_KEY, false ), \get_post_meta( $post->ID, Following::PENDING_META_KEY, false ) ); if ( $this->can_read_feed_of( $related_user_ids ) ) { return true; } /* * Following is not the only way an actor gets cached: authoring a post that was boosted * or replied to into someone's feed does it too, and those records carry no relationship * meta. The reader already renders that actor's name and avatar next to the post, so the * record is readable by whoever the feed belongs to. */ if ( self::authored_a_post_in_feed_of( $post->ID, \get_current_user_id() ) ) { return true; } return new \WP_Error( 'activitypub_rest_forbidden', \__( 'Sorry, you are not allowed to read this actor.', 'activitypub' ), array( 'status' => \rest_authorization_required_code() ) ); } /** * Check whether an actor authored a cached post in a given user's feed. * * @since 9.3.0 * * @param int $actor_post_id The `ap_actor` post ID. * @param int $user_id The local user whose feed to look in. * @return bool True if the actor authored at least one post in that feed. */ private static function authored_a_post_in_feed_of( $actor_post_id, $user_id ) { if ( ! $user_id ) { return false; } $posts = \get_posts( array( 'post_type' => Remote_Posts::POST_TYPE, 'post_status' => 'publish', 'posts_per_page' => 1, 'fields' => 'ids', 'no_found_rows' => true, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 'meta_query' => array( array( 'key' => '_activitypub_remote_actor_id', 'value' => $actor_post_id, ), array( 'key' => '_activitypub_user_id', 'value' => $user_id, ), ), ) ); return ! empty( $posts ); } }