diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index d6140535b9..78a7f37b8c 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -1111,6 +1111,10 @@ class Processor } if (!empty($activity['directmessage']) && self::postMail($item)) { + if (!empty($item['source']) && DI::config()->get('debug', 'store_source')) { + Post\Activity::insert($item['uri-id'], $item['source']); + } + continue; } diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index cd48768cc7..e6371a5975 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -436,15 +436,11 @@ class Receiver $object_data['object_id'] = $object_id; - // Test if it is an answer to a mail - if (DBA::exists('mail', ['uri' => $object_data['reply-to-id']])) { + // Test if it is a direct message + if (self::checkForDirectMessage($object_data, $activity)) { $object_data['directmessage'] = true; - } else { - $object_data['directmessage'] = JsonLD::fetchElement($activity, 'litepub:directMessage'); - - if (!empty(JsonLD::fetchElement($activity['as:object'], 'misskey:_misskey_talk'))) { - $object_data = self::setChatData($object_data, $receivers); - } + } elseif (!empty(JsonLD::fetchElement($activity['as:object'], 'misskey:_misskey_talk'))) { + $object_data = self::setChatData($object_data, $receivers); } } 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). @@ -523,6 +519,57 @@ class Receiver return $object_data; } + /** + * Check if the received message is a direct message + * + * @param array $object_data + * @param array $activity + * @return boolean + */ + private static function checkForDirectMessage(array $object_data, array $activity): bool + { + if (DBA::exists('mail', ['uri' => $object_data['reply-to-id']])) { + return true; + } + + if ($object_data['id'] != $object_data['reply-to-id']) { + return false; + } + + if (JsonLD::fetchElement($activity, 'litepub:directMessage')) { + return true; + } + + if (!empty($object_data['attachments'])) { + return false; + } + + if (!empty($object_data['receiver_urls']['as:cc']) || empty($object_data['receiver_urls']['as:to'])) { + return false; + } + + if ((count($object_data['receiver_urls']['as:to']) != 1) || !User::getIdForURL($object_data['receiver_urls']['as:to'][0])) { + return false; + } + + $mentions = 0; + foreach ($object_data['tags'] as $mention) { + if ($mention['type'] != 'Mention') { + continue; + } + if (!User::getIdForURL($mention['href'])) { + return false; + } + ++$mentions; + } + + if ($mentions > 1) { + return false; + } + + return true; + } + private static function setChatData(array $object_data, array $receivers): array { if (count($receivers) != 1) { @@ -682,7 +729,7 @@ class Receiver self::addArrivedId($object_data['object_id']); } - $decouple = DI::config()->get('system', 'decoupled_receiver') && !in_array($completion, [self::COMPLETION_MANUAL, self::COMPLETION_ANNOUNCE]); + $decouple = DI::config()->get('system', 'decoupled_receiver') && !in_array($completion, [self::COMPLETION_MANUAL, self::COMPLETION_ANNOUNCE]) && empty($object_data['directmessage']); 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); diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index 83155bf4f1..0a36f0c5bd 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -1121,19 +1121,17 @@ class Transmitter */ public static function fetchTargetInboxesFromMail(int $mail_id): array { - $mail = DBA::selectFirst('mail', ['uid', 'parent-uri', 'from-url'], ['id' => $mail_id]); + $mail = DBA::selectFirst('mail', ['contact-id'], ['id' => $mail_id]); if (!DBA::isResult($mail)) { return []; } - $reply = DBA::selectFirst('mail', ['from-url'], ['parent-uri' => $mail['parent-uri'], 'reply' => false]); - if (!DBA::isResult($reply)) { - $reply = $mail; + $account = DBA::selectFirst('account-user-view', ['ap-inbox'], ['id' => $mail['contact-id']]); + if (empty($account['ap-inbox'])) { + return []; } - $apcontact = APContact::getByURL($reply['from-url'], false); - - return [$apcontact['inbox'] => [Contact::getIdForURL($reply['from-url'])]]; + return [$account['ap-inbox'] => [$mail['contact-id']]]; } /**