X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FProtocol%2FDiaspora.php;h=14c8df1a7815c8867e71373771e77f669c2d3317;hb=890d1057d2d962f477aa6d1ddacab9b9963ce0fd;hp=7ab41eb52b08ea6bd1b2d9bdbf41e442df4b5f65;hpb=dc5624b0b624e01ee3778960840a3c1c59da1198;p=friendica.git diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 7ab41eb52b..14c8df1a78 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -76,9 +76,9 @@ class Diaspora return $contacts; } - $items = Item::select(['author-id', 'author-link', 'parent-author-link', 'parent-guid', 'guid'], + $items = Post::select(['author-id', 'author-link', 'parent-author-link', 'parent-guid', 'guid'], ['parent' => $item['parent'], 'gravity' => [GRAVITY_COMMENT, GRAVITY_ACTIVITY]]); - while ($item = DBA::fetch($items)) { + while ($item = Post::fetch($items)) { $contact = DBA::selectFirst('contact', ['id', 'url', 'name', 'protocol', 'batch', 'network'], ['id' => $item['author-id']]); if (!DBA::isResult($contact) || empty($contact['batch']) || @@ -537,7 +537,7 @@ class Diaspora return self::receiveConversation($importer, $msg, $fields); case "like": - return self::receiveLike($importer, $sender, $fields); + return self::receiveLike($importer, $sender, $fields, $fetched); case "message": if (!$private) { @@ -551,7 +551,7 @@ class Diaspora Logger::log('Message with type ' . $type . ' is not private, quitting.'); return false; } - return self::receiveParticipation($importer, $fields); + return self::receiveParticipation($importer, $fields, $fetched); case "photo": // Not implemented return self::receivePhoto($importer, $fields); @@ -567,7 +567,7 @@ class Diaspora return self::receiveProfile($importer, $fields); case "reshare": - return self::receiveReshare($importer, $fields, $msg["message"]); + return self::receiveReshare($importer, $fields, $msg["message"], $fetched); case "retraction": return self::receiveRetraction($importer, $sender, $fields); @@ -931,7 +931,7 @@ class Diaspora */ private static function messageExists($uid, $guid) { - $item = Item::selectFirst(['id'], ['uid' => $uid, 'guid' => $guid]); + $item = Post::selectFirst(['id'], ['uid' => $uid, 'guid' => $guid]); if (DBA::isResult($item)) { Logger::log("message ".$guid." already exists for user ".$uid); return $item["id"]; @@ -1151,7 +1151,7 @@ class Diaspora $guid = urldecode($matches[2]); - $item = Item::selectFirst(['id'], ['guid' => $guid, 'uid' => $uid]); + $item = Post::selectFirst(['id'], ['guid' => $guid, 'uid' => $uid]); if (DBA::isResult($item)) { Logger::info('Found', ['id' => $item['id']]); return $item['id']; @@ -1161,7 +1161,7 @@ class Diaspora $ret = self::storeByGuid($guid, $matches[1], $uid); Logger::info('Result', ['ret' => $ret]); - $item = Item::selectFirst(['id'], ['guid' => $guid, 'uid' => $uid]); + $item = Post::selectFirst(['id'], ['guid' => $guid, 'uid' => $uid]); if (DBA::isResult($item)) { Logger::info('Found', ['id' => $item['id']]); return $item['id']; @@ -1188,7 +1188,7 @@ class Diaspora 'author-name', 'author-link', 'author-avatar', 'gravity', 'owner-name', 'owner-link', 'owner-avatar']; $condition = ['uid' => $uid, 'guid' => $guid]; - $item = Item::selectFirst($fields, $condition); + $item = Post::selectFirst($fields, $condition); if (!DBA::isResult($item)) { $person = FContact::getByURL($author); @@ -1202,7 +1202,7 @@ class Diaspora if ($result) { Logger::log("Fetched missing item ".$guid." - result: ".$result, Logger::DEBUG); - $item = Item::selectFirst($fields, $condition); + $item = Post::selectFirst($fields, $condition); } } @@ -1265,7 +1265,7 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function plink($addr, $guid, $parent_guid = '') + private static function plink(string $addr, string $guid, string $parent_guid = '') { $contact = Contact::getByURL($addr); if (empty($contact)) { @@ -1410,7 +1410,7 @@ class Diaspora */ private static function getUriFromGuid($author, $guid, $onlyfound = false) { - $item = Item::selectFirst(['uri'], ['guid' => $guid]); + $item = Post::selectFirst(['uri'], ['guid' => $guid]); if (DBA::isResult($item)) { return $item["uri"]; } elseif (!$onlyfound) { @@ -1426,25 +1426,6 @@ class Diaspora return ""; } - /** - * Fetch the guid from our database with a given uri - * - * @param string $uri Message uri - * @param string $uid Author handle - * - * @return string The post guid - * @throws \Exception - */ - private static function getGuidFromUri($uri, $uid) - { - $item = Item::selectFirst(['guid'], ['uri' => $uri, 'uid' => $uid]); - if (DBA::isResult($item)) { - return $item["guid"]; - } else { - return false; - } - } - /** * Store the mentions in the tag table * @@ -1570,6 +1551,7 @@ class Diaspora $datarray["protocol"] = Conversation::PARCEL_DIASPORA; $datarray["source"] = $xml; + $datarray["direction"] = $fetched ? Conversation::PULL : Conversation::PUSH; $datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at; @@ -1589,6 +1571,11 @@ class Diaspora $datarray['diaspora_signed_text'] = json_encode($data); } + if (Item::isTooOld($datarray)) { + Logger::info('Comment is too old', ['created' => $datarray['created'], 'uid' => $datarray['uid'], 'guid' => $datarray['guid']]); + return false; + } + $message_id = Item::insert($datarray); if ($message_id <= 0) { @@ -1735,7 +1722,7 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function receiveLike(array $importer, $sender, $data) + private static function receiveLike(array $importer, $sender, $data, bool $fetched) { $author = Strings::escapeTags(XML::unescape($data->author)); $guid = Strings::escapeTags(XML::unescape($data->guid)); @@ -1784,6 +1771,7 @@ class Diaspora $datarray = []; $datarray["protocol"] = Conversation::PARCEL_DIASPORA; + $datarray["direction"] = $fetched ? Conversation::PULL : Conversation::PUSH; $datarray["uid"] = $importer["uid"]; $datarray["contact-id"] = $author_contact["cid"]; @@ -1808,7 +1796,7 @@ class Diaspora // like on comments have the comment as parent. So we need to fetch the toplevel parent if ($toplevel_parent_item['gravity'] != GRAVITY_PARENT) { - $toplevel = Item::selectFirst(['origin'], ['id' => $toplevel_parent_item['parent']]); + $toplevel = Post::selectFirst(['origin'], ['id' => $toplevel_parent_item['parent']]); $origin = $toplevel["origin"]; } else { $origin = $toplevel_parent_item["origin"]; @@ -1820,6 +1808,11 @@ class Diaspora $datarray['diaspora_signed_text'] = json_encode($data); } + if (Item::isTooOld($datarray)) { + Logger::info('Like is too old', ['created' => $datarray['created'], 'uid' => $datarray['uid'], 'guid' => $datarray['guid']]); + return false; + } + $message_id = Item::insert($datarray); if ($message_id <= 0) { @@ -1907,7 +1900,7 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function receiveParticipation(array $importer, $data) + private static function receiveParticipation(array $importer, $data, bool $fetched) { $author = strtolower(Strings::escapeTags(XML::unescape($data->author))); $guid = Strings::escapeTags(XML::unescape($data->guid)); @@ -1948,6 +1941,7 @@ class Diaspora $datarray = []; $datarray["protocol"] = Conversation::PARCEL_DIASPORA; + $datarray["direction"] = $fetched ? Conversation::PULL : Conversation::PUSH; $datarray["uid"] = $importer["uid"]; $datarray["contact-id"] = $author_contact["cid"]; @@ -1970,14 +1964,19 @@ class Diaspora // Diaspora doesn't provide a date for a participation $datarray["changed"] = $datarray["created"] = $datarray["edited"] = DateTimeFormat::utcNow(); + if (Item::isTooOld($datarray)) { + Logger::info('Participation is too old', ['created' => $datarray['created'], 'uid' => $datarray['uid'], 'guid' => $datarray['guid']]); + return false; + } + $message_id = Item::insert($datarray); Logger::info('Participation stored', ['id' => $message_id, 'guid' => $guid, 'parent_guid' => $parent_guid, 'author' => $author]); // Send all existing comments and likes to the requesting server - $comments = Item::select(['id', 'uri-id', 'parent-author-network', 'author-network', 'verb'], + $comments = Post::select(['id', 'uri-id', 'parent-author-network', 'author-network', 'verb'], ['parent' => $toplevel_parent_item['id'], 'gravity' => [GRAVITY_COMMENT, GRAVITY_ACTIVITY]]); - while ($comment = Item::fetch($comments)) { + while ($comment = Post::fetch($comments)) { if (in_array($comment['verb'], [Activity::FOLLOW, Activity::TAG])) { Logger::info('participation messages are not relayed', ['item' => $comment['id']]); continue; @@ -2267,7 +2266,7 @@ class Diaspora $fields = ['body', 'title', 'app', 'created', 'object-type', 'uri', 'guid', 'author-name', 'author-link', 'author-avatar', 'plink', 'uri-id']; $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => [Item::PUBLIC, Item::UNLISTED]]; - $item = Item::selectFirst($fields, $condition); + $item = Post::selectFirst($fields, $condition); if (DBA::isResult($item)) { Logger::log("reshared message ".$guid." already exists on system."); @@ -2311,7 +2310,7 @@ class Diaspora $fields = ['body', 'title', 'app', 'created', 'object-type', 'uri', 'guid', 'author-name', 'author-link', 'author-avatar', 'plink', 'uri-id']; $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => [Item::PUBLIC, Item::UNLISTED]]; - $item = Item::selectFirst($fields, $condition); + $item = Post::selectFirst($fields, $condition); if (DBA::isResult($item)) { // If it is a reshared post from another network then reformat to avoid display problems with two share elements @@ -2337,7 +2336,7 @@ class Diaspora */ private static function addReshareActivity($item, $parent_message_id, $guid, $author) { - $parent = Item::selectFirst(['uri', 'guid'], ['id' => $parent_message_id]); + $parent = Post::selectFirst(['uri', 'guid'], ['id' => $parent_message_id]); $datarray = []; @@ -2360,11 +2359,18 @@ class Diaspora $datarray['object-type'] = Activity\ObjectType::NOTE; $datarray['protocol'] = $item['protocol']; + $datarray['source'] = $item['source']; + $datarray['direction'] = $item['direction']; $datarray['plink'] = self::plink($author, $datarray['guid']); $datarray['private'] = $item['private']; $datarray['changed'] = $datarray['created'] = $datarray['edited'] = $item['created']; + if (Item::isTooOld($datarray)) { + Logger::info('Reshare activity is too old', ['created' => $datarray['created'], 'uid' => $datarray['uid'], 'guid' => $datarray['guid']]); + return false; + } + $message_id = Item::insert($datarray); if ($message_id) { @@ -2386,7 +2392,7 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function receiveReshare(array $importer, $data, $xml) + private static function receiveReshare(array $importer, $data, $xml, bool $fetched) { $author = Strings::escapeTags(XML::unescape($data->author)); $guid = Strings::escapeTags(XML::unescape($data->guid)); @@ -2411,6 +2417,10 @@ class Diaspora return false; } + if (empty($original_item['plink'])) { + $original_item['plink'] = self::plink($root_author, $root_guid); + } + $datarray = []; $datarray["uid"] = $importer["uid"]; @@ -2432,6 +2442,7 @@ class Diaspora $datarray["protocol"] = Conversation::PARCEL_DIASPORA; $datarray["source"] = $xml; + $datarray["direction"] = $fetched ? Conversation::PULL : Conversation::PUSH; /// @todo Copy tag data from original post @@ -2462,6 +2473,12 @@ class Diaspora $datarray["object-type"] = $original_item["object-type"]; self::fetchGuid($datarray); + + if (Item::isTooOld($datarray)) { + Logger::info('Reshare is too old', ['created' => $datarray['created'], 'uid' => $datarray['uid'], 'guid' => $datarray['guid']]); + return false; + } + $message_id = Item::insert($datarray); self::sendParticipation($contact, $datarray); @@ -2509,7 +2526,7 @@ class Diaspora } // Fetch items that are about to be deleted - $fields = ['uid', 'id', 'parent', 'author-link', 'file']; + $fields = ['uid', 'id', 'parent', 'author-link', 'uri-id']; // When we receive a public retraction, we delete every item that we find. if ($importer['uid'] == 0) { @@ -2518,20 +2535,20 @@ class Diaspora $condition = ['guid' => $target_guid, 'deleted' => false, 'uid' => $importer['uid']]; } - $r = Item::select($fields, $condition); + $r = Post::select($fields, $condition); if (!DBA::isResult($r)) { Logger::log("Target guid ".$target_guid." was not found on this system for user ".$importer['uid']."."); return false; } - while ($item = Item::fetch($r)) { - if (strstr($item['file'], '[')) { + while ($item = Post::fetch($r)) { + if (DBA::exists('post-category', ['uri-id' => $item['uri-id'], 'uid' => $item['uid'], 'type' => Post\Category::FILE])) { Logger::log("Target guid " . $target_guid . " for user " . $item['uid'] . " is filed. So it won't be deleted.", Logger::DEBUG); continue; } // Fetch the parent item - $parent = Item::selectFirst(['author-link'], ['id' => $item['parent']]); + $parent = Post::selectFirst(['author-link'], ['id' => $item['parent']]); // Only delete it if the parent author really fits if (!Strings::compareLink($parent["author-link"], $contact["url"]) && !Strings::compareLink($item["author-link"], $contact["url"])) { @@ -2543,6 +2560,7 @@ class Diaspora Logger::log("Deleted target ".$target_guid." (".$item["id"].") from user ".$item["uid"]." parent: ".$item['parent'], Logger::DEBUG); } + DBA::close($r); return true; } @@ -2723,6 +2741,7 @@ class Diaspora $datarray["protocol"] = Conversation::PARCEL_DIASPORA; $datarray["source"] = $xml; + $datarray["direction"] = $fetched ? Conversation::PULL : Conversation::PUSH; if ($fetched) { $datarray["post-type"] = Item::PT_FETCHED; @@ -2758,6 +2777,12 @@ class Diaspora } self::fetchGuid($datarray); + + if (Item::isTooOld($datarray)) { + Logger::info('Status is too old', ['created' => $datarray['created'], 'uid' => $datarray['uid'], 'guid' => $datarray['guid']]); + return false; + } + $message_id = Item::insert($datarray); self::sendParticipation($contact, $datarray); @@ -3031,7 +3056,18 @@ class Diaspora $owner['uprvkey'] = $owner['prvkey']; } - $envelope = self::buildMessage($msg, $owner, $contact, $owner['uprvkey'], $contact['pubkey'], $public_batch); + // When sending content to Friendica contacts using the Diaspora protocol + // we have to fetch the public key from the fcontact. + // This is due to the fact that legacy DFRN had unique keys for every contact. + $pubkey = $contact['pubkey']; + if (!empty($contact['addr'])) { + $fcontact = FContact::getByURL($contact['addr']); + if (!empty($fcontact)) { + $pubkey = $fcontact['pubkey']; + } + } + + $envelope = self::buildMessage($msg, $owner, $contact, $owner['uprvkey'], $pubkey, $public_batch); $return_code = self::transmit($owner, $contact, $envelope, $public_batch, $guid); @@ -3209,7 +3245,7 @@ class Diaspora if (!empty($reshared['guid']) && $complete) { $condition = ['guid' => $reshared['guid'], 'network' => [Protocol::DFRN, Protocol::DIASPORA]]; - $item = Item::selectFirst(['contact-id'], $condition); + $item = Post::selectFirst(['contact-id'], $condition); if (DBA::isResult($item)) { $ret = []; $ret["root_handle"] = self::handleFromContact($item["contact-id"]); @@ -3371,7 +3407,6 @@ class Diaspora } if ($item['author-link'] != $item['owner-link']) { - require_once 'mod/share.php'; $body = BBCode::getShareOpeningTag($item['author-name'], $item['author-link'], $item['author-avatar'], $item['plink'], $item['created']) . $body . '[/share]'; } @@ -3487,7 +3522,7 @@ class Diaspora */ private static function constructLike(array $item, array $owner) { - $parent = Item::selectFirst(['guid', 'uri', 'thr-parent'], ['uri' => $item["thr-parent"]]); + $parent = Post::selectFirst(['guid', 'uri', 'thr-parent'], ['uri' => $item["thr-parent"]]); if (!DBA::isResult($parent)) { return false; } @@ -3519,7 +3554,7 @@ class Diaspora */ private static function constructAttend(array $item, array $owner) { - $parent = Item::selectFirst(['guid'], ['uri' => $item['thr-parent']]); + $parent = Post::selectFirst(['guid'], ['uri' => $item['thr-parent']]); if (!DBA::isResult($parent)) { return false; } @@ -3564,7 +3599,7 @@ class Diaspora return $result; } - $toplevel_item = Item::selectFirst(['guid', 'author-id', 'author-link'], ['id' => $item['parent'], 'parent' => $item['parent']]); + $toplevel_item = Post::selectFirst(['guid', 'author-id', 'author-link', 'gravity'], ['id' => $item['parent'], 'parent' => $item['parent']]); if (!DBA::isResult($toplevel_item)) { Logger::error('Missing parent conversation item', ['parent' => $item['parent']]); return false; @@ -3572,7 +3607,7 @@ class Diaspora $thread_parent_item = $toplevel_item; if ($item['thr-parent'] != $item['parent-uri']) { - $thread_parent_item = Item::selectFirst(['guid', 'author-id', 'author-link'], ['uri' => $item['thr-parent'], 'uid' => $item['uid']]); + $thread_parent_item = Post::selectFirst(['guid', 'author-id', 'author-link', 'gravity'], ['uri' => $item['thr-parent'], 'uid' => $item['uid']]); } $body = $item["body"]; @@ -3583,6 +3618,7 @@ class Diaspora // - Implicit mentions are enabled if ( $item['author-id'] != $thread_parent_item['author-id'] + && ($thread_parent_item['gravity'] != GRAVITY_PARENT) && (empty($item['uid']) || !Feature::isEnabled($item['uid'], 'explicit_mentions')) && !DI::config()->get('system', 'disable_implicit_mentions') ) { @@ -3647,51 +3683,6 @@ class Diaspora return self::buildAndTransmit($owner, $contact, $type, $message, $public_batch, $item["guid"]); } - /** - * Creates a message from a signature record entry - * - * @param array $item The item that will be exported - * @return array The message - */ - private static function messageFromSignature(array $item) - { - // Split the signed text - $signed_parts = explode(";", $item['signed_text']); - - if ($item["deleted"]) { - $message = ["author" => $item['signer'], - "target_guid" => $signed_parts[0], - "target_type" => $signed_parts[1]]; - } elseif (in_array($item["verb"], [Activity::LIKE, Activity::DISLIKE])) { - $message = ["author" => $signed_parts[4], - "guid" => $signed_parts[1], - "parent_guid" => $signed_parts[3], - "parent_type" => $signed_parts[2], - "positive" => $signed_parts[0], - "author_signature" => $item['signature'], - "parent_author_signature" => ""]; - } else { - // Remove the comment guid - $guid = array_shift($signed_parts); - - // Remove the parent guid - $parent_guid = array_shift($signed_parts); - - // Remove the handle - $handle = array_pop($signed_parts); - - $message = [ - "author" => $handle, - "guid" => $guid, - "parent_guid" => $parent_guid, - "text" => implode(";", $signed_parts), - "author_signature" => $item['signature'], - "parent_author_signature" => "" - ]; - } - return $message; - } - /** * Relays messages (like, comment, retraction) to other servers if we are the thread owner * @@ -4048,7 +4039,7 @@ class Diaspora return false; } - $parent = Item::selectFirst(['parent-uri'], ['uri' => $item['thr-parent']]); + $parent = Post::selectFirst(['parent-uri'], ['uri' => $item['thr-parent']]); if (!DBA::isResult($parent)) { return; }