Skip to content

Commit b32dd85

Browse files
authored
Improve /@username URLs (#1390)
1 parent 7f4cbdc commit b32dd85

File tree

7 files changed

+71
-36
lines changed

7 files changed

+71
-36
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
* Use a later hook for Posts to get published to the Outbox, to get sure all `post_meta`s and `taxonomy`s are set stored properly.
1919
* Use webfinger as author email for comments from the Fediverse.
2020

21+
### Fixed
22+
23+
* Do not redirect `/@username` URLs to the API any more, to improve `AUTHORIZED_FETCH` handling.
24+
2125
## [5.3.2] - 2025-02-27
2226

2327
### Fixed

includes/class-activitypub.php

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Activitypub;
99

1010
use Exception;
11+
use Activitypub\Collection\Actors;
1112
use Activitypub\Collection\Outbox;
1213
use Activitypub\Collection\Followers;
1314
use Activitypub\Collection\Extra_Fields;
@@ -248,29 +249,50 @@ public static function redirect_canonical( $redirect_url, $requested_url ) {
248249
* @return void
249250
*/
250251
public static function template_redirect() {
252+
global $wp_query;
253+
251254
$comment_id = get_query_var( 'c', null );
252255

253256
// Check if it seems to be a comment.
254-
if ( ! $comment_id ) {
255-
return;
256-
}
257+
if ( $comment_id ) {
258+
$comment = get_comment( $comment_id );
257259

258-
$comment = get_comment( $comment_id );
260+
// Load a 404-page if `c` is set but not valid.
261+
if ( ! $comment ) {
262+
$wp_query->set_404();
263+
return;
264+
}
259265

260-
// Load a 404-page if `c` is set but not valid.
261-
if ( ! $comment ) {
262-
global $wp_query;
263-
$wp_query->set_404();
264-
return;
265-
}
266+
// Stop if it's not an ActivityPub comment.
267+
if ( is_activitypub_request() && ! is_local_comment( $comment ) ) {
268+
return;
269+
}
266270

267-
// Stop if it's not an ActivityPub comment.
268-
if ( is_activitypub_request() && ! is_local_comment( $comment ) ) {
269-
return;
271+
wp_safe_redirect( get_comment_link( $comment ) );
272+
exit;
270273
}
271274

272-
wp_safe_redirect( get_comment_link( $comment ) );
273-
exit;
275+
$actor = get_query_var( 'actor', null );
276+
if ( $actor ) {
277+
$actor = Actors::get_by_username( $actor );
278+
if ( ! $actor || \is_wp_error( $actor ) ) {
279+
$wp_query->set_404();
280+
return;
281+
}
282+
283+
if ( is_activitypub_request() ) {
284+
return;
285+
}
286+
287+
if ( $actor->get__id() > 0 ) {
288+
$redirect_url = $actor->get_url();
289+
} else {
290+
$redirect_url = get_bloginfo( 'url' );
291+
}
292+
293+
wp_safe_redirect( $redirect_url, 301 );
294+
exit;
295+
}
274296
}
275297

276298
/**
@@ -284,6 +306,7 @@ public static function add_query_vars( $vars ) {
284306
$vars[] = 'activitypub';
285307
$vars[] = 'preview';
286308
$vars[] = 'author';
309+
$vars[] = 'actor';
287310
$vars[] = 'c';
288311
$vars[] = 'p';
289312

@@ -405,12 +428,7 @@ public static function add_rewrite_rules() {
405428
);
406429
}
407430

408-
\add_rewrite_rule(
409-
'^@([\w\-\.]+)$',
410-
'index.php?rest_route=/' . ACTIVITYPUB_REST_NAMESPACE . '/actors/$matches[1]',
411-
'top'
412-
);
413-
431+
\add_rewrite_rule( '^@([\w\-\.]+)\/?$', 'index.php?actor=$matches[1]', 'top' );
414432
\add_rewrite_endpoint( 'activitypub', EP_AUTHORS | EP_PERMALINK | EP_PAGES );
415433
}
416434

includes/class-migration.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,10 @@ public static function maybe_migrate() {
182182
if ( \version_compare( $version_from_db, '5.2.0', '<' ) ) {
183183
Scheduler::register_schedules();
184184
}
185-
if ( \version_compare( $version_from_db, '5.3.0', '<' ) ) {
186-
add_action( 'init', 'flush_rewrite_rules', 20 );
187-
}
188185
if ( \version_compare( $version_from_db, 'unreleased', '<' ) ) {
189186
\wp_schedule_single_event( \time(), 'activitypub_upgrade', array( 'update_actor_json_slashing' ) );
190187
\wp_schedule_single_event( \time(), 'activitypub_upgrade', array( 'update_comment_author_emails' ) );
188+
\add_action( 'init', 'flush_rewrite_rules', 20 );
191189
}
192190

193191
/*

includes/class-query.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,10 @@ protected function maybe_get_virtual_object() {
205205
$author_id = url_to_authorid( $url );
206206

207207
if ( ! is_numeric( $author_id ) ) {
208-
return null;
208+
$author_id = $url;
209209
}
210210

211-
$user = Actors::get_by_id( $author_id );
211+
$user = Actors::get_by_various( $author_id );
212212

213213
if ( \is_wp_error( $user ) || ! $user ) {
214214
return null;

includes/rest/class-actors-controller.php

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,6 @@ public function get_item( $request ) {
101101
return $user;
102102
}
103103

104-
$link_header = \sprintf( '<%1$s>; rel="alternate"; type="application/activity+json"', $user->get_id() );
105-
106-
// Redirect to canonical URL if it is not an ActivityPub request.
107-
if ( ! is_activitypub_request() ) {
108-
\header( 'Link: ' . $link_header );
109-
\header( 'Location: ' . $user->get_canonical_url(), true, 301 );
110-
exit;
111-
}
112-
113104
/**
114105
* Action triggered prior to the ActivityPub profile being created and sent to the client.
115106
*/
@@ -119,7 +110,7 @@ public function get_item( $request ) {
119110

120111
$response = \rest_ensure_response( $data );
121112
$response->header( 'Content-Type', 'application/activity+json; charset=' . \get_option( 'blog_charset' ) );
122-
$response->header( 'Link', $link_header );
113+
$response->header( 'Link', \sprintf( '<%1$s>; rel="alternate"; type="application/activity+json"', $user->get_id() ) );
123114

124115
return $response;
125116
}

readme.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ For reasons of data protection, it is not possible to see the followers of other
136136
* Changed: Bumped minimum required WordPress version to 6.4.
137137
* Changed: Use a later hook for Posts to get published to the Outbox, to get sure all `post_meta`s and `taxonomy`s are set stored properly.
138138
* Changed: Use webfinger as author email for comments from the Fediverse.
139+
* Fixed: Do not redirect `/@username` URLs to the API any more, to improve `AUTHORIZED_FETCH` handling.
139140

140141
= 5.3.2 =
141142

tests/includes/class-test-query.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,29 @@ public function test_comment_activitypub_object() {
265265
$this->assertNull( Query::get_instance()->get_activitypub_object() );
266266
}
267267

268+
/**
269+
* Test user at URL activity object.
270+
*
271+
* @covers ::get_activitypub_object
272+
*/
273+
public function test_user_at_url_activity_object() {
274+
$user_id = self::factory()->user->create(
275+
array(
276+
'user_login' => 'testuser',
277+
'role' => 'author',
278+
)
279+
);
280+
281+
Query::get_instance()->__destruct();
282+
$user = get_user_by( 'id', $user_id );
283+
$at_url = home_url( '/@' . $user->user_login . '/?activitypub' );
284+
285+
$this->go_to( $at_url );
286+
$this->assertNotNull( Query::get_instance()->get_activitypub_object() );
287+
288+
\wp_delete_user( $user_id );
289+
}
290+
268291
/**
269292
* Test user activitypub object.
270293
*

0 commit comments

Comments
 (0)