X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=inline;f=src%2FProtocol%2FDiaspora.php;h=7eae2373a32646e1788f15fa3948b5fb5dddf7c5;hb=da60893590a302bf94dfd86f5586f26509160d34;hp=4d91f8b1c0661946f183676a6e15e567fc1e6c73;hpb=4032ad341832dc6ca86f1aa327e13aa087430e14;p=friendica.git diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 4d91f8b1c0..7eae2373a3 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -1,6 +1,6 @@ author); - if (!rsa_verify($signed_data, $author_signature, $key, "sha256")) { + if (!Crypto::rsaVerify($signed_data, $author_signature, $key, "sha256")) { logger("No valid author signature for author ".$fields->author. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$author_signature, LOGGER_DEBUG); return false; } else { @@ -928,10 +928,12 @@ class Diaspora /** * @brief Get a contact id for a given handle * + * @todo Move to Friendica\Model\Contact + * * @param int $uid The user id * @param string $handle The handle in the format user@domain.tld * - * @return The contact id + * @return int Contact id */ private static function contactByHandle($uid, $handle) { @@ -993,16 +995,18 @@ class Diaspora * That makes us friends. * Normally this should have handled by getting a request - but this could get lost */ - if ($contact["rel"] == CONTACT_IS_FOLLOWER && in_array($importer["page-flags"], array(PAGE_FREELOVE))) { - dba::update( - 'contact', - array('rel' => CONTACT_IS_FRIEND, 'writable' => true), - array('id' => $contact["id"], 'uid' => $contact["uid"]) - ); - - $contact["rel"] = CONTACT_IS_FRIEND; - logger("defining user ".$contact["nick"]." as friend"); - } + // It is deactivated by now, due to side effects. See issue https://github.com/friendica/friendica/pull/4033 + // It is not removed by now. Possibly the code is needed? + //if (!$is_comment && $contact["rel"] == CONTACT_IS_FOLLOWER && in_array($importer["page-flags"], array(PAGE_FREELOVE))) { + // dba::update( + // 'contact', + // array('rel' => CONTACT_IS_FRIEND, 'writable' => true), + // array('id' => $contact["id"], 'uid' => $contact["uid"]) + // ); + // + // $contact["rel"] = CONTACT_IS_FRIEND; + // logger("defining user ".$contact["nick"]." as friend"); + //} // We don't seem to like that person if ($contact["blocked"] || $contact["readonly"] || $contact["archive"]) { @@ -1090,7 +1094,7 @@ class Diaspora preg_replace_callback( $expression, function ($match) use ($item) { - return self::fetchGuidSub($match, $item); + self::fetchGuidSub($match, $item); }, $item["body"] ); @@ -1098,7 +1102,7 @@ class Diaspora preg_replace_callback( "&\[url=/posts/([^\[\]]*)\](.*)\[\/url\]&Usi", function ($match) use ($item) { - return self::fetchGuidSub($match, $item); + self::fetchGuidSub($match, $item); }, $item["body"] ); @@ -1111,7 +1115,7 @@ class Diaspora * @param string $body The item body to replace links from * @param string $author_link The author link for missing local contact fallback * - * @return the replaced string + * @return string the replaced string */ public static function replacePeopleGuid($body, $author_link) { @@ -1340,10 +1344,6 @@ class Diaspora if ($r) { $cid = $r[0]["id"]; $network = $r[0]["network"]; - - // We are receiving content from a user that possibly is about to be terminated - // This means the user is vital, so we remove a possible termination date. - Contact::unmarkForArchival($r[0]); } else { $cid = $contact["id"]; $network = NETWORK_DIASPORA; @@ -1433,7 +1433,7 @@ class Diaspora // Check signature $signed_text = 'AccountMigration:'.$old_handle.':'.$new_handle; $key = self::key($old_handle); - if (!rsa_verify($signed_text, $signature, $key, "sha256")) { + if (!Crypto::rsaVerify($signed_text, $signature, $key, "sha256")) { logger('No valid signature for migration.'); return false; } @@ -2015,7 +2015,7 @@ class Diaspora // like on comments have the comment as parent. So we need to fetch the toplevel parent if ($parent_item["id"] != $parent_item["parent"]) { - $toplevel = dba::select('item', array('origin'), array('id' => $parent_item["parent"]), array('limit' => 1)); + $toplevel = dba::selectOne('item', ['origin'], ['id' => $parent_item["parent"]]); $origin = $toplevel["origin"]; } else { $origin = $parent_item["origin"]; @@ -2211,7 +2211,7 @@ class Diaspora $image_url = "http://".$handle_parts[1].$image_url; } - update_contact_avatar($image_url, $importer["uid"], $contact["id"]); + Contact::updateAvatar($image_url, $importer["uid"], $contact["id"]); // Generic birthday. We don't know the timezone. The year is irrelevant. @@ -2250,9 +2250,9 @@ class Diaspora "addr" => $author, "nick" => $nick, "keywords" => $keywords, "hide" => !$searchable, "nsfw" => $nsfw); - $gcid = GlobalContact::update($gcontact); + $gcid = GContact::update($gcontact); - GlobalContact::link($gcid, $importer["uid"], $contact["id"]); + GContact::link($gcid, $importer["uid"], $contact["id"]); logger("Profile of contact ".$contact["id"]." stored for user ".$importer["uid"], LOGGER_DEBUG); @@ -2311,16 +2311,18 @@ class Diaspora $A = "[url=".$self[0]["url"]."]".$self[0]["name"]."[/url]"; $B = "[url=".$contact["url"]."]".$contact["name"]."[/url]"; $BPhoto = "[url=".$contact["url"]."][img]".$contact["thumb"]."[/img][/url]"; - $arr["body"] = sprintf(t("%1$s is now friends with %2$s"), $A, $B)."\n\n\n".$Bphoto; + $arr["body"] = sprintf(t('%1$s is now friends with %2$s'), $A, $B)."\n\n\n".$BPhoto; $arr["object"] = self::constructNewFriendObject($contact); $arr["last-child"] = 1; - $arr["allow_cid"] = $user[0]["allow_cid"]; - $arr["allow_gid"] = $user[0]["allow_gid"]; - $arr["deny_cid"] = $user[0]["deny_cid"]; - $arr["deny_gid"] = $user[0]["deny_gid"]; + $user = dba::selectOne('user', ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid'], ['uid' => $importer["uid"]]); + + $arr["allow_cid"] = $user["allow_cid"]; + $arr["allow_gid"] = $user["allow_gid"]; + $arr["deny_cid"] = $user["deny_cid"]; + $arr["deny_gid"] = $user["deny_gid"]; $i = item_store($arr); if ($i) { @@ -2465,13 +2467,9 @@ class Diaspora logger("Author ".$author." was added as contact number ".$contact_record["id"].".", LOGGER_DEBUG); - $def_gid = get_default_group($importer['uid'], $ret["network"]); + Group::addMember(User::getDefaultGroup($importer['uid'], $ret["network"]), $contact_record['id']); - if (intval($def_gid)) { - group_add_member($importer["uid"], "", $contact_record["id"], $def_gid); - } - - update_contact_avatar($ret["photo"], $importer['uid'], $contact_record["id"], true); + Contact::updateAvatar($ret["photo"], $importer['uid'], $contact_record["id"], true); if ($importer["page-flags"] == PAGE_NORMAL) { logger("Sending intra message for author ".$author.".", LOGGER_DEBUG); @@ -2494,7 +2492,7 @@ class Diaspora logger("Does an automatic friend approval for author ".$author.".", LOGGER_DEBUG); - update_contact_avatar($contact_record["photo"], $importer["uid"], $contact_record["id"]); + Contact::updateAvatar($contact_record["photo"], $importer["uid"], $contact_record["id"]); // technically they are sharing with us (CONTACT_IS_SHARING), // but if our page-type is PAGE_COMMUNITY or PAGE_SOAPBOX @@ -2691,6 +2689,8 @@ class Diaspora self::fetchGuid($datarray); $message_id = item_store($datarray); + self::sendParticipation($contact, $datarray); + if ($message_id) { logger("Stored reshare ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); return true; @@ -2741,7 +2741,7 @@ class Diaspora while ($item = dba::fetch($r)) { // Fetch the parent item - $parent = dba::select('item', array('author-link', 'origin'), array('id' => $item["parent"]), array('limit' => 1)); + $parent = dba::selectOne('item', ['author-link', 'origin'], ['id' => $item["parent"]]); // Only delete it if the parent author really fits if (!link_compare($parent["author-link"], $contact["url"]) && !link_compare($item["author-link"], $contact["url"])) { @@ -2929,6 +2929,8 @@ class Diaspora self::fetchGuid($datarray); $message_id = item_store($datarray); + self::sendParticipation($contact, $datarray); + if ($message_id) { logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); return true; @@ -3031,7 +3033,7 @@ class Diaspora $user['uprvkey'] = $user['prvkey']; } - $signature = rsa_sign($signable_data, $user["uprvkey"]); + $signature = Crypto::rsaSign($signable_data, $user["uprvkey"]); $sig = base64url_encode($signature); $xmldata = array("me:env" => array("me:data" => $data, @@ -3087,7 +3089,7 @@ class Diaspora $signed_text = implode(";", $sigmsg); - return base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256")); + return base64_encode(Crypto::rsaSign($signed_text, $owner["uprvkey"], "sha256")); } /** @@ -3112,7 +3114,15 @@ class Diaspora } $logid = random_string(4); - $dest_url = (($public_batch) ? $contact["batch"] : $contact["notify"]); + $dest_url = ($public_batch ? $contact["batch"] : $contact["notify"]); + + // Fetch the fcontact entry when there is missing data + // Will possibly happen when data is transmitted to a DFRN contact + if (empty($dest_url) && !empty($contact['addr'])) { + $fcontact = self::personByHandle($contact['addr']); + $dest_url = ($public_batch ? $fcontact["batch"] : $fcontact["notify"]); + } + if (!$dest_url) { logger("no url for contact: ".$contact["id"]." batch mode =".$public_batch); return 0; @@ -3213,11 +3223,59 @@ class Diaspora $return_code = self::transmit($owner, $contact, $envelope, $public_batch, false, $guid); } - logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG); + logger("guid: ".$guid." result ".$return_code, LOGGER_DEBUG); return $return_code; } + /** + * @brief sends a participation (Used to get all further updates) + * + * @param array $contact Target of the communication + * @param array $item Item array + * + * @return int The result of the transmission + */ + private static function sendParticipation($contact, $item) + { + // Don't send notifications for private postings + if ($item['private']) { + return; + } + + $cachekey = "diaspora:sendParticipation:".$item['guid']; + + $result = Cache::get($cachekey); + if (!is_null($result)) { + return; + } + + // Fetch some user id to have a valid handle to transmit the participation. + // In fact it doesn't matter which user sends this - but it is needed by the protocol. + // If the item belongs to a user, we take this user id. + if ($item['uid'] == 0) { + $condition = ['verified' => true, 'blocked' => false, 'account_removed' => false, 'account_expired' => false]; + $first_user = dba::selectOne('user', ['uid'], $condition); + $owner = User::getOwnerDataById($first_user['uid']); + } else { + $owner = User::getOwnerDataById($item['uid']); + } + + $author = self::myHandle($owner); + + $message = array("author" => $author, + "guid" => get_guid(32), + "parent_type" => "Post", + "parent_guid" => $item["guid"]); + + logger("Send participation for ".$item["guid"]." by ".$author, LOGGER_DEBUG); + + // It doesn't matter what we store, we only want to avoid sending repeated notifications for the same item + Cache::set($cachekey, $item["guid"], CACHE_QUARTER_HOUR); + + return self::buildAndTransmit($owner, $contact, "participation", $message); + } + /** * @brief sends an account migration * @@ -3233,7 +3291,7 @@ class Diaspora $profile = self::createProfileData($uid); $signed_text = 'AccountMigration:'.$old_handle.':'.$profile['author']; - $signature = base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256")); + $signature = base64_encode(Crypto::rsaSign($signed_text, $owner["uprvkey"], "sha256")); $message = array("author" => $old_handle, "profile" => $profile, @@ -3966,6 +4024,62 @@ class Diaspora return self::buildAndTransmit($owner, $contact, $type, $message, false, $item["guid"]); } + /** + * @brief Split a name into first name and last name + * + * @param string $name The name + * + * @return array The array with "first" and "last" + */ + public static function splitName($name) { + $name = trim($name); + + // Is the name longer than 64 characters? Then cut the rest of it. + if (strlen($name) > 64) { + if ((strpos($name, ' ') <= 64) && (strpos($name, ' ') !== false)) { + $name = trim(substr($name, 0, strrpos(substr($name, 0, 65), ' '))); + } else { + $name = substr($name, 0, 64); + } + } + + // Take the first word as first name + $first = ((strpos($name, ' ') ? trim(substr($name, 0, strpos($name, ' '))) : $name)); + $last = (($first === $name) ? '' : trim(substr($name, strlen($first)))); + if ((strlen($first) < 32) && (strlen($last) < 32)) { + return ['first' => $first, 'last' => $last]; + } + + // Take the last word as last name + $first = ((strrpos($name, ' ') ? trim(substr($name, 0, strrpos($name, ' '))) : $name)); + $last = (($first === $name) ? '' : trim(substr($name, strlen($first)))); + + if ((strlen($first) < 32) && (strlen($last) < 32)) { + return ['first' => $first, 'last' => $last]; + } + + // Take the first 32 characters if there is no space in the first 32 characters + if ((strpos($name, ' ') > 32) || (strpos($name, ' ') === false)) { + $first = substr($name, 0, 32); + $last = substr($name, 32); + return ['first' => $first, 'last' => $last]; + } + + $first = trim(substr($name, 0, strrpos(substr($name, 0, 33), ' '))); + $last = (($first === $name) ? '' : trim(substr($name, strlen($first)))); + + // Check if the last name is longer than 32 characters + if (strlen($last) > 32) { + if (strpos($last, ' ') <= 32) { + $last = trim(substr($last, 0, strrpos(substr($last, 0, 33), ' '))); + } else { + $last = substr($last, 0, 32); + } + } + + return ['first' => $first, 'last' => $last]; + } + /** * @brief Create profile data * @@ -3989,11 +4103,12 @@ class Diaspora } $profile = $r[0]; - $handle = $profile["addr"]; - $first = ((strpos($profile['name'], ' ') - ? trim(substr($profile['name'], 0, strpos($profile['name'], ' '))) : $profile['name'])); - $last = (($first === $profile['name']) ? '' : trim(substr($profile['name'], strlen($first)))); + + $split_name = self::splitName($profile['name']); + $first = $split_name['first']; + $last = $split_name['last']; + $large = System::baseUrl().'/photo/custom/300/'.$profile['uid'].'.jpg'; $medium = System::baseUrl().'/photo/custom/100/'.$profile['uid'].'.jpg'; $small = System::baseUrl().'/photo/custom/50/' .$profile['uid'].'.jpg'; @@ -4054,6 +4169,11 @@ class Diaspora return; } + $owner = User::getOwnerDataById($uid); + if (!$owner) { + return; + } + if (!$recips) { $recips = q( "SELECT `id`,`name`,`network`,`pubkey`,`notify` FROM `contact` WHERE `network` = '%s' @@ -4072,7 +4192,7 @@ class Diaspora foreach ($recips as $recip) { logger("Send updated profile data for user ".$uid." to contact ".$recip["id"], LOGGER_DEBUG); - self::buildAndTransmit($profile, $recip, "profile", $message, false, "", true); + self::buildAndTransmit($owner, $recip, "profile", $message, false, "", true); } }