X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FProtocol%2FActivityPub%2FReceiver.php;h=4b8f1557b88e3aaaa29e85c01406dee915052021;hb=7f4d399fc8ca0abd4ab99f1ee9dfecd5fa175fde;hp=fbe8c32dc70fe8624c6f408a0e5782aa18cfff96;hpb=fa579c2346d74b63c981cc7bdedc66f4e5697047;p=friendica.git diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index fbe8c32dc7..4b8f1557b8 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -1,6 +1,6 @@ $data) { $receivers[$key] = $data['uid']; @@ -412,7 +415,6 @@ class Receiver $object_data['object_id'] = JsonLD::fetchElement($activity, 'as:object', '@id'); $object_data['object_ids'] = JsonLD::fetchElementArray($activity, 'as:object', '@id'); $object_data['content'] = JsonLD::fetchElement($activity, 'as:content', '@type'); - $object_data['push'] = $push; } elseif (in_array($object_type, self::ACCOUNT_TYPES)) { $object_data = []; $object_data['id'] = JsonLD::fetchElement($activity, '@id'); @@ -420,16 +422,14 @@ class Receiver $object_data['object_actor'] = JsonLD::fetchElement($activity['as:object'], 'as:actor', '@id'); $object_data['object_object'] = JsonLD::fetchElement($activity['as:object'], 'as:object'); $object_data['object_type'] = JsonLD::fetchElement($activity['as:object'], '@type'); - $object_data['push'] = $push; if (!$trust_source && ($type == 'as:Delete')) { $apcontact = APContact::getByURL($object_data['object_id'], true); $trust_source = empty($apcontact) || ($apcontact['type'] == 'Tombstone') || $apcontact['suspended']; } - } elseif (in_array($type, ['as:Create', 'as:Update', 'as:Announce', 'as:Invite']) || strpos($type, '#emojiReaction')) { + } elseif (in_array($type, ['as:Create', 'as:Update', 'as:Invite']) || strpos($type, '#emojiReaction')) { // Fetch the content only on activities where this matters // We can receive "#emojiReaction" when fetching content from Hubzilla systems - // Always fetch on "Announce" - $object_data = self::fetchObject($object_id, $activity['as:object'], $trust_source && ($type != 'as:Announce'), $fetch_uid); + $object_data = self::fetchObject($object_id, $activity['as:object'], $trust_source, $fetch_uid); if (empty($object_data)) { Logger::info("Object data couldn't be processed"); return []; @@ -437,19 +437,13 @@ class Receiver $object_data['object_id'] = $object_id; - if ($type == 'as:Announce') { - $object_data['push'] = false; - } else { - $object_data['push'] = $push; - } - // Test if it is an answer to a mail if (DBA::exists('mail', ['uri' => $object_data['reply-to-id']])) { $object_data['directmessage'] = true; } else { $object_data['directmessage'] = JsonLD::fetchElement($activity, 'litepub:directMessage'); } - } elseif (in_array($type, array_merge(self::ACTIVITY_TYPES, ['as:Follow'])) && in_array($object_type, self::CONTENT_TYPES)) { + } elseif (in_array($type, array_merge(self::ACTIVITY_TYPES, ['as:Announce', 'as:Follow'])) && in_array($object_type, self::CONTENT_TYPES)) { // Create a mostly empty array out of the activity data (instead of the object). // This way we later don't have to check for the existence of each individual array element. $object_data = self::processObject($activity); @@ -457,7 +451,6 @@ class Receiver $object_data['author'] = JsonLD::fetchElement($activity, 'as:actor', '@id'); $object_data['object_id'] = $object_id; $object_data['object_type'] = ''; // Since we don't fetch the object, we don't know the type - $object_data['push'] = $push; } elseif (in_array($type, ['as:Add', 'as:Remove', 'as:Move'])) { $object_data = []; $object_data['id'] = JsonLD::fetchElement($activity, '@id'); @@ -465,7 +458,6 @@ class Receiver $object_data['object_id'] = JsonLD::fetchElement($activity, 'as:object', '@id'); $object_data['object_type'] = JsonLD::fetchElement($activity['as:object'], '@type'); $object_data['object_content'] = JsonLD::fetchElement($activity['as:object'], 'as:content', '@type'); - $object_data['push'] = $push; } else { $object_data = []; $object_data['id'] = JsonLD::fetchElement($activity, '@id'); @@ -473,7 +465,6 @@ class Receiver $object_data['object_actor'] = JsonLD::fetchElement($activity['as:object'], 'as:actor', '@id'); $object_data['object_object'] = JsonLD::fetchElement($activity['as:object'], 'as:object'); $object_data['object_type'] = JsonLD::fetchElement($activity['as:object'], '@type'); - $object_data['push'] = $push; // An Undo is done on the object of an object, so we need that type as well if (($type == 'as:Undo') && !empty($object_data['object_object'])) { @@ -488,6 +479,8 @@ class Receiver } } + $object_data['push'] = $push; + $object_data = self::addActivityFields($object_data, $activity); if (empty($object_data['object_type'])) { @@ -566,7 +559,7 @@ class Receiver return true; } - if ($type == 'as:View') { + if (!DI::config()->get('system', 'process_view') && ($type == 'as:View')) { Logger::info('View activities are ignored.', ['signer' => $signer, 'http_signer' => $http_signer]); return true; } @@ -650,7 +643,9 @@ class Receiver } } - if (DI::config()->get('system', 'decoupled_receiver') && ($trust_source || DI::config()->get('debug', 'ap_inbox_store_untrusted'))) { + $decouple = DI::config()->get('system', 'decoupled_receiver') && !in_array($completion, [self::COMPLETION_MANUAL, self::COMPLETION_ANNOUCE]); + + if ($decouple && ($trust_source || DI::config()->get('debug', 'ap_inbox_store_untrusted'))) { $object_data = Queue::add($object_data, $type, $uid, $http_signer, $push, $trust_source); } @@ -659,7 +654,7 @@ class Receiver return true; } - if (!empty($object_data['entry-id']) && DI::config()->get('system', 'decoupled_receiver') && ($push || ($completion == self::COMPLETION_RELAY))) { + if (!empty($object_data['entry-id']) && $decouple && ($push || ($completion == self::COMPLETION_RELAY))) { if (Queue::isProcessable($object_data['entry-id'])) { // We delay by 5 seconds to allow to accumulate all receivers $delayed = date(DateTimeFormat::MYSQL, time() + 5); @@ -676,7 +671,7 @@ class Receiver $object_data['recursion-depth'] = $activity['recursion-depth']; } - if (!self::routeActivities($object_data, $type, $push)) { + 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); } @@ -690,13 +685,12 @@ class Receiver * @param string $type * @param bool $push * @param bool $fetch_parents + * @param int $uid * * @return boolean Could the activity be routed? */ - public static function routeActivities(array $object_data, string $type, bool $push, bool $fetch_parents = true): bool + public static function routeActivities(array $object_data, string $type, bool $push, bool $fetch_parents = true, int $uid = 0): bool { - $activity = $object_data['object_activity'] ?? []; - switch ($type) { case 'as:Create': if (in_array($object_data['object_type'], self::CONTENT_TYPES)) { @@ -736,43 +730,24 @@ class Receiver case 'as:Announce': if (in_array($object_data['object_type'], self::CONTENT_TYPES)) { - $actor = JsonLD::fetchElement($activity, 'as:actor', '@id'); - $object_data['thread-completion'] = Contact::getIdForURL($actor); - $object_data['completion-mode'] = self::COMPLETION_ANNOUCE; - - if (!Post::exists(['uri' => $object_data['id'], 'uid' => 0])) { - $item = ActivityPub\Processor::createItem($object_data, $fetch_parents); - if (empty($item)) { - Logger::debug('announced id was not created', ['id' => $object_data['id']]); + if (!Item::searchByLink($object_data['object_id'], $uid)) { + if (ActivityPub\Processor::fetchMissingActivity($object_data['object_id'], [], $object_data['actor'], self::COMPLETION_ANNOUCE, $uid)) { + Logger::debug('Created announced id', ['uid' => $uid, 'id' => $object_data['object_id']]); + Queue::remove($object_data); + } else { + Logger::debug('Announced id was not created', ['uid' => $uid, 'id' => $object_data['object_id']]); Queue::remove($object_data); return true; } - - $item['post-reason'] = Item::PR_ANNOUNCEMENT; - ActivityPub\Processor::postItem($object_data, $item); - Logger::debug('Created announced id', ['id' => $object_data['id']]); } else { - Logger::info('Announced id already exists', ['id' => $object_data['id']]); + Logger::info('Announced id already exists', ['uid' => $uid, 'id' => $object_data['object_id']]); Queue::remove($object_data); } - if (!empty($activity)) { - $announce_object_data = self::processObject($activity); - $announce_object_data['name'] = $type; - $announce_object_data['author'] = $actor; - $announce_object_data['object_id'] = $object_data['id']; - $announce_object_data['object_type'] = $object_data['object_type']; - $announce_object_data['push'] = $push; - Logger::debug('Create announce activity', ['id' => $announce_object_data['id'], 'object_data' => $announce_object_data]); - - if (!empty($object_data['raw'])) { - $announce_object_data['raw'] = $object_data['raw']; - } - if (!empty($object_data['raw-object'])) { - $announce_object_data['raw-object'] = $object_data['raw-object']; - } - ActivityPub\Processor::createActivity($announce_object_data, Activity::ANNOUNCE); - } + ActivityPub\Processor::createActivity($object_data, Activity::ANNOUNCE); + } elseif (in_array($object_data['object_type'], ['as:Tombstone', ''])) { + // We don't have the object here or it is deleted. We ignore this activity. + Queue::remove($object_data); } else { return false; } @@ -841,7 +816,7 @@ class Receiver return false; } break; - + case 'as:Block': if (in_array($object_data['object_type'], self::ACCOUNT_TYPES)) { ActivityPub\Processor::blockAccount($object_data); @@ -857,7 +832,7 @@ class Receiver return false; } break; - + case 'as:Remove': if (in_array($object_data['object_type'], self::CONTENT_TYPES)) { ActivityPub\Processor::removeFromFeaturedCollection($object_data); @@ -1029,7 +1004,7 @@ class Receiver $uid = 0; $actor = JsonLD::fetchElement($activity, 'as:actor', '@id') ?? ''; - $receivers = self::getReceivers($activity, $actor); + $receivers = self::getReceivers($activity, $actor, [], false, false); foreach ($receivers as $receiver) { if ($receiver['type'] == self::TARGET_GLOBAL) { return 0; @@ -1062,6 +1037,10 @@ class Receiver } foreach ($receiver_list as $receiver) { + if ($receiver == 'Public') { + Logger::warning('Not compacted public collection found', ['activity' => $activity, 'callstack' => System::callstack(20)]); + $receiver = ActivityPub::PUBLIC_COLLECTION; + } if ($receiver == self::PUBLIC_COLLECTION) { $receiver = ActivityPub::PUBLIC_COLLECTION; } @@ -1076,14 +1055,15 @@ class Receiver * Fetch the receiver list from an activity array * * @param array $activity - * @param string $actor - * @param array $tags - * @param boolean $fetch_unlisted + * @param string $actor + * @param array $tags + * @param bool $fetch_unlisted + * @param bool $push * * @return array with receivers (user id) * @throws \Exception */ - private static function getReceivers(array $activity, string $actor, array $tags = [], bool $fetch_unlisted = false): array + private static function getReceivers(array $activity, string $actor, array $tags, bool $fetch_unlisted, bool $push): array { $reply = $receivers = $profile = []; @@ -1117,6 +1097,9 @@ class Receiver $profile = APContact::getByURL($actor); $followers = $profile['followers'] ?? ''; $is_forum = ($actor['type'] ?? '') == 'Group'; + if ($push) { + Contact::updateByUrlIfNeeded($actor); + } Logger::info('Got actor and followers', ['actor' => $actor, 'followers' => $followers]); } else { Logger::info('Empty actor', ['activity' => $activity]); @@ -1463,14 +1446,6 @@ class Receiver return $object_data; } - if ($type == 'as:Announce') { - $object_id = JsonLD::fetchElement($object, 'object', '@id'); - if (empty($object_id) || !is_string($object_id)) { - return false; - } - return self::fetchObject($object_id, [], false, $uid); - } - Logger::info('Unhandled object type: ' . $type); return false; } @@ -1878,6 +1853,35 @@ class Receiver return false; } + $object_data = self::getObjectDataFromActivity($object); + + $receiverdata = self::getReceivers($object, $object_data['actor'] ?? '', $object_data['tags'], true, false); + $receivers = $reception_types = []; + foreach ($receiverdata as $key => $data) { + $receivers[$key] = $data['uid']; + $reception_types[$data['uid']] = $data['type'] ?? 0; + } + + $object_data['receiver_urls'] = self::getReceiverURL($object); + $object_data['receiver'] = $receivers; + $object_data['reception_type'] = $reception_types; + + $object_data['unlisted'] = in_array(-1, $object_data['receiver']); + unset($object_data['receiver'][-1]); + unset($object_data['reception_type'][-1]); + + return $object_data; + } + + /** + * Create an object data array from a given activity + * + * @param array $object + * + * @return array Object data + */ + public static function getObjectDataFromActivity(array $object): array + { $object_data = []; $object_data['object_type'] = JsonLD::fetchElement($object, '@type'); $object_data['id'] = JsonLD::fetchElement($object, '@id'); @@ -1888,7 +1892,7 @@ class Receiver $object_data['reply-to-id'] = $object_data['id']; // On activities the "reply to" is the id of the object it refers to - if (in_array($object_data['object_type'], self::ACTIVITY_TYPES)) { + if (in_array($object_data['object_type'], array_merge(self::ACTIVITY_TYPES, ['as:Announce']))) { $object_id = JsonLD::fetchElement($object, 'as:object', '@id'); if (!empty($object_id)) { $object_data['reply-to-id'] = $object_id; @@ -2006,21 +2010,6 @@ class Receiver $object_data['question'] = self::processQuestion($object); } - $receiverdata = self::getReceivers($object, $object_data['actor'] ?? '', $object_data['tags'], true); - $receivers = $reception_types = []; - foreach ($receiverdata as $key => $data) { - $receivers[$key] = $data['uid']; - $reception_types[$data['uid']] = $data['type'] ?? 0; - } - - $object_data['receiver_urls'] = self::getReceiverURL($object); - $object_data['receiver'] = $receivers; - $object_data['reception_type'] = $reception_types; - - $object_data['unlisted'] = in_array(-1, $object_data['receiver']); - unset($object_data['receiver'][-1]); - unset($object_data['reception_type'][-1]); - return $object_data; }