X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FProtocol%2FActivityPub%2FReceiver.php;h=f371eede7fe4b048f611447b0b2a98bbea53df9e;hb=9305821b9d5637a30b0f4c32c4834749992af633;hp=48bfc0c8c855feb2013974bc1cd16d9070067654;hpb=3a74f3364d28297ba957544893d9c721d683dba1;p=friendica.git diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index 48bfc0c8c8..f371eede7f 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -30,9 +30,6 @@ use Friendica\Protocol\ActivityPub; * - Remove * - Undo Block * - Undo Accept (Problem: This could invert a contact accept or an event accept) - * - * General: - * - Possibly using the LD-JSON parser */ class Receiver { @@ -108,30 +105,68 @@ class Receiver $trust_source = false; } - self::processActivity($activity, $ldactivity, $body, $uid, $trust_source); + self::processActivity($ldactivity, $body, $uid, $trust_source); } /** - * + * Fetches the object type for a given object id + * + * @param array $activity + * @param string $object_id Object ID of the the provided object + * + * @return string with object type + */ + private static function fetchObjectType($activity, $object_id) + { + + $object_type = JsonLD::fetchElement($activity['as:object'], '@type'); + if (!empty($object_type)) { + return $object_type; + } + + if (Item::exists(['uri' => $object_id, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]])) { + // We just assume "note" since it doesn't make a difference for the further processing + return 'as:Note'; + } + + $profile = APContact::getByURL($object_id); + if (!empty($profile['type'])) { + return 'as:' . $profile['type']; + } + + $data = ActivityPub::fetchContent($object_id); + if (!empty($data)) { + $object = JsonLD::compact($data); + $type = JsonLD::fetchElement($object, '@type'); + if (!empty($type)) { + return $type; + } + } + + return null; + } + + /** + * Prepare the object array * * @param array $activity * @param integer $uid User ID * @param $trust_source * - * @return + * @return array with object data */ - private static function prepareObjectData($activity, $ldactivity, $uid, &$trust_source) + private static function prepareObjectData($activity, $uid, &$trust_source) { - $actor = JsonLD::fetchElement($ldactivity, 'as:actor'); + $actor = JsonLD::fetchElement($activity, 'as:actor'); if (empty($actor)) { logger('Empty actor', LOGGER_DEBUG); return []; } - $type = JsonLD::fetchElement($ldactivity, '@type'); + $type = JsonLD::fetchElement($activity, '@type'); // Fetch all receivers from to, cc, bto and bcc - $receivers = self::getReceivers($ldactivity, $actor); + $receivers = self::getReceivers($activity, $actor); // When it is a delivery to a personal inbox we add that user to the receivers if (!empty($uid)) { @@ -142,15 +177,20 @@ class Receiver logger('Receivers: ' . json_encode($receivers), LOGGER_DEBUG); - $object_id = JsonLD::fetchElement($ldactivity, 'as:object'); + $object_id = JsonLD::fetchElement($activity, 'as:object'); if (empty($object_id)) { logger('No object found', LOGGER_DEBUG); return []; } + $object_type = self::fetchObjectType($activity, $object_id); + // Fetch the content only on activities where this matters if (in_array($type, ['as:Create', 'as:Announce'])) { - $object_data = self::fetchObject($object_id, $activity['object'], $ldactivity['as:object'], $trust_source); + if ($type == 'as:Announce') { + $trust_source = false; + } + $object_data = self::fetchObject($object_id, $activity['as:object'], $trust_source); if (empty($object_data)) { logger("Object data couldn't be processed", LOGGER_DEBUG); return []; @@ -160,22 +200,28 @@ class Receiver } elseif (in_array($type, ['as:Like', 'as:Dislike'])) { // 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 ech individual array element. - $object_data = self::processObject($ldactivity); + $object_data = self::processObject($activity); $object_data['name'] = $type; - $object_data['author'] = JsonLD::fetchElement($ldactivity, 'as:actor'); - $object_data['object'] = $object_id; + $object_data['author'] = JsonLD::fetchElement($activity, 'as:actor'); + $object_data['object_id'] = $object_id; $object_data['object_type'] = ''; // Since we don't fetch the object, we don't know the type } else { $object_data = []; - $object_data['id'] = JsonLD::fetchElement($ldactivity, '@id'); - $object_data['object'] = $activity['object']; - $object_data['object_type'] = JsonLD::fetchElement($ldactivity, 'as:object', '@type'); + $object_data['id'] = JsonLD::fetchElement($activity, '@id'); + $object_data['object_id'] = JsonLD::fetchElement($activity, 'as:object'); + $object_data['object_actor'] = JsonLD::fetchElement($activity['as:object'], 'as:actor'); + $object_data['object_object'] = JsonLD::fetchElement($activity['as:object'], 'as:object'); + $object_data['object_type'] = JsonLD::fetchElement($activity['as:object'], '@type'); } $object_data = self::addActivityFields($object_data, $activity); - $object_data['type'] = $activity['type']; - $object_data['owner'] = $actor; + if (empty($object_data['object_type'])) { + $object_data['object_type'] = $object_type; + } + + $object_data['type'] = $type; + $object_data['actor'] = $actor; $object_data['receiver'] = array_merge(defaults($object_data, 'receiver', []), $receivers); logger('Processing ' . $object_data['type'] . ' ' . $object_data['object_type'] . ' ' . $object_data['id'], LOGGER_DEBUG); @@ -184,38 +230,34 @@ class Receiver } /** - * + * Processes the activity object * - * @param array $activity - * @param $body - * @param integer $uid User ID - * @param $trust_source + * @param array $activity Array with activity data + * @param string $body + * @param integer $uid User ID + * @param boolean $trust_source Do we trust the source? */ - public static function processActivity($activity, $ldactivity = '', $body = '', $uid = null, $trust_source = false) + public static function processActivity($activity, $body = '', $uid = null, $trust_source = false) { - if (empty($ldactivity)) { - $ldactivity = JsonLD::compact($activity); - } - - $type = JsonLD::fetchElement($ldactivity, '@type'); + $type = JsonLD::fetchElement($activity, '@type'); if (!$type) { logger('Empty type', LOGGER_DEBUG); return; } - if (!JsonLD::fetchElement($ldactivity, 'as:object')) { + if (!JsonLD::fetchElement($activity, 'as:object')) { logger('Empty object', LOGGER_DEBUG); return; } - if (!JsonLD::fetchElement($ldactivity, 'as:actor')) { + if (!JsonLD::fetchElement($activity, 'as:actor')) { logger('Empty actor', LOGGER_DEBUG); return; } // $trust_source is called by reference and is set to true if the content was retrieved successfully - $object_data = self::prepareObjectData($activity, $ldactivity, $uid, $trust_source); + $object_data = self::prepareObjectData($activity, $uid, $trust_source); if (empty($object_data)) { logger('No object data found', LOGGER_DEBUG); return; @@ -226,6 +268,11 @@ class Receiver return; } + // Internal flag for thread completion. See Processor.php + if (!empty($activity['thread-completion'])) { + $object_data['thread-completion'] = $activity['thread-completion']; + } + switch ($type) { case 'as:Create': case 'as:Announce': @@ -436,19 +483,19 @@ class Receiver private static function addActivityFields($object_data, $activity) { if (!empty($activity['published']) && empty($object_data['published'])) { - $object_data['published'] = $activity['published']; + $object_data['published'] = JsonLD::fetchElement($activity, 'published', '@value'); } if (!empty($activity['updated']) && empty($object_data['updated'])) { - $object_data['updated'] = $activity['updated']; + $object_data['updated'] = JsonLD::fetchElement($activity, 'updated', '@value'); } if (!empty($activity['diaspora:guid']) && empty($object_data['diaspora:guid'])) { - $object_data['diaspora:guid'] = $activity['diaspora:guid']; + $object_data['diaspora:guid'] = JsonLD::fetchElement($activity, 'diaspora:guid'); } if (!empty($activity['inReplyTo']) && empty($object_data['parent-uri'])) { - $object_data['parent-uri'] = JsonLD::fetchElement($activity, 'inReplyTo', 'id'); + $object_data['parent-uri'] = JsonLD::fetchElement($activity, 'inReplyTo'); } if (!empty($activity['instrument'])) { @@ -458,58 +505,60 @@ class Receiver } /** - * + * Fetches the object data from external ressources if needed * - * @param $object_id - * @param $object - * @param $trust_source + * @param string $object_id Object ID of the the provided object + * @param array $object The provided object array + * @param boolean $trust_source Do we trust the provided object? * - * @return array with object data + * @return array with trusted and valid object data */ - private static function fetchObject($object_id, $object = [], $ldobject = [], $trust_source = false) + private static function fetchObject($object_id, $object = [], $trust_source = false) { - if (!$trust_source || is_string($object)) { + // By fetching the type we check if the object is complete. + $type = JsonLD::fetchElement($object, '@type'); + + if (!$trust_source || empty($type)) { $data = ActivityPub::fetchContent($object_id); - if (empty($data)) { - logger('Empty content for ' . $object_id . ', check if content is available locally.', LOGGER_DEBUG); - $data = $object_id; - } else { - $ldobject = JsonLD::compact($data); + if (!empty($data)) { + $object = JsonLD::compact($data); logger('Fetched content for ' . $object_id, LOGGER_DEBUG); + } else { + logger('Empty content for ' . $object_id . ', check if content is available locally.', LOGGER_DEBUG); + + $item = Item::selectFirst([], ['uri' => $object_id]); + if (!DBA::isResult($item)) { + logger('Object with url ' . $object_id . ' was not found locally.', LOGGER_DEBUG); + return false; + } + logger('Using already stored item for url ' . $object_id, LOGGER_DEBUG); + $data = ActivityPub\Transmitter::createNote($item); + $object = JsonLD::compact($data); } } else { logger('Using original object for url ' . $object_id, LOGGER_DEBUG); - $data = $object; } - if (is_string($data)) { - $item = Item::selectFirst([], ['uri' => $data]); - if (!DBA::isResult($item)) { - logger('Object with url ' . $data . ' was not found locally.', LOGGER_DEBUG); - return false; - } - logger('Using already stored item for url ' . $object_id, LOGGER_DEBUG); - $data = ActivityPub\Transmitter::createNote($item); - $ldobject = JsonLD::compact($data); - } + $type = JsonLD::fetchElement($object, '@type'); - if (empty($data['type'])) { + if (empty($type)) { logger('Empty type', LOGGER_DEBUG); return false; } - if (in_array($data['type'], ActivityPub::CONTENT_TYPES)) { - return self::processObject($ldobject); + if (in_array($type, self::CONTENT_TYPES)) { + return self::processObject($object); } - if ($data['type'] == 'Announce') { - if (empty($data['object'])) { + if ($type == 'as:Announce') { + $object_id = JsonLD::fetchElement($object, 'object'); + if (empty($object_id)) { return false; } - return self::fetchObject($data['object']); + return self::fetchObject($object_id); } - logger('Unhandled object type: ' . $data['type'], LOGGER_DEBUG); + logger('Unhandled object type: ' . $type, LOGGER_DEBUG); } /** @@ -522,7 +571,16 @@ class Receiver private static function processTags($tags) { $taglist = []; + + if (empty($tags)) { + return []; + } + foreach ($tags as $tag) { + if (empty($tag)) { + continue; + } + $taglist[] = ['type' => str_replace('as:', '', JsonLD::fetchElement($tag, '@type')), 'href' => JsonLD::fetchElement($tag, 'as:href'), 'name' => JsonLD::fetchElement($tag, 'as:name')]; @@ -540,7 +598,16 @@ class Receiver private static function processAttachments($attachments) { $attachlist = []; + + if (empty($attachments)) { + return []; + } + foreach ($attachments as $attachment) { + if (empty($attachment)) { + continue; + } + $attachlist[] = ['type' => str_replace('as:', '', JsonLD::fetchElement($attachment, '@type')), 'mediaType' => JsonLD::fetchElement($attachment, 'as:mediaType'), 'name' => JsonLD::fetchElement($attachment, 'as:name'), @@ -590,7 +657,7 @@ class Receiver $object_data['diaspora:guid'] = JsonLD::fetchElement($object, 'diaspora:guid'); $object_data['diaspora:comment'] = JsonLD::fetchElement($object, 'diaspora:comment'); - $object_data['owner'] = $object_data['author'] = $actor; + $object_data['actor'] = $object_data['author'] = $actor; $object_data['context'] = JsonLD::fetchElement($object, 'as:context'); $object_data['conversation'] = JsonLD::fetchElement($object, 'ostatus:conversation'); $object_data['sensitive'] = JsonLD::fetchElement($object, 'as:sensitive'); @@ -614,7 +681,7 @@ class Receiver } } - $object_data['receiver'] = self::getReceivers($object, $object_data['owner']); + $object_data['receiver'] = self::getReceivers($object, $object_data['actor']); // Common object data: