updated plugin ActivityPub version 9.1.0
This commit is contained in:
@ -71,6 +71,8 @@ class Router {
|
||||
'top'
|
||||
);
|
||||
|
||||
// Must precede the generic @username rule, which would otherwise match "application" as an actor username.
|
||||
\add_rewrite_rule( '^@application\/?$', 'index.php?rest_route=/' . ACTIVITYPUB_REST_NAMESPACE . '/application', 'top' );
|
||||
\add_rewrite_rule( '^@([\w\-\.]+)\/?$', 'index.php?actor=$matches[1]', 'top' );
|
||||
\add_rewrite_endpoint( 'activitypub', EP_AUTHORS | EP_PERMALINK | EP_PAGES );
|
||||
}
|
||||
@ -107,8 +109,31 @@ class Router {
|
||||
}
|
||||
|
||||
$activitypub_object = Query::get_instance()->get_activitypub_object();
|
||||
$queried_object = Query::get_instance()->get_queried_object();
|
||||
|
||||
if ( Tombstone::exists_local( Query::get_instance()->get_request_url() ) ) {
|
||||
/*
|
||||
* Serve the Tombstone for a deleted object — but not while an authorized
|
||||
* user is previewing it. During an editor `?preview=true` request,
|
||||
* `is_post_publicly_queryable()` treats a draft or pending post as
|
||||
* queryable only for a user who can edit it, so the author can still use
|
||||
* the Fediverse Preview on a post they just soft-deleted (which is
|
||||
* otherwise already in the tombstone registry).
|
||||
*
|
||||
* The bypass is scoped to that preview request on purpose. A normal
|
||||
* ActivityPub fetch (no `preview`) of a tombstoned URL always gets the
|
||||
* Tombstone — even if the URL now resolves to a fresh public post because
|
||||
* its slug was reused — since remote servers were told that id is gone.
|
||||
* The legitimate restore path clears the registry entry itself, via
|
||||
* `Create::maybe_unbury()` when the re-publish Create is queued.
|
||||
*/
|
||||
$is_authorized_preview = \get_query_var( 'preview' )
|
||||
&& $queried_object instanceof \WP_Post
|
||||
&& is_post_publicly_queryable( $queried_object );
|
||||
|
||||
if (
|
||||
Tombstone::exists_local( Query::get_instance()->get_request_url() )
|
||||
&& ! $is_authorized_preview
|
||||
) {
|
||||
// Set 410 Gone for permanently deleted posts, 200 OK for soft-deleted.
|
||||
if ( ! $activitypub_object ) {
|
||||
\status_header( 410 );
|
||||
@ -117,18 +142,36 @@ class Router {
|
||||
return ACTIVITYPUB_PLUGIN_DIR . 'templates/tombstone-json.php';
|
||||
}
|
||||
|
||||
/*
|
||||
* Refuse to expose the content-negotiated representation of a post
|
||||
* that is no longer publicly queryable (non-public status, AP
|
||||
* visibility flipped, post-type support removed, etc.). The
|
||||
* lifecycle gate in `is_post_disabled()` intentionally lets such
|
||||
* posts through the federation pipeline so a Delete can fire, but
|
||||
* that escape hatch must not leak into front-end rendering during
|
||||
* the window between status change and Delete delivery.
|
||||
*/
|
||||
if (
|
||||
$activitypub_object &&
|
||||
$queried_object instanceof \WP_Post &&
|
||||
'ap_outbox' !== $queried_object->post_type &&
|
||||
! is_post_publicly_queryable( $queried_object )
|
||||
) {
|
||||
return $template;
|
||||
}
|
||||
|
||||
$activitypub_template = false;
|
||||
|
||||
if ( $activitypub_object ) {
|
||||
if ( \get_query_var( 'preview' ) ) {
|
||||
\define( 'ACTIVITYPUB_PREVIEW', true );
|
||||
\defined( 'ACTIVITYPUB_PREVIEW' ) || \define( 'ACTIVITYPUB_PREVIEW', true );
|
||||
|
||||
/**
|
||||
* Filter the template used for the ActivityPub preview.
|
||||
*
|
||||
* @param string $activitypub_template Absolute path to the template file.
|
||||
*/
|
||||
$activitypub_template = apply_filters( 'activitypub_preview_template', ACTIVITYPUB_PLUGIN_DIR . '/templates/post-preview.php' );
|
||||
$activitypub_template = \apply_filters( 'activitypub_preview_template', ACTIVITYPUB_PLUGIN_DIR . '/templates/post-preview.php' );
|
||||
} else {
|
||||
$activitypub_template = ACTIVITYPUB_PLUGIN_DIR . 'templates/activitypub-json.php';
|
||||
}
|
||||
@ -191,7 +234,7 @@ class Router {
|
||||
}
|
||||
|
||||
if ( ! \headers_sent() ) {
|
||||
\header( 'Link: <' . esc_url( $id ) . '>; title="ActivityPub (JSON)"; rel="alternate"; type="application/activity+json"', false );
|
||||
\header( 'Link: <' . \esc_url( $id ) . '>; title="ActivityPub (JSON)"; rel="alternate"; type="application/activity+json"', false );
|
||||
|
||||
if ( \get_option( 'activitypub_vary_header', '1' ) ) {
|
||||
// Send Vary header for Accept header.
|
||||
@ -202,7 +245,7 @@ class Router {
|
||||
\add_action(
|
||||
'wp_head',
|
||||
static function () use ( $id ) {
|
||||
echo PHP_EOL . '<link rel="alternate" title="ActivityPub (JSON)" type="application/activity+json" href="' . esc_url( $id ) . '" />' . PHP_EOL;
|
||||
echo PHP_EOL . '<link rel="alternate" title="ActivityPub (JSON)" type="application/activity+json" href="' . \esc_url( $id ) . '" />' . PHP_EOL;
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -216,7 +259,7 @@ class Router {
|
||||
* @return string $redirect_url The possibly-unslashed redirect URL.
|
||||
*/
|
||||
public static function no_trailing_redirect( $redirect_url, $requested_url ) {
|
||||
if ( get_query_var( 'actor' ) ) {
|
||||
if ( \get_query_var( 'actor' ) ) {
|
||||
return $requested_url;
|
||||
}
|
||||
|
||||
@ -246,7 +289,7 @@ class Router {
|
||||
unset( $query_params['activitypub'] );
|
||||
unset( $query_params['stamp'] );
|
||||
|
||||
if ( 1 !== count( $query_params ) ) {
|
||||
if ( 1 !== \count( $query_params ) ) {
|
||||
return $redirect_url;
|
||||
}
|
||||
|
||||
@ -286,12 +329,20 @@ class Router {
|
||||
return;
|
||||
}
|
||||
|
||||
\wp_safe_redirect( get_comment_link( $comment ) );
|
||||
\wp_safe_redirect( \get_comment_link( $comment ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
$actor = \get_query_var( 'actor', null );
|
||||
if ( $actor ) {
|
||||
/*
|
||||
* Skip the actor branch when this looks like an actor-scoped FEP-7aa9
|
||||
* stamp URL: numeric `actor` paired with a `stamp`. Those resolve to a
|
||||
* FeatureAuthorization via Activitypub\Query, not via the username
|
||||
* lookup which would 404 the numeric ID. Non-numeric actors fall
|
||||
* through to the regular Mastodon-style profile lookup.
|
||||
*/
|
||||
$actor = \get_query_var( 'actor', null );
|
||||
$is_stamp_url = $actor && \get_query_var( 'stamp' ) && \ctype_digit( (string) $actor );
|
||||
if ( $actor && ! $is_stamp_url ) {
|
||||
$actor = Actors::get_by_username( $actor );
|
||||
if ( ! $actor || \is_wp_error( $actor ) ) {
|
||||
$wp_query->set_404();
|
||||
@ -325,7 +376,7 @@ class Router {
|
||||
*/
|
||||
$supported_taxonomies = \apply_filters( 'activitypub_supported_taxonomies', array( 'category', 'post_tag' ) );
|
||||
|
||||
if ( ! in_array( $term->taxonomy, $supported_taxonomies, true ) ) {
|
||||
if ( ! \in_array( $term->taxonomy, $supported_taxonomies, true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user