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-update.php +16 -5 8.2.19.2.1 View file →
@@ -12,8 +12,9 @@
12 12 use Activitypub\Collection\Remote_Posts;
13 13 use Activitypub\Http;
14 14
15 15 use function Activitypub\is_activity_reply;
16 +use function Activitypub\object_to_uri;
16 17
17 18 /**
18 19 * Handle Update requests.
19 20 */
@@ -28,9 +29,9 @@
28 29 /**
29 30 * Handle "Update" requests.
30 31 *
31 32 * @param array $activity The Activity object.
32 - * @param int[] $user_ids The user IDs. Always null for Update activities.
33 + * @param int[] $user_ids Local recipient user IDs (followers and addressed local actors); may be empty.
33 34 * @param \Activitypub\Activity\Activity $activity_object The activity object. Default null.
34 35 */
35 36 public static function handle_update( $activity, $user_ids, $activity_object ) {
36 37 $object_type = $activity['object']['type'] ?? '';
@@ -77,9 +78,9 @@
77 78 /**
78 79 * Update an Object.
79 80 *
80 81 * @param array $activity The Activity object.
81 - * @param int[]|null $user_ids The user IDs. Always null for Update activities.
82 + * @param int[]|null $user_ids Local recipient user IDs (followers and addressed local actors); may be empty.
82 83 * @param \Activitypub\Activity\Activity $activity_object The activity object. Default null.
83 84 */
84 85 public static function update_object( $activity, $user_ids, $activity_object ) {
85 86 $result = new \WP_Error( 'activitypub_update_failed', 'Update failed' );
@@ -90,8 +91,12 @@
90 91 $comment_data = Interactions::update_comment( $activity );
91 92
92 93 if ( false === $comment_data ) {
93 94 $updated = false;
95 + } elseif ( \is_wp_error( $comment_data ) ) {
96 + // Handled but rejected (e.g. a foreign actor): keep the failure so the
97 + // success flag stays false and the Create fallback is not triggered.
98 + $result = $comment_data;
94 99 } elseif ( ! empty( $comment_data['comment_ID'] ) ) {
95 100 $result = \get_comment( $comment_data['comment_ID'] );
96 101 }
97 102 } elseif ( \get_option( 'activitypub_create_posts', false ) ) {
@@ -123,9 +128,9 @@
123 128 /**
124 129 * Update an Actor.
125 130 *
126 131 * @param array $activity The Activity object.
127 - * @param int[]|null $user_ids The user IDs. Always null for Update activities.
132 + * @param int[]|null $user_ids Local recipient user IDs (followers and addressed local actors); may be empty.
128 133 */
129 134 public static function update_actor( $activity, $user_ids ) {
130 135 /*
131 136 * Prefer the actor data embedded in the activity object, as it contains
@@ -147,12 +152,18 @@
147 152 $actor = $object;
148 153 }
149 154 }
150 155
151 - if ( \is_array( $actor ) && isset( $actor['id'] ) ) {
156 + /*
157 + * An actor may only update itself. Bind the updated object to the activity
158 + * actor (the same constraint the Delete handler enforces) so a remote server
159 + * cannot overwrite another host's cached actor by sending an Update whose
160 + * object.id points at a victim actor.
161 + */
162 + if ( \is_array( $actor ) && isset( $actor['id'] ) && object_to_uri( $actor ) === object_to_uri( $activity['actor'] ) ) {
152 163 $state = Remote_Actors::upsert( $actor );
153 164 } else {
154 - $state = new \WP_Error( 'activitypub_update_failed', 'Update failed: missing or invalid actor object in Update activity' );
165 + $state = new \WP_Error( 'activitypub_update_failed', \__( 'Update failed: missing, invalid, or unauthorized actor object in Update activity.', 'activitypub' ) );
155 166 $actor = array();
156 167 }
157 168
158 169 /**