diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index 33cbfc98a4..672589a64f 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -563,6 +563,11 @@ class Processor return ''; } + if (in_array($activity['reply-to-id'], $activity['children'] ?? [])) { + Logger::notice('reply-to-id is already in the list of children', ['id' => $activity['reply-to-id'], 'children' => $activity['children'], 'depth' => count($activity['children'])]); + return ''; + } + self::addActivityId($activity['reply-to-id']); $completion = $activity['completion-mode'] ?? Receiver::COMPLETION_NONE; @@ -1632,6 +1637,11 @@ class Processor return null; } + if (!empty($child['children']) && in_array($url, $child['children'])) { + Logger::notice('id is already in the list of children', ['depth' => count($child['children']), 'children' => $child['children'], 'id' => $url]); + return null; + } + try { $curlResult = HTTPSignature::fetchRaw($url, $uid); } catch (\Exception $exception) { @@ -1725,6 +1735,16 @@ class Processor } $ldactivity['recursion-depth'] = !empty($child['recursion-depth']) ? $child['recursion-depth'] + 1 : 0; + $ldactivity['children'] = $child['children'] ?? []; + // This check ist mostly superflous, since there are similar checks before. This covers the case, when the fetched id doesn't match the url + if (in_array($activity['id'], $ldactivity['children'])) { + Logger::notice('Fetched id is already in the list of children. It will not be processed.', ['id' => $activity['id'], 'children' => $ldactivity['children'], 'depth' => count($ldactivity['children'])]); + return null; + } + if (!empty($child['id'])) { + $ldactivity['children'][] = $child['id']; + } + if ($object_actor != $actor) { Contact::updateByUrlIfNeeded($object_actor); @@ -1782,6 +1802,10 @@ class Processor if (Processor::alreadyKnown($id, $child['id'] ?? '')) { continue; } + if (!empty($child['children']) && in_array($id, $child['children'])) { + Logger::debug('Replies id is already in the list of children', ['depth' => count($child['children']), 'children' => $child['children'], 'id' => $id]); + continue; + } if (parse_url($id, PHP_URL_HOST) == parse_url($url, PHP_URL_HOST)) { Logger::debug('Incluced activity will be processed', ['replies' => $url, 'id' => $id]); self::processActivity($reply, $id, $child, '', Receiver::COMPLETION_REPLIES); diff --git a/src/Protocol/ActivityPub/Queue.php b/src/Protocol/ActivityPub/Queue.php index 53761585ff..b2e8cb301b 100644 --- a/src/Protocol/ActivityPub/Queue.php +++ b/src/Protocol/ActivityPub/Queue.php @@ -318,7 +318,7 @@ class Queue self::retrial($id); return false; } - if (!Post::exists(['uri' => $entry['in-reply-to-id']])) { + if (!Processor::alreadyKnown($entry['in-reply-to-id'], '')) { // This entry belongs to some other entry that need to be fetched first if (Fetch::hasWorker($entry['in-reply-to-id'])) { Logger::debug('Fetching of the activity is already queued', ['id' => $entry['activity-id'], 'reply-to-id' => $entry['in-reply-to-id']]); @@ -327,6 +327,11 @@ class Queue } Fetch::add($entry['in-reply-to-id']); $activity = json_decode($entry['activity'], true); + if (in_array($entry['in-reply-to-id'], $activity['children'] ?? [])) { + Logger::notice('reply-to-id is already in the list of children', ['id' => $entry['in-reply-to-id'], 'children' => $activity['children'], 'depth' => count($activity['children'])]); + self::retrial($id); + return false; + } $activity['recursion-depth'] = 0; $wid = Worker::add(Worker::PRIORITY_HIGH, 'FetchMissingActivity', $entry['in-reply-to-id'], $activity, '', Receiver::COMPLETION_ASYNC); Fetch::setWorkerId($entry['in-reply-to-id'], $wid); diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index bab386979a..9660827cd3 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -757,6 +757,8 @@ class Receiver $object_data['recursion-depth'] = $activity['recursion-depth']; } + $object_data['children'] = $activity['children'] ?? []; + if (!self::routeActivities($object_data, $type, $push, true, $uid)) { self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer); Queue::remove($object_data);