APContact::unmarkForArchival($apcontact);
}
+ $sig_contact = HTTPSignature::getKeyIdContact($header);
+ if (APContact::isRelay($sig_contact)) {
+ Logger::info('Message from a relay', ['url' => $sig_contact['url']]);
+ self::processRelayPost($ldactivity, $sig_contact['url']);
+ return;
+ }
+
$http_signer = HTTPSignature::getSigner($body, $header);
if ($http_signer === false) {
- Logger::warning('Invalid HTTP signature, message will be discarded.');
- return;
+ Logger::notice('Invalid HTTP signature, message will not be trusted.', ['uid' => $uid, 'actor' => $actor, 'header' => $header, 'body' => $body]);
+ $signer = [];
} elseif (empty($http_signer)) {
Logger::info('Signer is a tombstone. The message will be discarded, the signer account is deleted.');
return;
} else {
Logger::info('Valid HTTP signature', ['signer' => $http_signer]);
+ $signer = [$http_signer];
}
- $signer = [$http_signer];
-
Logger::info('Message for user ' . $uid . ' is from actor ' . $actor);
- if (LDSignature::isSigned($activity)) {
+ if ($http_signer === false) {
+ $trust_source = false;
+ } elseif (LDSignature::isSigned($activity)) {
$ld_signer = LDSignature::getSigner($activity);
if (empty($ld_signer)) {
Logger::info('Invalid JSON-LD signature from ' . $actor);
{
$type = JsonLD::fetchElement($activity, '@type');
if (!$type) {
- Logger::info('Empty type', ['activity' => $activity, 'actor' => $actor]);
+ Logger::notice('Empty type', ['activity' => $activity, 'actor' => $actor]);
return;
}
- if ($type != 'as:Announce') {
- Logger::info('Not an announcement', ['activity' => $activity, 'actor' => $actor]);
- return;
- }
+ $object_type = JsonLD::fetchElement($activity, 'as:object', '@type') ?? '';
$object_id = JsonLD::fetchElement($activity, 'as:object', '@id');
if (empty($object_id)) {
- Logger::info('No object id found', ['activity' => $activity, 'actor' => $actor]);
+ Logger::notice('No object id found', ['type' => $type, 'object_type' => $object_type, 'actor' => $actor, 'activity' => $activity]);
+ return;
+ }
+
+ $handle = ($type == 'as:Announce');
+
+ if (!$handle && in_array($type, ['as:Create', 'as:Update'])) {
+ $handle = in_array($object_type, self::CONTENT_TYPES);
+ }
+
+ if (!$handle) {
+ $trust_source = false;
+ $object_data = self::prepareObjectData($activity, 0, false, $trust_source);
+
+ if (!$trust_source) {
+ Logger::notice('Activity trust could not be achieved.', ['type' => $type, 'object_type' => $object_type, 'object_id' => $object_id, 'actor' => $actor, 'activity' => $activity]);
+ return;
+ }
+
+ if (empty($object_data)) {
+ Logger::notice('No object data found', ['type' => $type, 'object_type' => $object_type, 'object_id' => $object_id, 'actor' => $actor, 'activity' => $activity]);
+ return;
+ }
+
+ if (self::routeActivities($object_data, $type, true)) {
+ Logger::debug('Handled activity', ['type' => $type, 'object_type' => $object_type, 'object_id' => $object_id, 'actor' => $actor]);
+ } else {
+ Logger::info('Unhandled activity', ['type' => $type, 'object_type' => $object_type, 'object_id' => $object_id, 'actor' => $actor, 'activity' => $activity]);
+ }
return;
}
return;
}
- Logger::info('Got relayed message id', ['id' => $object_id, 'actor' => $actor]);
+ Logger::debug('Got relayed message id', ['id' => $object_id, 'actor' => $actor]);
$item_id = Item::searchByLink($object_id);
if ($item_id) {
// Fetch the activity on Lemmy "Announce" messages (announces of activities)
if (($type == 'as:Announce') && in_array($object_type, array_merge(self::ACTIVITY_TYPES, ['as:Delete', 'as:Undo', 'as:Update']))) {
+ Logger::debug('Fetch announced activity', ['object' => $object_id]);
$data = Processor::fetchCachedActivity($object_id, $fetch_uid);
if (!empty($data)) {
$type = $object_type;
// }
// }
- Logger::info('Processing ' . $object_data['type'] . ' ' . $object_data['object_type'] . ' ' . $object_data['id']);
+ $account = Contact::selectFirstAccount(['platform'], ['nurl' => Strings::normaliseLink($actor)]);
+ $platform = $account['platform'] ?? '';
+
+ Logger::info('Processing', ['type' => $object_data['type'], 'object_type' => $object_data['object_type'], 'id' => $object_data['id'], 'actor' => $actor, 'platform' => $platform]);
return $object_data;
}
// Lemmy is announcing activities.
// We are changing the announces into regular activities.
if (($type == 'as:Announce') && in_array($object_data['type'] ?? '', array_merge(self::ACTIVITY_TYPES, ['as:Delete', 'as:Undo', 'as:Update']))) {
+ Logger::debug('Change type of announce to activity', ['type' => $object_data['type']]);
$type = $object_data['type'];
}
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']]);
return false;
}
$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']]);
Queue::remove($object_data);
$announce_object_data = self::processObject($activity);
$announce_object_data['name'] = $type;
$announce_object_data['author'] = $actor;
- $announce_object_data['object_id'] = $object_data['object_id'];
+ $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'];
case 'as:Accept':
if ($object_data['object_type'] == 'as:Follow') {
- ActivityPub\Processor::acceptFollowUser($object_data);
+ if (!empty($object_data['object_actor'])) {
+ ActivityPub\Processor::acceptFollowUser($object_data);
+ } else {
+ Logger::notice('Unhandled "accept follow" message.', ['object_data' => $object_data]);
+ }
} elseif (in_array($object_data['object_type'], self::CONTENT_TYPES)) {
ActivityPub\Processor::createActivity($object_data, Activity::ATTEND);
} else {
} elseif (($object_data['object_type'] == 'as:Block') &&
in_array($object_data['object_object_type'], self::ACCOUNT_TYPES)) {
ActivityPub\Processor::unblockAccount($object_data);
- } elseif (in_array($object_data['object_type'], array_merge(self::ACTIVITY_TYPES, ['as:Announce'])) &&
- in_array($object_data['object_object_type'], array_merge(['as:Tombstone'], self::CONTENT_TYPES))) {
- ActivityPub\Processor::undoActivity($object_data);
} elseif (in_array($object_data['object_type'], array_merge(self::ACTIVITY_TYPES, ['as:Announce', 'as:Create', ''])) &&
empty($object_data['object_object_type'])) {
// We cannot detect the target object. So we can ignore it.
Queue::remove($object_data);
+ } elseif (in_array($object_data['object_type'], array_merge(self::ACTIVITY_TYPES, ['as:Announce'])) &&
+ in_array($object_data['object_object_type'], array_merge(['as:Tombstone'], self::CONTENT_TYPES))) {
+ ActivityPub\Processor::undoActivity($object_data);
} elseif (in_array($object_data['object_type'], ['as:Create']) &&
in_array($object_data['object_object_type'], ['pt:CacheFile'])) {
// Unhandled Peertube activity
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
+ // 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];
+ $receivers[-1] = ['uid' => -1, 'type' => self::TARGET_GLOBAL];
+ Logger::notice('Post from "birdsitelive" is set to "unlisted"', ['id' => JsonLD::fetchElement($activity, '@id')]);
+ } elseif (empty($receivers)) {
+ Logger::notice('Post has got no receivers', ['fetch_unlisted' => $fetch_unlisted, 'actor' => $actor, 'id' => JsonLD::fetchElement($activity, '@id'), 'type' => JsonLD::fetchElement($activity, '@type')]);
+ }
+
return $receivers;
}
$object_data['diaspora:comment'] = JsonLD::fetchElement($object, 'diaspora:comment', '@value');
$object_data['diaspora:like'] = JsonLD::fetchElement($object, 'diaspora:like', '@value');
$object_data['actor'] = $object_data['author'] = $actor;
- $object_data['context'] = JsonLD::fetchElement($object, 'as:context', '@id');
- $object_data['conversation'] = JsonLD::fetchElement($object, 'ostatus:conversation', '@id');
+ $element = JsonLD::fetchElement($object, 'as:context', '@id');
+ $object_data['context'] = $element != './' ? $element : null;
+ $element = JsonLD::fetchElement($object, 'ostatus:conversation', '@id');
+ $object_data['conversation'] = $element != './' ? $element : null;
$object_data['sensitive'] = JsonLD::fetchElement($object, 'as:sensitive');
$object_data['name'] = JsonLD::fetchElement($object, 'as:name', '@value');
$object_data['summary'] = JsonLD::fetchElement($object, 'as:summary', '@value');
$object_data['attachments'] = array_merge($object_data['attachments'], self::processAttachmentUrls($object['as:url'] ?? []));
}
+ // Support for quoted posts (Pleroma, Fedibird and Misskey)
+ $object_data['quote-url'] = JsonLD::fetchElement($object, 'as:quoteUrl', '@value');
+ if (empty($object_data['quote-url'])) {
+ $object_data['quote-url'] = JsonLD::fetchElement($object, 'fedibird:quoteUri', '@value');
+ }
+ if (empty($object_data['quote-url'])) {
+ $object_data['quote-url'] = JsonLD::fetchElement($object, 'misskey:_misskey_quote', '@value');
+ }
+
+ // Misskey adds some data to the standard "content" value for quoted posts for backwards compatibility.
+ // Their own "_misskey_content" value does then contain the content without this extra data.
+ if (!empty($object_data['quote-url'])) {
+ $misskey_content = JsonLD::fetchElement($object, 'misskey:_misskey_content', '@value');
+ if (!empty($misskey_content)) {
+ $object_data['content'] = $misskey_content;
+ }
+ }
+
// For page types we expect that the alternate url posts to some page.
// So we add this to the attachments if it differs from the id.
// Currently only Lemmy is using the page type.