PluginProbe
ActivityPub / 9.2.1
ActivityPub v9.2.1
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
← All changes | includes/handler/class-undo.php +81 -26 2.0.09.2.1 View file →
@@ -1,47 +1,102 @@
1 1 <?php
2 +/**
3 + * Undo handler file.
4 + *
5 + * @package Activitypub
6 + */
7 +
2 8 namespace Activitypub\Handler;
3 9
4 -use Activitypub\Collection\Users;
5 -use Activitypub\Collection\Followers;
10 +use Activitypub\Collection\Inbox as Inbox_Collection;
6 11
12 +use function Activitypub\object_to_uri;
13 +
7 14 /**
8 - * Handle Undo requests
15 + * Handle Undo requests.
9 16 */
10 17 class Undo {
11 18 /**
12 - * Initialize the class, registering WordPress hooks
19 + * Initialize the class, registering WordPress hooks.
13 20 */
14 21 public static function init() {
15 - \add_action(
16 - 'activitypub_inbox_undo',
17 - array( self::class, 'handle_undo' )
18 - );
22 + \add_action( 'activitypub_inbox_undo', array( self::class, 'handle_undo' ), 10, 2 );
23 + \add_action( 'activitypub_validate_object', array( self::class, 'validate_object' ), 10, 3 );
19 24 }
20 25
21 26 /**
22 - * Handle "Unfollow" requests
27 + * Handle "Unfollow" requests.
23 28 *
24 - * @param array $activity The JSON "Undo" Activity
25 - * @param int $user_id The ID of the ID of the WordPress User
29 + * @param array $activity The JSON "Undo" Activity.
30 + * @param int|int[]|null $user_ids The user ID(s).
26 31 */
27 - public static function handle_undo( $activity ) {
28 - if (
29 - isset( $activity['object']['type'] ) &&
30 - 'Follow' === $activity['object']['type'] &&
31 - isset( $activity['object']['object'] ) &&
32 - filter_var( $activity['object']['object'], FILTER_VALIDATE_URL )
33 - ) {
34 - $user = Users::get_by_resource( $activity['object']['object'] );
32 + public static function handle_undo( $activity, $user_ids ) {
33 + $success = false;
35 34
36 - if ( ! $user || is_wp_error( $user ) ) {
37 - // If we can not find a user,
38 - // we can not initiate a follow process
39 - return;
40 - }
35 + /*
36 + * Resolve the sender so Inbox::undo() can verify ownership. A genuinely absent actor
37 + * maps to null (no ownership check, for programmatic callers), but an actor that is
38 + * present yet unparseable must be rejected rather than skipping the check — passing
39 + * null there would re-open the undo-by-id attack.
40 + */
41 + $actor = isset( $activity['actor'] ) ? object_to_uri( $activity['actor'] ) : null;
41 42
42 - $user_id = $user->get__id();
43 + if ( isset( $activity['actor'] ) && empty( $actor ) ) {
44 + $result = new \WP_Error(
45 + 'activitypub_undo_invalid_actor',
46 + \__( 'The Undo activity has an invalid actor.', 'activitypub' ),
47 + array( 'status' => 400 )
48 + );
49 + } else {
50 + $result = Inbox_Collection::undo( object_to_uri( $activity['object'] ), $actor );
51 + }
43 52
44 - Followers::remove_follower( $user_id, $activity['actor'] );
53 + if ( $result && ! \is_wp_error( $result ) ) {
54 + $success = true;
45 55 }
56 +
57 + /**
58 + * Fires after an ActivityPub Undo activity has been handled.
59 + *
60 + * @param array $activity The ActivityPub activity data.
61 + * @param int[] $user_ids The local user IDs.
62 + * @param bool $success True on success, false on failure.
63 + * @param \WP_Comment|string $result The target, based on the activity that is being undone.
64 + */
65 + \do_action( 'activitypub_handled_undo', $activity, (array) $user_ids, $success, $result );
66 + }
67 +
68 + /**
69 + * Validate the object.
70 + *
71 + * @param bool $valid The validation state.
72 + * @param string $param The object parameter.
73 + * @param \WP_REST_Request $request The request object.
74 + *
75 + * @return bool The validation state: true if valid, false if not.
76 + */
77 + public static function validate_object( $valid, $param, $request ) {
78 + $activity = $request->get_json_params();
79 +
80 + if ( empty( $activity['type'] ) ) {
81 + return false;
82 + }
83 +
84 + if ( 'Undo' !== $activity['type'] ) {
85 + return $valid;
86 + }
87 +
88 + if ( ! isset( $activity['actor'], $activity['object'] ) ) {
89 + return false;
90 + }
91 +
92 + if ( ! \is_array( $activity['object'] ) && ! \is_string( $activity['object'] ) ) {
93 + return false;
94 + }
95 +
96 + if ( \is_array( $activity['object'] ) && ! isset( $activity['object']['id'] ) ) {
97 + return false;
98 + }
99 +
100 + return $valid;
46 101 }
47 102 }