X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FProtocol%2FDiaspora.php;h=23220d04cd0ed2981a3c796f3878f494aac6e9e9;hb=1068091bbe81324fa5e6e5387559d6b711934769;hp=d6f1078f4c7f26a0c252418cd21e1aeae0238093;hpb=5ba6c7717a06842c27fec15508ff8cabb3d9a31b;p=friendica.git diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index d6f1078f4c..23220d04cd 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 { @@ -927,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) { @@ -1091,7 +1094,7 @@ class Diaspora preg_replace_callback( $expression, function ($match) use ($item) { - return self::fetchGuidSub($match, $item); + self::fetchGuidSub($match, $item); }, $item["body"] ); @@ -1099,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"] ); @@ -1112,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) { @@ -1430,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; } @@ -2012,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::selectFirst('item', ['origin'], ['id' => $parent_item["parent"]]); $origin = $toplevel["origin"]; } else { $origin = $parent_item["origin"]; @@ -2308,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::selectFirst('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) { @@ -2462,11 +2467,7 @@ class Diaspora logger("Author ".$author." was added as contact number ".$contact_record["id"].".", LOGGER_DEBUG); - $def_gid = get_default_group($importer['uid'], $ret["network"]); - - if (intval($def_gid)) { - group_add_member($importer["uid"], "", $contact_record["id"], $def_gid); - } + Group::addMember(User::getDefaultGroup($importer['uid'], $ret["network"]), $contact_record['id']); Contact::updateAvatar($ret["photo"], $importer['uid'], $contact_record["id"], true); @@ -2688,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; @@ -2738,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::selectFirst('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"])) { @@ -2926,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; @@ -3028,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, @@ -3084,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")); } /** @@ -3109,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; @@ -3210,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::selectFirst('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 * @@ -3230,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, @@ -3963,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 * @@ -3986,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'; @@ -4051,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' @@ -4069,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); } }