PluginProbe
ActivityPub / 7.7.0
ActivityPub v7.7.0
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 +16 -117 9.2.07.7.0 View file →
@@ -6,13 +6,11 @@
6 6 */
7 7
8 8 namespace Activitypub;
9 9
10 -use Activitypub\Activity\Extended_Object\Feature_Authorization;
11 10 use Activitypub\Activity\Extended_Object\Quote_Authorization;
12 11 use Activitypub\Collection\Actors;
13 12 use Activitypub\Collection\Outbox;
14 -use Activitypub\Handler\Feature_Request;
15 13 use Activitypub\Transformer\Factory;
16 14
17 15 /**
18 16 * Singleton class to handle and store the ActivityPub query.
@@ -140,17 +138,10 @@
140 138 */
141 139 private function prepare_activitypub_data() {
142 140 $queried_object = $this->get_queried_object();
143 141
144 - if ( \get_query_var( 'stamp' ) ) {
145 - if ( $queried_object instanceof \WP_Post ) {
146 - return $this->maybe_get_stamp();
147 - }
148 -
149 - // Note: the blog actor's `actor` query var is '0', which is falsy but valid.
150 - if ( $queried_object instanceof \WP_User || '' !== \get_query_var( 'actor' ) ) {
151 - return $this->maybe_get_actor_stamp();
152 - }
142 + if ( $queried_object instanceof \WP_Post && \get_query_var( 'stamp' ) ) {
143 + return $this->maybe_get_stamp();
153 144 }
154 145
155 146 // Check for Outbox Activity.
156 147 if (
@@ -206,16 +197,8 @@
206 197 $queried_object = \get_post( $post_id );
207 198 }
208 199 }
209 200
210 - // Check Term by ID.
211 - if ( ! $queried_object ) {
212 - $term_id = \get_query_var( 'term_id' );
213 - if ( $term_id ) {
214 - $queried_object = \get_term( $term_id );
215 - }
216 - }
217 -
218 201 // Try to get Author by ID.
219 202 if ( ! $queried_object ) {
220 203 $url = $this->get_request_url();
221 204 $author_id = url_to_authorid( $url );
@@ -228,9 +211,9 @@
228 211 * Filters the queried object.
229 212 *
230 213 * @param \WP_Term|\WP_Post_Type|\WP_Post|\WP_User|\WP_Comment|null $queried_object The queried object.
231 214 */
232 - return \apply_filters( 'activitypub_queried_object', $queried_object );
215 + return apply_filters( 'activitypub_queried_object', $queried_object );
233 216 }
234 217
235 218 /**
236 219 * Get the virtual object.
@@ -235,11 +218,12 @@
235 218 /**
236 219 * Get the virtual object.
237 220 *
238 221 * Virtual objects are objects that are not stored in the database, but are created on the fly.
239 - * The plugin currently supports one virtual object: The Blog-Actor.
222 + * The plugins currently supports two virtual objects: The Blog-Actor and the Application-Actor.
240 223 *
241 224 * @see \Activitypub\Model\Blog
225 + * @see \Activitypub\Model\Application
242 226 *
243 227 * @return object|null The virtual object.
244 228 */
245 229 protected function maybe_get_virtual_object() {
@@ -250,9 +234,9 @@
250 234 }
251 235
252 236 $author_id = url_to_authorid( $url );
253 237
254 - if ( ! \is_numeric( $author_id ) ) {
238 + if ( ! is_numeric( $author_id ) ) {
255 239 $author_id = $url;
256 240 }
257 241
258 242 $user = Actors::get_by_various( $author_id );
@@ -299,24 +283,19 @@
299 283 $this->is_activitypub_request = true;
300 284
301 285 // The other (more common) option to make an ActivityPub request is to send an Accept header.
302 286 } elseif ( isset( $_SERVER['HTTP_ACCEPT'] ) ) {
287 + $accept = \sanitize_text_field( \wp_unslash( $_SERVER['HTTP_ACCEPT'] ) );
288 +
303 289 /*
304 - * The Accept-header decision is delegated to is_json_only_accept() so the plugin and the
305 - * Surge cache drop-in classify byte-for-byte identically. Both must hand it the same raw
306 - * header, and they reach that raw form differently on purpose: this runs after
307 - * wp_magic_quotes() has addslashed $_SERVER, so it wp_unslash()es to recover the original
308 - * bytes; the drop-in runs before wp_magic_quotes() and passes its already-raw value
309 - * untouched. Do NOT sanitize it (the drop-in can't, its sanitizers aren't loaded yet) and
310 - * the helper must not stripslashes() either (that would corrupt the drop-in's genuine
311 - * bytes). It is only used to pick a content type, never stored or echoed.
312 - *
313 - * The request is ActivityPub only when *every* media type is JSON; a client that also
314 - * accepts HTML (e.g. a browser sending `text/html, application/activity+json`) gets the
315 - * normal HTML page.
290 + * $accept can be a single value, or a comma separated list of values.
291 + * We want to support both scenarios,
292 + * and return true when the header includes at least one of the following:
293 + * - application/activity+json
294 + * - application/ld+json
295 + * - application/json
316 296 */
317 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Classified only; wp_unslash() recovers the raw bytes the pre-plugin cache path sees, and it must not be sanitized.
318 - if ( is_json_only_accept( \wp_unslash( $_SERVER['HTTP_ACCEPT'] ) ) ) {
297 + if ( \preg_match( '/(application\/(ld\+json|activity\+json|json))/i', $accept ) ) {
319 298 \defined( 'ACTIVITYPUB_REQUEST' ) || \define( 'ACTIVITYPUB_REQUEST', true );
320 299 $this->is_activitypub_request = true;
321 300 }
322 301 }
@@ -350,12 +329,8 @@
350 329 if ( \get_option( 'activitypub_content_negotiation', '1' ) ) {
351 330 $return = true;
352 331 }
353 332
354 - if ( \is_author() && \get_user_option( 'activitypub_use_permalink_as_id', \get_queried_object_id() ) ) {
355 - $return = true;
356 - }
357 -
358 333 /**
359 334 * Filters whether content negotiation should be forced.
360 335 *
361 336 * @param bool $return Whether content negotiation should be forced.
@@ -413,20 +388,9 @@
413 388 if ( ! $meta ) {
414 389 return false;
415 390 }
416 391
417 - $post = $this->get_queried_object();
418 -
419 - /*
420 - * Only quote-authorization meta may be reflected as a stamp, and only for the queried
421 - * post. Checking the post id alone would still let an unauthenticated request read any
422 - * of that post's meta rows (e.g. _edit_lock or private custom fields) by guessing a
423 - * meta_id, so the meta key is verified too.
424 - */
425 - if ( '_activitypub_quoted_by' !== $meta->meta_key || (int) $meta->post_id !== $post->ID ) {
426 - return false;
427 - }
428 -
392 + $post = $this->get_queried_object();
429 393 $user_uri = get_user_id( $post->post_author );
430 394
431 395 if ( ! $user_uri ) {
432 396 return false;
@@ -447,73 +411,8 @@
447 411 $activitypub_object->set_interaction_target( get_post_id( $post->ID ) );
448 412
449 413 $this->activitypub_object = $activitypub_object;
450 414 $this->activitypub_object_id = $activitypub_object->get_id();
451 -
452 - return true;
453 - }
454 -
455 - /**
456 - * Maybe get a FeatureAuthorization object from an actor-scoped stamp.
457 - *
458 - * Resolves URLs of the form `?actor=USER_ID&stamp=STAMP_ID` against the
459 - * actor's stamp store, see {@see Feature_Request::get_stamp()}. Ownership
460 - * is enforced by resolving the stamp scoped to the queried actor, which
461 - * includes the blog actor (`actor=0`).
462 - *
463 - * @return bool True if a FeatureAuthorization was prepared, false otherwise.
464 - */
465 - private function maybe_get_actor_stamp() {
466 - $stamp_id = (int) \get_query_var( 'stamp' );
467 - $actor_var = \get_query_var( 'actor' );
468 -
469 - if ( ! $stamp_id ) {
470 - return false;
471 - }
472 -
473 - if ( '' === $actor_var ) {
474 - $queried = $this->get_queried_object();
475 - if ( ! $queried instanceof \WP_User ) {
476 - return false;
477 - }
478 -
479 - $actor_id = (int) $queried->ID;
480 - } else {
481 - // Values like '0e1' or '1.5' pass is_numeric() but cast to 0/1 and alias
482 - // an actor, so require a plain decimal integer before casting.
483 - if ( ! \ctype_digit( (string) $actor_var ) ) {
484 - return false;
485 - }
486 -
487 - $actor_id = (int) $actor_var;
488 - }
489 -
490 - $instrument = Feature_Request::get_stamp( $actor_id, $stamp_id );
491 - if ( null === $instrument ) {
492 - return false;
493 - }
494 -
495 - $actor = Actors::get_by_id( $actor_id );
496 - if ( \is_wp_error( $actor ) ) {
497 - return false;
498 - }
499 -
500 - $stamp_url = \add_query_arg(
501 - array(
502 - 'actor' => $actor_id,
503 - 'stamp' => $stamp_id,
504 - ),
505 - \home_url( '/' )
506 - );
507 -
508 - $authorization = new Feature_Authorization();
509 - $authorization->set_id( $stamp_url );
510 - $authorization->set_attributed_to( $actor->get_id() );
511 - $authorization->set_interacting_object( $instrument );
512 - $authorization->set_interaction_target( $actor->get_id() );
513 -
514 - $this->activitypub_object = $authorization;
515 - $this->activitypub_object_id = $authorization->get_id();
516 415
517 416 return true;
518 417 }
519 418 }