Skip to content

Commit 50ed13a

Browse files
authored
Fix error when receiving replies to non-existent posts (#2673)
1 parent 5c1accb commit 50ed13a

File tree

4 files changed

+121
-0
lines changed

4 files changed

+121
-0
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 error when receiving replies to non-existent posts.

includes/collection/class-interactions.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ public static function add_comment( $activity ) {
8282
$comment_post_id = $parent_comment->comment_post_ID;
8383
}
8484

85+
if ( ! $comment_post_id ) {
86+
// Not a reply to a post or comment.
87+
return false;
88+
}
89+
8590
$comment_data['comment_post_ID'] = $comment_post_id;
8691
$comment_data['comment_parent'] = $parent_comment_id ? $parent_comment_id : 0;
8792

tests/phpunit/tests/includes/collection/class-test-interactions.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,74 @@ public function test_add_comment_to_ap_post_when_disabled() {
10641064
\remove_filter( 'pre_get_remote_metadata_by_actor', $metadata_filter );
10651065
}
10661066

1067+
/**
1068+
* Test add_comment returns false when post ID cannot be determined.
1069+
*
1070+
* This tests the guard against missing post ID when the inReplyTo
1071+
* doesn't resolve to any known post or comment.
1072+
*
1073+
* @covers ::add_comment
1074+
*/
1075+
public function test_add_comment_returns_false_when_no_post_id() {
1076+
$activity = array(
1077+
'actor' => 'https://example.com/users/someone',
1078+
'id' => 'https://example.com/activities/orphan',
1079+
'object' => array(
1080+
'id' => 'https://example.com/notes/orphan',
1081+
'content' => 'This is a reply to nothing',
1082+
'inReplyTo' => 'https://nonexistent.example.com/post/does-not-exist',
1083+
),
1084+
);
1085+
1086+
// Mock actor metadata.
1087+
$metadata_filter = static function () {
1088+
return array(
1089+
'name' => 'Someone',
1090+
'preferredUsername' => 'someone',
1091+
'id' => 'https://example.com/users/someone',
1092+
'url' => 'https://example.com/@someone',
1093+
);
1094+
};
1095+
\add_filter( 'pre_get_remote_metadata_by_actor', $metadata_filter );
1096+
1097+
$result = Interactions::add_comment( $activity );
1098+
1099+
$this->assertFalse( $result, 'Should return false when inReplyTo does not resolve to a post or comment' );
1100+
1101+
\remove_filter( 'pre_get_remote_metadata_by_actor', $metadata_filter );
1102+
}
1103+
1104+
/**
1105+
* Test add_reaction returns false when post ID cannot be determined.
1106+
*
1107+
* @covers ::add_reaction
1108+
*/
1109+
public function test_add_reaction_returns_false_when_no_post_id() {
1110+
$activity = array(
1111+
'type' => 'Like',
1112+
'actor' => 'https://example.com/users/liker',
1113+
'object' => 'https://nonexistent.example.com/post/does-not-exist',
1114+
'id' => 'https://example.com/activities/orphan-like',
1115+
);
1116+
1117+
// Mock actor metadata.
1118+
$metadata_filter = static function () {
1119+
return array(
1120+
'name' => 'Liker',
1121+
'preferredUsername' => 'liker',
1122+
'id' => 'https://example.com/users/liker',
1123+
'url' => 'https://example.com/@liker',
1124+
);
1125+
};
1126+
\add_filter( 'pre_get_remote_metadata_by_actor', $metadata_filter );
1127+
1128+
$result = Interactions::add_reaction( $activity );
1129+
1130+
$this->assertFalse( $result, 'Should return false when object does not resolve to a post' );
1131+
1132+
\remove_filter( 'pre_get_remote_metadata_by_actor', $metadata_filter );
1133+
}
1134+
10671135
/**
10681136
* Test that nested replies work with ap_post.
10691137
*

tests/phpunit/tests/includes/handler/class-test-create.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,4 +542,48 @@ public function test_create_post_enabled_by_option() {
542542
\remove_filter( 'activitypub_pre_http_get_remote_object', $mock_callback );
543543
\delete_option( 'activitypub_create_posts' );
544544
}
545+
546+
/**
547+
* Test that replies to non-existent posts return false.
548+
*
549+
* @covers \Activitypub\Collection\Interactions::add_comment
550+
*/
551+
public function test_reply_to_non_existent_post_returns_false() {
552+
$object = array(
553+
'actor' => $this->user_url,
554+
'type' => 'Create',
555+
'id' => 'https://example.com/id/' . microtime( true ),
556+
'to' => array( $this->user_url ),
557+
'cc' => array( 'https://www.w3.org/ns/activitystreams#Public' ),
558+
'object' => array(
559+
'id' => 'https://example.com/reply/123',
560+
'url' => 'https://example.com/reply/123',
561+
'inReplyTo' => 'https://non-existent-site.example/post/999',
562+
'content' => 'Reply to non-existent post',
563+
),
564+
);
565+
566+
$result = Create::handle_create( $object, $this->user_id );
567+
568+
$this->assertNull( $result );
569+
570+
// Verify no comment was created.
571+
$args = array(
572+
'type' => 'comment',
573+
'status' => 'any',
574+
);
575+
576+
$query = new \WP_Comment_Query( $args );
577+
$comments = $query->comments;
578+
579+
// Filter to check for our specific comment.
580+
$found = array_filter(
581+
$comments,
582+
function ( $comment ) {
583+
return 'Reply to non-existent post' === $comment->comment_content;
584+
}
585+
);
586+
587+
$this->assertEmpty( $found );
588+
}
545589
}

0 commit comments

Comments
 (0)