]> git.mxchange.org Git - friendica.git/blobdiff - src/Protocol/ActivityPub/Receiver.php
Issue 12977: Ensure to fetch quoted posts
[friendica.git] / src / Protocol / ActivityPub / Receiver.php
index 42fcb50865e142740cfbcd9058a7a0d097a620cb..a5286761639fcdb91df0ca546a42f10f358f9198 100644 (file)
@@ -74,11 +74,11 @@ class Receiver
        const TARGET_ANSWER = 6;
        const TARGET_GLOBAL = 7;
 
-       const COMPLETION_NONE    = 0;
-       const COMPLETION_ANNOUCE = 1;
-       const COMPLETION_RELAY   = 2;
-       const COMPLETION_MANUAL  = 3;
-       const COMPLETION_AUTO    = 4;
+       const COMPLETION_NONE     = 0;
+       const COMPLETION_ANNOUNCE = 1;
+       const COMPLETION_RELAY    = 2;
+       const COMPLETION_MANUAL   = 3;
+       const COMPLETION_AUTO     = 4;
 
        /**
         * Checks incoming message from the inbox
@@ -248,14 +248,14 @@ class Receiver
         * Fetches the object type for a given object id
         *
         * @param array   $activity
-        * @param string  $object_id Object ID of the the provided object
+        * @param string  $object_id Object ID of the provided object
         * @param integer $uid       User ID
         *
         * @return string with object type or NULL
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         * @throws \ImagickException
         */
-       private static function fetchObjectType(array $activity, string $object_id, int $uid = 0)
+       public static function fetchObjectType(array $activity, string $object_id, int $uid = 0)
        {
                if (!empty($activity['as:object'])) {
                        $object_type = JsonLD::fetchElement($activity['as:object'], '@type');
@@ -559,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;
                }
@@ -630,7 +630,7 @@ class Receiver
                        $object_data['object_activity'] = $activity;
                }
 
-               if (($type == 'as:Create') && $trust_source) {
+               if (($type == 'as:Create') && $trust_source && !in_array($completion, [self::COMPLETION_MANUAL, self::COMPLETION_ANNOUNCE])) {
                        if (self::hasArrived($object_data['object_id'])) {
                                Logger::info('The activity already arrived.', ['id' => $object_data['object_id']]);
                                return true;
@@ -641,9 +641,11 @@ class Receiver
                                Logger::info('The activity is already added.', ['id' => $object_data['object_id']]);
                                return true;
                        }
+               } elseif (($type == 'as:Create') && $trust_source && !self::hasArrived($object_data['object_id'])) {
+                       self::addArrivedId($object_data['object_id']);
                }
 
-               $decouple = DI::config()->get('system', 'decoupled_receiver') && !in_array($completion, [self::COMPLETION_MANUAL, self::COMPLETION_ANNOUCE]);
+               $decouple = DI::config()->get('system', 'decoupled_receiver') && !in_array($completion, [self::COMPLETION_MANUAL, self::COMPLETION_ANNOUNCE]);
 
                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);
@@ -731,7 +733,7 @@ class Receiver
                        case 'as:Announce':
                                if (in_array($object_data['object_type'], self::CONTENT_TYPES)) {
                                        if (!Item::searchByLink($object_data['object_id'], $uid)) {
-                                               if (ActivityPub\Processor::fetchMissingActivity($object_data['object_id'], [], $object_data['actor'], self::COMPLETION_ANNOUCE, $uid)) {
+                                               if (ActivityPub\Processor::fetchMissingActivity($object_data['object_id'], [], $object_data['actor'], self::COMPLETION_ANNOUNCE, $uid)) {
                                                        Logger::debug('Created announced id', ['uid' => $uid, 'id' => $object_data['object_id']]);
                                                        Queue::remove($object_data);
                                                } else {
@@ -1067,7 +1069,7 @@ class Receiver
        {
                $reply = $receivers = $profile = [];
 
-               // When it is an answer, we inherite the receivers from the parent
+               // When it is an answer, we inherit the receivers from the parent
                $replyto = JsonLD::fetchElement($activity, 'as:inReplyTo', '@id');
                if (!empty($replyto)) {
                        $reply = [$replyto];
@@ -1085,14 +1087,6 @@ class Receiver
                        $reply[] = $object_id;
                }
 
-               if (!empty($reply)) {
-                       $parents = Post::select(['uid'], DBA::mergeConditions(['uri' => $reply], ["`uid` != ?", 0]));
-                       while ($parent = Post::fetch($parents)) {
-                               $receivers[$parent['uid']] = ['uid' => $parent['uid'], 'type' => self::TARGET_ANSWER];
-                       }
-                       DBA::close($parents);
-               }
-
                if (!empty($actor)) {
                        $profile   = APContact::getByURL($actor);
                        $followers = $profile['followers'] ?? '';
@@ -1178,10 +1172,18 @@ class Receiver
                        }
                }
 
+               if (!empty($reply) && (!empty($receivers[0]) || !empty($receivers[-1]))) {
+                       $parents = Post::select(['uid'], DBA::mergeConditions(['uri' => $reply], ["`uid` != ?", 0]));
+                       while ($parent = Post::fetch($parents)) {
+                               $receivers[$parent['uid']] = ['uid' => $parent['uid'], 'type' => self::TARGET_ANSWER];
+                       }
+                       DBA::close($parents);
+               }
+
                self::switchContacts($receivers, $actor);
 
                // "birdsitelive" is a service that mirrors tweets into the fediverse
-               // These posts can be fetched without authentification, but are not marked as public
+               // These posts can be fetched without authentication, but are not marked as public
                // We treat them as unlisted posts to be able to handle them.
                if (empty($receivers) && $fetch_unlisted && Contact::isPlatform($actor, 'birdsitelive')) {
                        $receivers[0]  = ['uid' => 0, 'type' => self::TARGET_GLOBAL];
@@ -1370,9 +1372,9 @@ class Receiver
        }
 
        /**
-        * Fetches the object data from external ressources if needed
+        * Fetches the object data from external resources if needed
         *
-        * @param string  $object_id    Object ID of the the provided object
+        * @param string  $object_id    Object ID of the provided object
         * @param array   $object       The provided object array
         * @param boolean $trust_source Do we trust the provided object?
         * @param integer $uid          User ID for the signature that we use to fetch data
@@ -1873,23 +1875,6 @@ class Receiver
                return $object_data;
        }
 
-       /**
-        * Fetches data from the object part of an client to server activity
-        *
-        * @param array $object
-        *
-        * @return array Object data
-        */
-       private static function processC2SObject(array $object): array
-       {
-               $object_data = self::getObjectDataFromActivity($object);
-
-               $object_data['target']   = self::getTargets($object, $object_data['actor'] ?? '');
-               $object_data['receiver'] = [];
-
-               return $object_data;
-       }
-
        /**
         * Create an object data array from a given activity
         *
@@ -1897,7 +1882,7 @@ class Receiver
         *
         * @return array Object data
         */
-       private static function getObjectDataFromActivity(array $object): array
+       public static function getObjectDataFromActivity(array $object): array
        {
                $object_data = [];
                $object_data['object_type'] = JsonLD::fetchElement($object, '@type');
@@ -2054,190 +2039,4 @@ class Receiver
        {
                return DBA::exists('arrived-activity', ['object-id' => $id]);
        }
-
-       /**
-        * Process client to server activities
-        *
-        * @param array $activity
-        * @param integer $uid
-        * @param array $application
-        * @return array
-        */
-       public static function processC2SActivity(array $activity, int $uid, array $application): array
-       {
-               $ldactivity = JsonLD::compact($activity);
-               if (empty($ldactivity)) {
-                       Logger::notice('Invalid activity', ['activity' => $activity, 'uid' => $uid]);
-                       return [];
-               }
-
-               $type = JsonLD::fetchElement($ldactivity, '@type');
-               if (!$type) {
-                       Logger::notice('Empty type', ['activity' => $ldactivity, 'uid' => $uid]);
-                       return [];
-               }
-
-               $object_id   = JsonLD::fetchElement($ldactivity, 'as:object', '@id') ?? '';
-               $object_type = self::fetchObjectType($ldactivity, $object_id, $uid);
-               if (!$object_type && !$object_id) {
-                       Logger::notice('Empty object type or id', ['activity' => $ldactivity, 'uid' => $uid]);
-                       return [];
-               }
-
-               Logger::debug('Processing activity', ['type' => $type, 'object_type' => $object_type, 'object_id' => $object_id, 'activity' => $ldactivity]);
-               return self::routeC2SActivities($type, $object_type, $object_id, $uid, $application, $ldactivity);
-       }
-
-       /**
-        * Accumulate the targets and visibility of this post
-        *
-        * @param array $object
-        * @param string $actor
-        * @return array
-        */
-       private static function getTargets(array $object, string $actor): array
-       {
-               $profile   = APContact::getByURL($actor);
-               $followers = $profile['followers'];
-
-               $targets = [];
-
-               foreach (['as:to', 'as:cc', 'as:bto', 'as:bcc'] as $element) {
-                       switch ($element) {
-                               case 'as:to':
-                                       $type = self::TARGET_TO;
-                                       break;
-                               case 'as:cc':
-                                       $type = self::TARGET_CC;
-                                       break;
-                               case 'as:bto':
-                                       $type = self::TARGET_BTO;
-                                       break;
-                               case 'as:bcc':
-                                       $type = self::TARGET_BCC;
-                                       break;
-                       }
-                       $receiver_list = JsonLD::fetchElementArray($object, $element, '@id');
-                       if (empty($receiver_list)) {
-                               continue;
-                       }
-
-                       foreach ($receiver_list as $receiver) {
-                               if ($receiver == self::PUBLIC_COLLECTION) {
-                                       $targets[self::TARGET_GLOBAL] = ($element == 'as:to');
-                                       continue;
-                               }
-
-                               if ($receiver == $followers) {
-                                       $targets[self::TARGET_FOLLOWER] = true;
-                                       continue;
-                               }
-                               $targets[$type][] = Contact::getIdForURL($receiver);
-                       }
-               }
-               return $targets;
-       }
-
-       /**
-        * Route client to server activities
-        *
-        * @param string $type
-        * @param string $object_type
-        * @param string $object_id
-        * @param integer $uid
-        * @param array $application
-        * @param array $ldactivity
-        * @return array
-        */
-       private static function routeC2SActivities(string $type, string $object_type, string $object_id, int $uid, array $application, array $ldactivity): array
-       {
-               switch ($type) {
-                       case 'as:Create':
-                               if (in_array($object_type, self::CONTENT_TYPES)) {
-                                       return self::createContent($uid, $application, $ldactivity);
-                               }
-                               break;
-                       case 'as:Update':
-                               if (in_array($object_type, self::CONTENT_TYPES) && !empty($object_id)) {
-                                       return self::updateContent($uid, $object_id, $application, $ldactivity);
-                               }
-                               break;
-                       case 'as:Follow':
-                               if (in_array($object_type, self::ACCOUNT_TYPES) && !empty($object_id)) {
-                                       return self::followAccount($uid, $object_id, $ldactivity);
-                               }
-                               break;
-               }
-               return [];
-       }
-
-       /**
-        * Create a new post or comment
-        *
-        * @param integer $uid
-        * @param array $application
-        * @param array $ldactivity
-        * @return array
-        */
-       private static function createContent(int $uid, array $application, array $ldactivity): array
-       {
-               $object_data = self::processC2SObject($ldactivity['as:object']);
-               $item = Processor::processC2SContent($object_data, $application, $uid);
-               Logger::debug('Got data', ['item' => $item, 'object' => $object_data]);
-
-               $id = Item::insert($item, true);
-               if (!empty($id)) {
-                       $item = Post::selectFirst(['uri-id'], ['id' => $id]);
-                       if (!empty($item['uri-id'])) {
-                               return Transmitter::createActivityFromItem($id);
-                       }
-               }
-               return [];
-       }
-
-       /**
-        * Update an existing post or comment
-        *
-        * @param integer $uid
-        * @param string $object_id
-        * @param array $application
-        * @param array $ldactivity
-        * @return array
-        */
-       private static function updateContent(int $uid, string $object_id, array $application, array $ldactivity):array
-       {
-               $id = Item::fetchByLink($object_id, $uid);
-               $original_post = Post::selectFirst(['uri-id'], ['uid' => $uid, 'origin' => true, 'id' => $id]);
-               if (empty($original_post)) {
-                       Logger::debug('Item not found or does not belong to the user', ['id' => $id, 'uid' => $uid, 'object_id' => $object_id, 'activity' => $ldactivity]);
-                       return [];
-               }
-
-               $object_data = self::processC2SObject($ldactivity['as:object']);
-               $item = Processor::processC2SContent($object_data, $application, $uid);
-               if (empty($item['title']) && empty($item['body'])) {
-                       Logger::debug('Empty body and title', ['id' => $id, 'uid' => $uid, 'object_id' => $object_id, 'activity' => $ldactivity]);
-                       return [];
-               }
-               $post = ['title' => $item['title'], 'body' => $item['body']];
-               Logger::debug('Got data', ['id' => $id, 'uid' => $uid, 'item' => $post]);
-               Item::update($post, ['id' => $id]);
-               Item::updateDisplayCache($original_post['uri-id']);
-
-               return Transmitter::createActivityFromItem($id);
-       }
-
-       /**
-        * Follow a given account
-        * @todo Check the expected return value
-        *
-        * @param integer $uid
-        * @param string $object_id
-        * @param array $ldactivity
-        * @return array
-        */
-       private static function followAccount(int $uid, string $object_id, array $ldactivity): array
-       {
-               return [];
-       }
 }