PluginProbe
ActivityPub / 5.3.1
ActivityPub v5.3.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/class-query.php +68 -215 8.2.15.3.1 View file →
@@ -6,9 +6,8 @@
6 6 */
7 7
8 8 namespace Activitypub;
9 9
10 -use Activitypub\Activity\Extended_Object\Quote_Authorization;
11 10 use Activitypub\Collection\Actors;
12 11 use Activitypub\Collection\Outbox;
13 12 use Activitypub\Transformer\Factory;
14 13
@@ -49,15 +48,8 @@
49 48 */
50 49 private $is_activitypub_request;
51 50
52 51 /**
53 - * Whether the current request is from the old host.
54 - *
55 - * @var bool
56 - */
57 - private $is_old_host_request;
58 -
59 - /**
60 52 * The constructor.
61 53 */
62 54 private function __construct() {
63 55 // Do nothing.
@@ -92,15 +84,38 @@
92 84 if ( $this->activitypub_object ) {
93 85 return $this->activitypub_object;
94 86 }
95 87
96 - if ( $this->prepare_activitypub_data() ) {
97 - return $this->activitypub_object;
88 + $queried_object = $this->get_queried_object();
89 +
90 + // Check for Outbox Activity.
91 + if (
92 + $queried_object instanceof \WP_Post &&
93 + Outbox::POST_TYPE === $queried_object->post_type
94 + ) {
95 + $activitypub_object = Outbox::maybe_get_activity( $queried_object );
96 +
97 + // Check if the Outbox Activity is public.
98 + if ( ! \is_wp_error( $activitypub_object ) ) {
99 + $this->activitypub_object = $activitypub_object;
100 +
101 + return $this->activitypub_object;
102 + }
98 103 }
99 104
100 - $queried_object = $this->get_queried_object();
101 - $transformer = Factory::get_transformer( $queried_object );
105 + if ( ! $queried_object ) {
106 + // If the object is not a valid ActivityPub object, try to get a virtual object.
107 + $activitypub_object = $this->maybe_get_virtual_object();
102 108
109 + if ( $activitypub_object ) {
110 + $this->activitypub_object = $activitypub_object;
111 +
112 + return $this->activitypub_object;
113 + }
114 + }
115 +
116 + $transformer = Factory::get_transformer( $queried_object );
117 +
103 118 if ( $transformer && ! \is_wp_error( $transformer ) ) {
104 119 $this->activitypub_object = $transformer->to_object();
105 120 }
106 121
@@ -116,64 +131,18 @@
116 131 if ( $this->activitypub_object_id ) {
117 132 return $this->activitypub_object_id;
118 133 }
119 134
120 - if ( $this->prepare_activitypub_data() ) {
135 + if ( $this->activitypub_object ) {
136 + $this->activitypub_object_id = $this->activitypub_object->get_id();
137 +
121 138 return $this->activitypub_object_id;
122 139 }
123 140
124 - $queried_object = $this->get_queried_object();
125 - $transformer = Factory::get_transformer( $queried_object );
126 -
127 - if ( $transformer && ! \is_wp_error( $transformer ) ) {
128 - $this->activitypub_object_id = $transformer->to_id();
129 - }
130 -
131 - return $this->activitypub_object_id;
141 + return $this->get_activitypub_object();
132 142 }
133 143
134 144 /**
135 - * Prepare and set both ActivityPub object and ID for Outbox activities and virtual objects.
136 - *
137 - * @return bool True if an object was found and set, false otherwise.
138 - */
139 - private function prepare_activitypub_data() {
140 - $queried_object = $this->get_queried_object();
141 -
142 - if ( $queried_object instanceof \WP_Post && \get_query_var( 'stamp' ) ) {
143 - return $this->maybe_get_stamp();
144 - }
145 -
146 - // Check for Outbox Activity.
147 - if (
148 - $queried_object instanceof \WP_Post &&
149 - Outbox::POST_TYPE === $queried_object->post_type
150 - ) {
151 - $activitypub_object = Outbox::maybe_get_activity( $queried_object );
152 -
153 - // Check if the Outbox Activity is public.
154 - if ( ! \is_wp_error( $activitypub_object ) ) {
155 - $this->activitypub_object = $activitypub_object;
156 - $this->activitypub_object_id = $this->activitypub_object->get_id();
157 - return true;
158 - }
159 - }
160 -
161 - if ( ! $queried_object ) {
162 - // If the object is not a valid ActivityPub object, try to get a virtual object.
163 - $activitypub_object = $this->maybe_get_virtual_object();
164 -
165 - if ( $activitypub_object ) {
166 - $this->activitypub_object = $activitypub_object;
167 - $this->activitypub_object_id = $this->activitypub_object->get_id();
168 - return true;
169 - }
170 - }
171 -
172 - return false;
173 - }
174 -
175 - /**
176 145 * Get the queried object.
177 146 *
178 147 * This adds support for Comments by `?c=123` IDs and Users by `?author=123` and `@username` IDs.
179 148 *
@@ -197,16 +166,8 @@
197 166 $queried_object = \get_post( $post_id );
198 167 }
199 168 }
200 169
201 - // Check Term by ID.
202 - if ( ! $queried_object ) {
203 - $term_id = \get_query_var( 'term_id' );
204 - if ( $term_id ) {
205 - $queried_object = \get_term( $term_id );
206 - }
207 - }
208 -
209 170 // Try to get Author by ID.
210 171 if ( ! $queried_object ) {
211 172 $url = $this->get_request_url();
212 173 $author_id = url_to_authorid( $url );
@@ -228,10 +189,10 @@
228 189 *
229 190 * Virtual objects are objects that are not stored in the database, but are created on the fly.
230 191 * The plugins currently supports two virtual objects: The Blog-Actor and the Application-Actor.
231 192 *
232 - * @see \Activitypub\Model\Blog
233 - * @see \Activitypub\Model\Application
193 + * @see \Activitypub\Blog
194 + * @see \Activitypub\Application
234 195 *
235 196 * @return object|null The virtual object.
236 197 */
237 198 protected function maybe_get_virtual_object() {
@@ -243,12 +204,12 @@
243 204
244 205 $author_id = url_to_authorid( $url );
245 206
246 207 if ( ! is_numeric( $author_id ) ) {
247 - $author_id = $url;
208 + return null;
248 209 }
249 210
250 - $user = Actors::get_by_various( $author_id );
211 + $user = Actors::get_by_id( $author_id );
251 212
252 213 if ( \is_wp_error( $user ) || ! $user ) {
253 214 return null;
254 215 }
@@ -260,9 +221,9 @@
260 221 * Get the request URL.
261 222 *
262 223 * @return string|null The request URL.
263 224 */
264 - public function get_request_url() {
225 + protected function get_request_url() {
265 226 if ( ! isset( $_SERVER['REQUEST_URI'] ) ) {
266 227 return null;
267 228 }
268 229
@@ -279,158 +240,50 @@
279 240 *
280 241 * @return bool True if the request is an ActivityPub request, false otherwise.
281 242 */
282 243 public function is_activitypub_request() {
283 - if ( ! isset( $this->is_activitypub_request ) ) {
284 - global $wp_query;
285 -
286 - $this->is_activitypub_request = false;
287 -
288 - // One can trigger an ActivityPub request by adding `?activitypub` to the URL.
289 - if ( isset( $wp_query->query_vars['activitypub'] ) || isset( $_GET['activitypub'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
290 - \defined( 'ACTIVITYPUB_REQUEST' ) || \define( 'ACTIVITYPUB_REQUEST', true );
291 - $this->is_activitypub_request = true;
292 -
293 - // The other (more common) option to make an ActivityPub request is to send an Accept header.
294 - } elseif ( isset( $_SERVER['HTTP_ACCEPT'] ) ) {
295 - $accept = \sanitize_text_field( \wp_unslash( $_SERVER['HTTP_ACCEPT'] ) );
296 -
297 - /*
298 - * $accept can be a single value, or a comma separated list of values.
299 - * We want to support both scenarios,
300 - * and return true when the header includes at least one of the following:
301 - * - application/activity+json
302 - * - application/ld+json
303 - * - application/json
304 - */
305 - if ( \preg_match( '/(application\/(ld\+json|activity\+json|json))/i', $accept ) ) {
306 - \defined( 'ACTIVITYPUB_REQUEST' ) || \define( 'ACTIVITYPUB_REQUEST', true );
307 - $this->is_activitypub_request = true;
308 - }
309 - }
244 + if ( isset( $this->is_activitypub_request ) ) {
245 + return $this->is_activitypub_request;
310 246 }
311 247
312 - /**
313 - * Filters whether the current request is an ActivityPub request.
314 - *
315 - * @param bool $is_activitypub_request True if the request is an ActivityPub request, false otherwise.
316 - */
317 - return \apply_filters( 'activitypub_is_activitypub_request', $this->is_activitypub_request );
318 - }
248 + global $wp_query;
319 249
320 - /**
321 - * Check if content negotiation is allowed for a request.
322 - *
323 - * @return bool True if content negotiation is allowed, false otherwise.
324 - */
325 - public function should_negotiate_content() {
326 - $return = false;
327 - $always_negotiate = array( 'p', 'c', 'author', 'actor', 'stamp', 'preview', 'activitypub' );
328 - $url = \wp_parse_url( $this->get_request_url(), PHP_URL_QUERY );
329 - $query = array();
330 - \wp_parse_str( $url, $query );
250 + // One can trigger an ActivityPub request by adding `?activitypub` to the URL.
251 + if (
252 + isset( $wp_query->query_vars['activitypub'] ) ||
253 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended
254 + isset( $_GET['activitypub'] )
255 + ) {
256 + defined( 'ACTIVITYPUB_REQUEST' ) || \define( 'ACTIVITYPUB_REQUEST', true );
257 + $this->is_activitypub_request = true;
331 258
332 - // Check if any of the query params are in the `$always_negotiate` array.
333 - if ( \array_intersect( \array_keys( $query ), $always_negotiate ) ) {
334 - $return = true;
259 + return true;
335 260 }
336 261
337 - if ( \get_option( 'activitypub_content_negotiation', '1' ) ) {
338 - $return = true;
339 - }
340 -
341 - if ( \is_author() && \get_user_option( 'activitypub_use_permalink_as_id', \get_queried_object_id() ) ) {
342 - $return = true;
343 - }
344 -
345 - /**
346 - * Filters whether content negotiation should be forced.
347 - *
348 - * @param bool $return Whether content negotiation should be forced.
262 + /*
263 + * The other (more common) option to make an ActivityPub request
264 + * is to send an Accept header.
349 265 */
350 - return \apply_filters( 'activitypub_should_negotiate_content', $return );
351 - }
266 + if ( isset( $_SERVER['HTTP_ACCEPT'] ) ) {
267 + $accept = \sanitize_text_field( \wp_unslash( $_SERVER['HTTP_ACCEPT'] ) );
352 268
353 - /**
354 - * Check if the current request is from the old host.
355 - *
356 - * @return bool True if the request is from the old host, false otherwise.
357 - */
358 - public function is_old_host_request() {
359 - if ( isset( $this->is_old_host_request ) ) {
360 - return $this->is_old_host_request;
361 - }
269 + /*
270 + * $accept can be a single value, or a comma separated list of values.
271 + * We want to support both scenarios,
272 + * and return true when the header includes at least one of the following:
273 + * - application/activity+json
274 + * - application/ld+json
275 + * - application/json
276 + */
277 + if ( \preg_match( '/(application\/(ld\+json|activity\+json|json))/i', $accept ) ) {
278 + defined( 'ACTIVITYPUB_REQUEST' ) || \define( 'ACTIVITYPUB_REQUEST', true );
279 + $this->is_activitypub_request = true;
362 280
363 - $old_host = \get_option( 'activitypub_old_host' );
364 -
365 - if ( ! $old_host ) {
366 - $this->is_old_host_request = false;
367 - return false;
281 + return true;
282 + }
368 283 }
369 284
370 - $request_host = isset( $_SERVER['HTTP_HOST'] ) ? \sanitize_text_field( \wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
371 - $referer_host = isset( $_SERVER['HTTP_REFERER'] ) ? \wp_parse_url( \sanitize_text_field( \wp_unslash( $_SERVER['HTTP_REFERER'] ) ), PHP_URL_HOST ) : '';
285 + $this->is_activitypub_request = false;
372 286
373 - // Check if the domain matches either the request domain or referer.
374 - $check = $old_host === $request_host || $old_host === $referer_host;
375 - $this->is_old_host_request = $check;
376 -
377 - return $check;
378 - }
379 -
380 - /**
381 - * Fake an old host request.
382 - *
383 - * @param bool $state Optional. The state to set. Default true.
384 - */
385 - public function set_old_host_request( $state = true ) {
386 - $this->is_old_host_request = $state;
387 - }
388 -
389 - /**
390 - * Maybe get a QuoteAuthorization object from a stamp.
391 - *
392 - * @return bool True if the object was prepared, false otherwise.
393 - */
394 - private function maybe_get_stamp() {
395 - require_once ABSPATH . 'wp-admin/includes/post.php';
396 -
397 - $stamp = \get_query_var( 'stamp' );
398 - $meta = \get_post_meta_by_id( (int) $stamp );
399 -
400 - if ( ! $meta ) {
401 - return false;
402 - }
403 -
404 - $post = $this->get_queried_object();
405 -
406 - // Ensure the meta belongs to the queried post to prevent arbitrary meta disclosure.
407 - if ( (int) $meta->post_id !== $post->ID ) {
408 - return false;
409 - }
410 -
411 - $user_uri = get_user_id( $post->post_author );
412 -
413 - if ( ! $user_uri ) {
414 - return false;
415 - }
416 -
417 - $stamp_uri = \add_query_arg(
418 - array(
419 - 'p' => $post->ID,
420 - 'stamp' => $meta->meta_id,
421 - ),
422 - \home_url( '/' )
423 - );
424 -
425 - $activitypub_object = new Quote_Authorization();
426 - $activitypub_object->set_id( $stamp_uri );
427 - $activitypub_object->set_attributed_to( $user_uri );
428 - $activitypub_object->set_interacting_object( $meta->meta_value );
429 - $activitypub_object->set_interaction_target( get_post_id( $post->ID ) );
430 -
431 - $this->activitypub_object = $activitypub_object;
432 - $this->activitypub_object_id = $activitypub_object->get_id();
433 -
434 - return true;
287 + return false;
435 288 }
436 289 }