Skip to content

Commit 51cecc8

Browse files
authored
Fix public key retrieval for GoToSocial profiles (#2354)
1 parent b5ce6c8 commit 51cecc8

File tree

5 files changed

+74
-35
lines changed

5 files changed

+74
-35
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: fixed
3+
4+
Fix public key retrieval for GoToSocial profiles with path-based key URLs.

includes/collection/class-remote-actors.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use Activitypub\Sanitize;
1313
use Activitypub\Webfinger;
1414

15-
use function Activitypub\get_remote_metadata_by_actor;
1615
use function Activitypub\is_actor;
1716
use function Activitypub\object_to_uri;
1817

@@ -535,7 +534,14 @@ public static function normalize_identifier( $actor ) {
535534
* @return resource|\WP_Error The public key resource or WP_Error.
536535
*/
537536
public static function get_public_key( $key_id ) {
538-
$actor = get_remote_metadata_by_actor( \strip_fragment_from_url( $key_id ) );
537+
$actor = self::get_by_uri( \strip_fragment_from_url( $key_id ) );
538+
539+
if ( \is_wp_error( $actor ) ) {
540+
$actor = Http::get_remote_object( $key_id );
541+
} else {
542+
$actor = \json_decode( $actor->post_content, true );
543+
}
544+
539545
if ( \is_wp_error( $actor ) ) {
540546
return new \WP_Error( 'activitypub_no_remote_profile_found', 'No Profile found or Profile not accessible', array( 'status' => 401 ) );
541547
}

tests/phpunit/tests/includes/class-test-signature.php

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public function test_valid_hs2019_signatures_for_ec_curves( $curve, $algo ) {
8888

8989
// Mock the remote key retrieval for this curve.
9090
\add_filter(
91-
'pre_get_remote_metadata_by_actor',
91+
'activitypub_pre_http_get_remote_object',
9292
function () use ( $public_key ) {
9393
return array(
9494
'name' => 'Test User',
@@ -103,7 +103,7 @@ function () use ( $public_key ) {
103103
);
104104

105105
$this->assertTrue( Signature::verify_http_signature( $request ), "Valid hs2019 signature for curve {$curve} should verify" );
106-
\remove_all_filters( 'pre_get_remote_metadata_by_actor' );
106+
\remove_all_filters( 'activitypub_pre_http_get_remote_object' );
107107
}
108108

109109
/**
@@ -132,7 +132,7 @@ public function test_invalid_hs2019_signatures_for_ec_curves() {
132132
);
133133

134134
\add_filter(
135-
'pre_get_remote_metadata_by_actor',
135+
'activitypub_pre_http_get_remote_object',
136136
function () use ( $public_key ) {
137137
return array(
138138
'name' => 'Test User',
@@ -146,7 +146,7 @@ function () use ( $public_key ) {
146146
}
147147
);
148148
$this->assertWPError( Signature::verify_http_signature( $request ), 'Invalid hs2019 signature for curve prime256v1 should fail' );
149-
\remove_all_filters( 'pre_get_remote_metadata_by_actor' );
149+
\remove_all_filters( 'activitypub_pre_http_get_remote_object' );
150150
}
151151

152152
/**
@@ -191,7 +191,7 @@ public function test_valid_hs2019_signatures_for_rsa_sizes( $bits, $algo ) {
191191
);
192192

193193
\add_filter(
194-
'pre_get_remote_metadata_by_actor',
194+
'activitypub_pre_http_get_remote_object',
195195
function () use ( $public_key ) {
196196
return array(
197197
'name' => 'Test User',
@@ -205,7 +205,7 @@ function () use ( $public_key ) {
205205
}
206206
);
207207
$this->assertTrue( Signature::verify_http_signature( $request ), "Valid hs2019 signature for RSA {$bits} bits should verify" );
208-
\remove_all_filters( 'pre_get_remote_metadata_by_actor' );
208+
\remove_all_filters( 'activitypub_pre_http_get_remote_object' );
209209
}
210210

211211
/**
@@ -234,7 +234,7 @@ public function test_invalid_hs2019_signatures_for_rsa_sizes() {
234234
);
235235

236236
\add_filter(
237-
'pre_get_remote_metadata_by_actor',
237+
'activitypub_pre_http_get_remote_object',
238238
function () use ( $public_key ) {
239239
return array(
240240
'name' => 'Test User',
@@ -248,7 +248,7 @@ function () use ( $public_key ) {
248248
}
249249
);
250250
$this->assertWPError( Signature::verify_http_signature( $request ), 'Invalid hs2019 signature for RSA 2048 bits should fail' );
251-
\remove_all_filters( 'pre_get_remote_metadata_by_actor' );
251+
\remove_all_filters( 'activitypub_pre_http_get_remote_object' );
252252
}
253253

254254
/**
@@ -276,7 +276,7 @@ public function test_unsupported_ec_curve_for_hs2019() {
276276
),
277277
);
278278
\add_filter(
279-
'pre_get_remote_metadata_by_actor',
279+
'activitypub_pre_http_get_remote_object',
280280
function () use ( $public_key ) {
281281
return array(
282282
'name' => 'Test User',
@@ -290,7 +290,7 @@ function () use ( $public_key ) {
290290
}
291291
);
292292
$this->assertWPError( Signature::verify_http_signature( $request ), 'Unsupported EC curve secp256k1 should fail' );
293-
\remove_all_filters( 'pre_get_remote_metadata_by_actor' );
293+
\remove_all_filters( 'activitypub_pre_http_get_remote_object' );
294294
}
295295

296296
/**
@@ -303,7 +303,7 @@ public function test_verify_http_signature_with_digest() {
303303
$keys = Actors::get_keypair( 1 );
304304

305305
\add_filter(
306-
'pre_get_remote_metadata_by_actor',
306+
'activitypub_pre_http_get_remote_object',
307307
function () use ( $keys ) {
308308
return array(
309309
'name' => 'Admin',
@@ -359,7 +359,7 @@ function () use ( $keys ) {
359359

360360
$this->assertTrue( Signature::verify_http_signature( $request ) );
361361

362-
\remove_all_filters( 'pre_get_remote_metadata_by_actor' );
362+
\remove_all_filters( 'activitypub_pre_http_get_remote_object' );
363363
}
364364

365365
/**
@@ -377,7 +377,7 @@ public function test_verify_http_signature_rfc9421() {
377377
$keys = self::$test_keys['rsa']['4096'];
378378

379379
\add_filter(
380-
'pre_get_remote_metadata_by_actor',
380+
'activitypub_pre_http_get_remote_object',
381381
function () use ( $keys ) {
382382
return array(
383383
'name' => 'Admin',
@@ -441,7 +441,7 @@ function () use ( $keys ) {
441441
// The verification should succeed.
442442
$this->assertTrue( Signature::verify_http_signature( $request ) );
443443

444-
\remove_all_filters( 'pre_get_remote_metadata_by_actor' );
444+
\remove_all_filters( 'activitypub_pre_http_get_remote_object' );
445445
\delete_option( 'activitypub_rfc9421_signature' );
446446
}
447447

@@ -496,7 +496,7 @@ public function test_verify_http_signature_rfc9421_get_request() {
496496
$keys = self::$test_keys['rsa']['2048'];
497497

498498
\add_filter(
499-
'pre_get_remote_metadata_by_actor',
499+
'activitypub_pre_http_get_remote_object',
500500
function () use ( $keys ) {
501501
return array(
502502
'name' => 'Admin',
@@ -558,7 +558,7 @@ function () use ( $keys ) {
558558
// The verification should succeed.
559559
$this->assertTrue( Signature::verify_http_signature( $request ) );
560560

561-
\remove_all_filters( 'pre_get_remote_metadata_by_actor' );
561+
\remove_all_filters( 'activitypub_pre_http_get_remote_object' );
562562
}
563563

564564
/**
@@ -592,7 +592,7 @@ public function test_verify_http_signature_rfc9421_algorithms() {
592592
*/
593593
private function verify_rfc9421_signature_with_keys( $keys, $algorithm ) {
594594
\add_filter(
595-
'pre_get_remote_metadata_by_actor',
595+
'activitypub_pre_http_get_remote_object',
596596
function () use ( $keys ) {
597597
return array(
598598
'name' => 'Admin',
@@ -665,7 +665,7 @@ function () use ( $keys ) {
665665
// The verification should succeed.
666666
$this->assertTrue( Signature::verify_http_signature( $request ) );
667667

668-
\remove_all_filters( 'pre_get_remote_metadata_by_actor' );
668+
\remove_all_filters( 'activitypub_pre_http_get_remote_object' );
669669
}
670670

671671
/**

tests/phpunit/tests/includes/collection/class-test-remote-actors.php

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ public function test_key_format_handling() {
674674
-----END PUBLIC KEY-----
675675
';
676676

677-
\add_filter( 'pre_get_remote_metadata_by_actor', array( $this, 'pre_get_remote_metadata_by_actor' ), 10, 2 );
677+
\add_filter( 'activitypub_pre_http_get_remote_object', array( $this, 'pre_http_get_remote_object' ), 10, 2 );
678678

679679
// X.509 key should remain unchanged.
680680
$result = Remote_Actors::get_public_key( 'https://example.com/author/x509' );
@@ -702,7 +702,12 @@ public function test_key_format_handling() {
702702
$result = Remote_Actors::get_public_key( 'https://example.com/author/invalid' );
703703
$this->assertWPError( $result );
704704

705-
\remove_filter( 'pre_get_remote_metadata_by_actor', array( $this, 'pre_get_remote_metadata_by_actor' ) );
705+
// Test GoToSocial-style /main-key path suffix is stripped correctly.
706+
$result = Remote_Actors::get_public_key( 'https://example.com/author/x509/main-key' );
707+
$key_resource = \openssl_pkey_get_details( $result );
708+
$this->assertSame( $this->x509_key, $key_resource['key'] );
709+
710+
\remove_filter( 'activitypub_pre_http_get_remote_object', array( $this, 'pre_http_get_remote_object' ) );
706711
}
707712

708713
/**
@@ -876,7 +881,31 @@ function ( $preempt, $parsed_args, $url ) {
876881
* @return array|\WP_Error
877882
*/
878883
public function pre_get_remote_metadata_by_actor( $value, $url ) {
879-
if ( 'https://example.com/author/x509' === $url ) {
884+
if ( 'https://example.com/author/invalid' === $url ) {
885+
return array(
886+
'name' => 'Test Actor',
887+
'url' => 'https://example.com/author/invalid',
888+
'publicKey' => array(
889+
'id' => 'https://example.com/author#main-key',
890+
'owner' => 'https://example.com/author',
891+
'publicKeyPem' => 'INVALID KEY DATA',
892+
),
893+
);
894+
}
895+
896+
return new \WP_Error( 'invalid_url', $url );
897+
}
898+
899+
/**
900+
* Pre http get remote object.
901+
*
902+
* @param mixed $pre The preempted value.
903+
* @param string $url_or_object The URL or object.
904+
* @return array|\WP_Error
905+
*/
906+
public function pre_http_get_remote_object( $pre, $url_or_object ) {
907+
908+
if ( 'https://example.com/author/x509' === $url_or_object ) {
880909
return array(
881910
'name' => 'Test Actor',
882911
'url' => 'https://example.com/author/x509',
@@ -888,7 +917,7 @@ public function pre_get_remote_metadata_by_actor( $value, $url ) {
888917
);
889918
}
890919

891-
if ( 'https://example.com/author/pkcs1' === $url ) {
920+
if ( 'https://example.com/author/pkcs1' === $url_or_object ) {
892921
return array(
893922
'name' => 'Test Actor',
894923
'url' => 'https://example.com/author/pkcs1',
@@ -900,7 +929,7 @@ public function pre_get_remote_metadata_by_actor( $value, $url ) {
900929
);
901930
}
902931

903-
if ( 'https://example.com/author/ec' === $url ) {
932+
if ( 'https://example.com/author/ec' === $url_or_object ) {
904933
return array(
905934
'name' => 'Test Actor',
906935
'url' => 'https://example.com/author/ec',
@@ -912,7 +941,7 @@ public function pre_get_remote_metadata_by_actor( $value, $url ) {
912941
);
913942
}
914943

915-
if ( 'https://example.com/author/pkcs8' === $url ) {
944+
if ( 'https://example.com/author/pkcs8' === $url_or_object ) {
916945
return array(
917946
'name' => 'Test Actor',
918947
'url' => 'https://example.com/author/pkcs8',
@@ -924,18 +953,18 @@ public function pre_get_remote_metadata_by_actor( $value, $url ) {
924953
);
925954
}
926955

927-
if ( 'https://example.com/author/invalid' === $url ) {
956+
if ( 'https://example.com/author/x509/main-key' === $url_or_object ) {
928957
return array(
929-
'name' => 'Test Actor',
930-
'url' => 'https://example.com/author/invalid',
958+
'id' => 'https://example.com/author/x509',
959+
'type' => 'Person',
931960
'publicKey' => array(
932961
'id' => 'https://example.com/author#main-key',
933962
'owner' => 'https://example.com/author',
934-
'publicKeyPem' => 'INVALID KEY DATA',
963+
'publicKeyPem' => $this->x509_key,
935964
),
936965
);
937966
}
938967

939-
return new \WP_Error( 'invalid_url', $url );
968+
return $pre;
940969
}
941970
}

tests/phpunit/tests/includes/rest/class-test-actors-inbox-controller.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,8 @@ public function test_announce_request() {
260260
* @covers ::create_item
261261
*/
262262
public function test_user_inbox_post_verification() {
263-
add_filter(
264-
'pre_get_remote_metadata_by_actor',
263+
\add_filter(
264+
'activitypub_pre_http_get_remote_object',
265265
function ( $json, $actor ) {
266266
$public_key = Actors::get_public_key( self::$user_id );
267267

@@ -286,7 +286,7 @@ function ( $json, $actor ) {
286286
// Test valid request.
287287
$actor = Actors::get_by_id( self::$user_id );
288288
$object = \Activitypub\Transformer\Post::transform( $post )->to_object();
289-
$activity = new \Activitypub\Activity\Activity( 'Like' );
289+
$activity = new \Activitypub\Activity\Activity();
290290
$activity->from_array(
291291
array(
292292
'id' => 'https://example.com/activity/1',
@@ -330,7 +330,7 @@ function ( $json, $actor ) {
330330
$response = \rest_do_request( $request );
331331
$this->assertEquals( 202, $response->get_status() );
332332

333-
remove_filter( 'pre_get_remote_metadata_by_actor', '__return_true' );
333+
\remove_all_filters( 'activitypub_pre_http_get_remote_object' );
334334
}
335335

336336
/**

0 commit comments

Comments
 (0)