From 9fe70af85a9bc6ca69e6e708009420042e665d3f Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 22 Dec 2022 21:58:51 +0000 Subject: [PATCH] AP: Support for "move" and "accept" from gup.pe --- src/Protocol/ActivityPub/Processor.php | 57 +++++++++++++++++++++++++- src/Protocol/ActivityPub/Receiver.php | 31 ++++++++++---- 2 files changed, 77 insertions(+), 11 deletions(-) diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index d098ddb69..a18d6be77 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -1733,6 +1733,38 @@ class Processor Queue::remove($activity); } + /** + * Add moved contacts as followers for all subscribers of the old contact + * + * @param array $activity + * @return void + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + */ + public static function movePerson(array $activity) + { + if (empty($activity['target_id']) || empty($activity['object_id'])) { + return; + } + + if ($activity['object_id'] != $activity['actor']) { + Logger::notice('Object is not the actor', ['activity' => $activity]); + return; + } + + $from = Contact::getByURL($activity['object_id'], false, ['uri-id']); + if (empty($from['uri-id'])) { + Logger::info('Object not found', ['activity' => $activity]); + return; + } + + $contacts = DBA::select('contact', ['uid', 'url'], ["`uri-id` = ? AND `uid` != ? AND `rel` IN (?, ?)", $from['uri-id'], 0, Contact::FRIEND, Contact::SHARING]); + while ($from_contact = DBA::fetch($contacts)) { + $result = Contact::createFromProbeForUser($from_contact['uid'], $activity['target_id']); + Logger::debug('Follower added', ['from' => $from_contact, 'result' => $result]); + } + DBA::close($contacts); + } + /** * Blocks the user by the contact * @@ -1792,17 +1824,38 @@ class Processor */ public static function acceptFollowUser(array $activity) { - $uid = User::getIdForURL($activity['object_actor']); + if (!empty($activity['object_actor'])) { + $uid = User::getIdForURL($activity['object_actor']); + $check_id = false; + } elseif (!empty($activity['receiver']) && (count($activity['receiver']) == 1)) { + $uid = array_shift($activity['receiver']); + $check_id = true; + } + if (empty($uid)) { + Logger::notice('User could not be detected', ['activity' => $activity]); + Queue::remove($activity); return; } $cid = Contact::getIdForURL($activity['actor'], $uid); if (empty($cid)) { - Logger::info('No contact found', ['actor' => $activity['actor']]); + Logger::notice('No contact found', ['actor' => $activity['actor']]); + Queue::remove($activity); return; } + $id = Transmitter::activityIDFromContact($cid); + if ($id == $activity['object_id']) { + Logger::info('Successful id check', ['uid' => $uid, 'cid' => $cid]); + } else { + Logger::info('Unsuccessful id check', ['uid' => $uid, 'cid' => $cid, 'id' => $id, 'object_id' => $activity['object_id']]); + if ($check_id) { + Queue::remove($activity); + return; + } + } + self::switchContact($cid); $fields = ['pending' => false]; diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index 893982274..cb76ca7e1 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -451,7 +451,7 @@ class Receiver $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'])) { + } elseif (in_array($type, ['as:Add', 'as:Remove', 'as:Move'])) { $object_data = []; $object_data['id'] = JsonLD::fetchElement($activity, '@id'); $object_data['target_id'] = JsonLD::fetchElement($activity, 'as:target', '@id'); @@ -669,10 +669,6 @@ class Receiver $object_data['recursion-depth'] = $activity['recursion-depth']; } - if (in_array('as:Question', [$object_data['object_type'] ?? '', $object_data['object_object_type'] ?? ''])) { - self::storeUnhandledActivity(false, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer); - } - if (!self::routeActivities($object_data, $type, $push)) { self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer); Queue::remove($object_data); @@ -702,6 +698,8 @@ class Receiver } elseif (in_array($object_data['object_type'], ['pt:CacheFile'])) { // Unhandled Peertube activity Queue::remove($object_data); + } elseif (in_array($object_data['object_type'], self::ACCOUNT_TYPES)) { + ActivityPub\Processor::updatePerson($object_data); } else { return false; } @@ -739,7 +737,8 @@ class Receiver $item = ActivityPub\Processor::createItem($object_data, $fetch_parents); if (empty($item)) { Logger::debug('announced id was not created', ['id' => $object_data['id']]); - return false; + Queue::remove($object_data); + return true; } $item['post-reason'] = Item::PR_ANNOUNCEMENT; @@ -775,7 +774,7 @@ class Receiver case 'as:Like': if (in_array($object_data['object_type'], self::CONTENT_TYPES)) { ActivityPub\Processor::createActivity($object_data, Activity::LIKE); - } elseif ($object_data['object_type'] == '') { + } elseif (in_array($object_data['object_type'], ['', 'as:Tombstone'])) { // The object type couldn't be determined. We don't have it and we can't fetch it. We ignore this activity. Queue::remove($object_data); } else { @@ -786,7 +785,7 @@ class Receiver case 'as:Dislike': if (in_array($object_data['object_type'], self::CONTENT_TYPES)) { ActivityPub\Processor::createActivity($object_data, Activity::DISLIKE); - } elseif ($object_data['object_type'] == '') { + } elseif (in_array($object_data['object_type'], ['', 'as:Tombstone'])) { // The object type couldn't be determined. We don't have it and we can't fetch it. We ignore this activity. Queue::remove($object_data); } else { @@ -828,6 +827,14 @@ class Receiver } break; + case 'as:Move': + if (in_array($object_data['object_type'], self::ACCOUNT_TYPES)) { + ActivityPub\Processor::movePerson($object_data); + } else { + return false; + } + break; + case 'as:Block': if (in_array($object_data['object_type'], self::ACCOUNT_TYPES)) { ActivityPub\Processor::blockAccount($object_data); @@ -867,6 +874,9 @@ class Receiver } } elseif (in_array($object_data['object_type'], self::CONTENT_TYPES)) { ActivityPub\Processor::createActivity($object_data, Activity::ATTEND); + } elseif (!empty($object_data['object_id']) && empty($object_data['object_actor']) && empty($object_data['object_type'])) { + // Follow acceptances from gup.pe only contain the object id + ActivityPub\Processor::acceptFollowUser($object_data); } else { return false; } @@ -906,6 +916,9 @@ class Receiver in_array($object_data['object_object_type'], ['pt:CacheFile'])) { // Unhandled Peertube activity Queue::remove($object_data); + } elseif (in_array($object_data['object_type'], ['as:Delete'])) { + // We cannot undo deletions, so we just ignore this + Queue::remove($object_data); } else { return false; } @@ -972,7 +985,7 @@ class Receiver $tempfile = tempnam(System::getTempPath(), $file); file_put_contents($tempfile, json_encode(['activity' => $activity, 'body' => $body, 'uid' => $uid, 'trust_source' => $trust_source, 'push' => $push, 'signer' => $signer, 'object_data' => $object_data], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); - Logger::notice('Unknown activity stored', ['type' => $type, 'object_type' => $object_data['object_type'], $object_data['object_object_type'] ?? '', 'file' => $tempfile]); + Logger::notice('Unknown activity stored', ['type' => $type, 'object_type' => $object_data['object_type'], 'object_object_type' => $object_data['object_object_type'] ?? '', 'file' => $tempfile]); } /**