X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=include%2Fdiaspora.php;h=21081dd6a7250d7e4891984c47889ad633e4b065;hb=4b16de6d8010323cc63cde302b4ee0becb429d3b;hp=fc88c79bf2be203ad9609caf7c7c7bf74ab5e82f;hpb=dbf7c7d9ad697f7951f102c8372e7d65c167de96;p=friendica.git diff --git a/include/diaspora.php b/include/diaspora.php index fc88c79bf2..21081dd6a7 100644 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -8,17 +8,20 @@ * This will change in the future. */ -require_once("include/items.php"); -require_once("include/bb2diaspora.php"); -require_once("include/Scrape.php"); -require_once("include/Contact.php"); -require_once("include/Photo.php"); -require_once("include/socgraph.php"); -require_once("include/group.php"); -require_once("include/xml.php"); -require_once("include/datetime.php"); -require_once("include/queue_fn.php"); -require_once("include/cache.php"); +use Friendica\App; +use Friendica\Core\Config; + +require_once 'include/items.php'; +require_once 'include/bb2diaspora.php'; +require_once 'include/Scrape.php'; +require_once 'include/Contact.php'; +require_once 'include/Photo.php'; +require_once 'include/socgraph.php'; +require_once 'include/group.php'; +require_once 'include/xml.php'; +require_once 'include/datetime.php'; +require_once 'include/queue_fn.php'; +require_once 'include/cache.php'; /** * @brief This class contain functions to create and send Diaspora XML files @@ -43,15 +46,15 @@ class Diaspora { $servers = explode(",", $serverdata); - foreach($servers AS $server) { + foreach ($servers AS $server) { $server = trim($server); + $addr = "relay@".str_replace("http://", "", normalise_link($server)); $batch = $server."/receive/public"; - $relais = q("SELECT `batch`, `id`, `name`,`network` FROM `contact` WHERE `uid` = 0 AND `batch` = '%s' LIMIT 1", dbesc($batch)); + $relais = q("SELECT `batch`, `id`, `name`,`network` FROM `contact` WHERE `uid` = 0 AND `batch` = '%s' AND `addr` = '%s' AND `nurl` = '%s' LIMIT 1", + dbesc($batch), dbesc($addr), dbesc(normalise_link($server))); if (!$relais) { - $addr = "relay@".str_replace("http://", "", normalise_link($server)); - $r = q("INSERT INTO `contact` (`uid`, `created`, `name`, `nick`, `addr`, `url`, `nurl`, `batch`, `network`, `rel`, `blocked`, `pending`, `writable`, `name-date`, `uri-date`, `avatar-date`) VALUES (0, '%s', '%s', 'relay', '%s', '%s', '%s', '%s', '%s', %d, 0, 0, 1, '%s', '%s', '%s')", datetime_convert(), @@ -158,6 +161,32 @@ class Diaspora { return $data; } + /** + * @brief encrypts data via AES + * + * @param string $key The AES key + * @param string $iv The IV (is used for CBC encoding) + * @param string $data The data that is to be encrypted + * + * @return string encrypted data + */ + private static function aes_encrypt($key, $iv, $data) { + return openssl_encrypt($data, 'aes-256-cbc', str_pad($key, 32, "\0"), OPENSSL_RAW_DATA, str_pad($iv, 16, "\0")); + } + + /** + * @brief decrypts data via AES + * + * @param string $key The AES key + * @param string $iv The IV (is used for CBC encoding) + * @param string $encrypted The encrypted data + * + * @return string decrypted data + */ + private static function aes_decrypt($key, $iv, $encrypted) { + return openssl_decrypt($encrypted,'aes-256-cbc', str_pad($key, 32, "\0"), OPENSSL_RAW_DATA,str_pad($iv, 16, "\0")); + } + /** * @brief: Decodes incoming Diaspora message * @@ -179,7 +208,7 @@ class Diaspora { $children = $basedom->children('https://joindiaspora.com/protocol'); - if($children->header) { + if ($children->header) { $public = true; $author_link = str_replace('acct:','',$children->header->author_id); } else { @@ -197,10 +226,7 @@ class Diaspora { $outer_iv = base64_decode($j_outer_key_bundle->iv); $outer_key = base64_decode($j_outer_key_bundle->key); - $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $outer_key, $ciphertext, MCRYPT_MODE_CBC, $outer_iv); - - - $decrypted = pkcs5_unpad($decrypted); + $decrypted = self::aes_decrypt($outer_key, $outer_iv, $ciphertext); logger('decrypted: '.$decrypted, LOGGER_DEBUG); $idom = parse_xml_string($decrypted,false); @@ -215,11 +241,11 @@ class Diaspora { // figure out where in the DOM tree our data is hiding - if($dom->provenance->data) + if ($dom->provenance->data) $base = $dom->provenance; - elseif($dom->env->data) + elseif ($dom->env->data) $base = $dom->env; - elseif($dom->data) + elseif ($dom->data) $base = $dom; if (!$base) { @@ -252,15 +278,14 @@ class Diaspora { $data = base64url_decode($data); - if($public) + if ($public) $inner_decrypted = $data; else { // Decode the encrypted blob $inner_encrypted = base64_decode($data); - $inner_decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $inner_encrypted, MCRYPT_MODE_CBC, $inner_iv); - $inner_decrypted = pkcs5_unpad($inner_decrypted); + $inner_decrypted = self::aes_decrypt($inner_aes_key, $inner_iv, $inner_encrypted); } if (!$author_link) { @@ -309,10 +334,6 @@ class Diaspora { return false; } - // Use a dummy importer to import the data for the public copy - $importer = array("uid" => 0, "page-flags" => PAGE_FREELOVE); - $message_id = self::dispatch($importer,$msg); - // Now distribute it to the followers $r = q("SELECT `user`.* FROM `user` WHERE `user`.`uid` IN (SELECT `contact`.`uid` FROM `contact` WHERE `contact`.`network` = '%s' AND `contact`.`addr` = '%s') @@ -320,13 +341,17 @@ class Diaspora { dbesc(NETWORK_DIASPORA), dbesc($msg["author"]) ); - if ($r) { + + if (dbm::is_result($r)) { foreach ($r as $rr) { logger("delivering to: ".$rr["username"]); self::dispatch($rr,$msg); } } else { - logger("No subscribers for ".$msg["author"]." ".print_r($msg, true), LOGGER_DEBUG); + // Use a dummy importer to import the data for the public copy + // or for comments from unknown people + $importer = array("uid" => 0, "page-flags" => PAGE_FREELOVE); + $message_id = self::dispatch($importer,$msg); } return $message_id; @@ -353,6 +378,11 @@ class Diaspora { $type = $fields->getName(); + $social_relay = Config::get('system', 'relay_subscribe', false); + if (!$social_relay AND ($type == 'message')) { + logger("Unwanted message from ".$sender." send by ".$_SERVER["REMOTE_ADDR"]." with ".$_SERVER["HTTP_USER_AGENT"].": ".print_r($msg, true), LOGGER_DEBUG); + } + logger("Received message type ".$type." from ".$sender." for user ".$importer["uid"], LOGGER_DEBUG); switch ($type) { @@ -549,7 +579,7 @@ class Diaspora { logger("Fetching diaspora key for: ".$handle); $r = self::person_by_handle($handle); - if($r) + if ($r) return $r["pubkey"]; return ""; @@ -605,7 +635,7 @@ class Diaspora { */ private static function add_fcontact($arr, $update = false) { - if($update) { + if ($update) { $r = q("UPDATE `fcontact` SET `name` = '%s', `photo` = '%s', @@ -789,7 +819,7 @@ class Diaspora { // perhaps we were already sharing with this person. Now they're sharing with us. // 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))) { + if ($contact["rel"] == CONTACT_IS_FOLLOWER && in_array($importer["page-flags"], array(PAGE_FREELOVE))) { q("UPDATE `contact` SET `rel` = %d, `writable` = 1 WHERE `id` = %d AND `uid` = %d", intval(CONTACT_IS_FRIEND), intval($contact["id"]), @@ -799,12 +829,12 @@ class Diaspora { logger("defining user ".$contact["nick"]." as friend"); } - if(($contact["blocked"]) || ($contact["readonly"]) || ($contact["archive"])) + if (($contact["blocked"]) || ($contact["readonly"]) || ($contact["archive"])) return false; - if($contact["rel"] == CONTACT_IS_SHARING || $contact["rel"] == CONTACT_IS_FRIEND) + if ($contact["rel"] == CONTACT_IS_SHARING || $contact["rel"] == CONTACT_IS_FRIEND) return true; - if($contact["rel"] == CONTACT_IS_FOLLOWER) - if(($importer["page-flags"] == PAGE_COMMUNITY) OR $is_comment) + if ($contact["rel"] == CONTACT_IS_FOLLOWER) + if (($importer["page-flags"] == PAGE_COMMUNITY) OR $is_comment) return true; // Messages for the global users are always accepted @@ -962,7 +992,7 @@ class Diaspora { logger("Fetch post from ".$source_url, LOGGER_DEBUG); $envelope = fetch_url($source_url); - if($envelope) { + if ($envelope) { logger("Envelope was fetched.", LOGGER_DEBUG); $x = self::verify_magic_envelope($envelope); if (!$x) @@ -978,7 +1008,7 @@ class Diaspora { logger("Fetch post from ".$source_url, LOGGER_DEBUG); $x = fetch_url($source_url); - if(!$x) + if (!$x) return false; } @@ -1035,7 +1065,7 @@ class Diaspora { FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($uid), dbesc($guid)); - if(!$r) { + if (!$r) { $result = self::store_by_guid($guid, $contact["url"], $uid); if (!$result) { @@ -1198,6 +1228,27 @@ class Diaspora { } } + /** + * @brief Find the best importer for a comment + * + * @param array $importer Array of the importer user + * @param string $guid The guid of the item + * + * @return array the importer that fits the best + */ + private static function importer_for_comment($importer, $guid) { + $item = dba::fetch_first("SELECT `uid` FROM `item` WHERE `origin` AND `guid` = ? LIMIT 1", $guid); + + if (dbm::is_result($item)) { + logger("Found user ".$item['uid']." as owner of item ".$guid, LOGGER_DEBUG); + $contact = dba::fetch_first("SELECT * FROM `contact` WHERE `self` AND `uid` = ?", $item['uid']); + if (dbm::is_result($contact)) { + $importer = $contact; + } + } + return $importer; + } + /** * @brief Processes an incoming comment * @@ -1227,6 +1278,11 @@ class Diaspora { $thr_uri = ""; } + // Find the best importer when there was no importer found + if ($importer["uid"] == 0) { + $importer = self::importer_for_comment($importer, $parent_guid); + } + $contact = self::allowed_contact_by_handle($importer, $sender, true); if (!$contact) { return false; @@ -1279,7 +1335,9 @@ class Diaspora { } $datarray["object-type"] = ACTIVITY_OBJ_COMMENT; - $datarray["object"] = $xml; + + $datarray["protocol"] = PROTOCOL_DIASPORA; + $datarray["source"] = $xml; $datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at; @@ -1296,7 +1354,7 @@ class Diaspora { } // If we are the origin of the parent we store the original data and notify our followers - if($message_id AND $parent_item["origin"]) { + if ($message_id AND $parent_item["origin"]) { // Formerly we stored the signed text, the signature and the author in different fields. // We now store the raw data so that we are more flexible. @@ -1473,7 +1531,7 @@ class Diaspora { intval($importer["uid"]), dbesc($guid) ); - if($c) + if ($c) $conversation = $c[0]; else { $r = q("INSERT INTO `conv` (`uid`, `guid`, `creator`, `created`, `updated`, `subject`, `recips`) @@ -1486,13 +1544,13 @@ class Diaspora { dbesc($subject), dbesc($participants) ); - if($r) + if ($r) $c = q("SELECT * FROM `conv` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer["uid"]), dbesc($guid) ); - if($c) + if ($c) $conversation = $c[0]; } if (!$conversation) { @@ -1500,7 +1558,7 @@ class Diaspora { return; } - foreach($messages as $mesg) + foreach ($messages as $mesg) self::receive_conversation_message($importer, $contact, $data, $msg, $mesg, $conversation); return true; @@ -1599,6 +1657,8 @@ class Diaspora { $datarray = array(); + $datarray["protocol"] = PROTOCOL_DIASPORA; + $datarray["uid"] = $importer["uid"]; $datarray["contact-id"] = $author_contact["cid"]; $datarray["network"] = $author_contact["network"]; @@ -1630,7 +1690,7 @@ class Diaspora { logger("Stored like ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); // If we are the origin of the parent we store the original data and notify our followers - if($message_id AND $parent_item["origin"]) { + if ($message_id AND $parent_item["origin"]) { // Formerly we stored the signed text, the signature and the author in different fields. // We now store the raw data so that we are more flexible. @@ -1805,10 +1865,10 @@ class Diaspora { $handle_parts = explode("@", $author); $nick = $handle_parts[0]; - if($name === "") + if ($name === "") $name = $handle_parts[0]; - if( preg_match("|^https?://|", $image_url) === 0) + if ( preg_match("|^https?://|", $image_url) === 0) $image_url = "http://".$handle_parts[1].$image_url; update_contact_avatar($image_url, $importer["uid"], $contact["id"]); @@ -1823,7 +1883,7 @@ class Diaspora { // this is to prevent multiple birthday notifications in a single year // if we already have a stored birthday and the 'm-d' part hasn't changed, preserve the entry, which will preserve the notify year - if(substr($birthday,5) === substr($contact["bd"],5)) + if (substr($birthday,5) === substr($contact["bd"],5)) $birthday = $contact["bd"]; $r = q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `addr` = '%s', `name-date` = '%s', `bd` = '%s', @@ -1841,18 +1901,15 @@ class Diaspora { intval($importer["uid"]) ); - if ($searchable) { - poco_check($contact["url"], $name, NETWORK_DIASPORA, $image_url, $about, $location, $gender, $keywords, "", - datetime_convert(), 2, $contact["id"], $importer["uid"]); - } - $gcontact = array("url" => $contact["url"], "network" => NETWORK_DIASPORA, "generation" => 2, "photo" => $image_url, "name" => $name, "location" => $location, "about" => $about, "birthday" => $birthday, "gender" => $gender, "addr" => $author, "nick" => $nick, "keywords" => $keywords, "hide" => !$searchable, "nsfw" => $nsfw); - update_gcontact($gcontact); + $gcid = update_gcontact($gcontact); + + link_gcontact($gcid, $importer["uid"], $contact["id"]); logger("Profile of contact ".$contact["id"]." stored for user ".$importer["uid"], LOGGER_DEBUG); @@ -1869,7 +1926,7 @@ class Diaspora { $a = get_app(); - if($contact["rel"] == CONTACT_IS_FOLLOWER && in_array($importer["page-flags"], array(PAGE_FREELOVE))) { + if ($contact["rel"] == CONTACT_IS_FOLLOWER && in_array($importer["page-flags"], array(PAGE_FREELOVE))) { q("UPDATE `contact` SET `rel` = %d, `writable` = 1 WHERE `id` = %d AND `uid` = %d", intval(CONTACT_IS_FRIEND), intval($contact["id"]), @@ -1882,7 +1939,7 @@ class Diaspora { intval($importer["uid"]) ); - if($r && !$r[0]["hide-friends"] && !$contact["hidden"] && intval(get_pconfig($importer["uid"], "system", "post_newfriend"))) { + if ($r && !$r[0]["hide-friends"] && !$contact["hidden"] && intval(get_pconfig($importer["uid"], "system", "post_newfriend"))) { $self = q("SELECT * FROM `contact` WHERE `self` AND `uid` = %d LIMIT 1", intval($importer["uid"]) @@ -1890,9 +1947,10 @@ class Diaspora { // they are not CONTACT_IS_FOLLOWER anymore but that's what we have in the array - if($self && $contact["rel"] == CONTACT_IS_FOLLOWER) { + if ($self && $contact["rel"] == CONTACT_IS_FOLLOWER) { $arr = array(); + $arr["protocol"] = PROTOCOL_DIASPORA; $arr["uri"] = $arr["parent-uri"] = item_new_uri($a->get_hostname(), $importer["uid"]); $arr["uid"] = $importer["uid"]; $arr["contact-id"] = $self[0]["id"]; @@ -1921,7 +1979,7 @@ class Diaspora { $arr["deny_gid"] = $user[0]["deny_gid"]; $i = item_store($arr); - if($i) + if ($i) proc_run(PRIORITY_HIGH, "include/notifier.php", "activity", $i); } } @@ -2060,12 +2118,12 @@ class Diaspora { $def_gid = get_default_group($importer['uid'], $ret["network"]); - if(intval($def_gid)) + 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); - if($importer["page-flags"] == PAGE_NORMAL) { + if ($importer["page-flags"] == PAGE_NORMAL) { logger("Sending intra message for author ".$author.".", LOGGER_DEBUG); @@ -2115,7 +2173,7 @@ class Diaspora { ); $u = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($importer["uid"])); - if($u) { + if ($u) { logger("Sending share message (Relation: ".$new_relation.") to author ".$author." - Contact: ".$contact_record["id"]." - User: ".$importer["uid"], LOGGER_DEBUG); $ret = self::send_share($u[0], $contact_record); @@ -2252,7 +2310,8 @@ class Diaspora { $datarray["verb"] = ACTIVITY_POST; $datarray["gravity"] = GRAVITY_PARENT; - $datarray["object"] = $xml; + $datarray["protocol"] = PROTOCOL_DIASPORA; + $datarray["source"] = $xml; $prefix = share_header($original_item["author-name"], $original_item["author-link"], $original_item["author-avatar"], $original_item["guid"], $original_item["created"], $orig_url); @@ -2455,7 +2514,8 @@ class Diaspora { $datarray["verb"] = ACTIVITY_POST; $datarray["gravity"] = GRAVITY_PARENT; - $datarray["object"] = $xml; + $datarray["protocol"] = PROTOCOL_DIASPORA; + $datarray["source"] = $xml; $datarray["body"] = self::replace_people_guid($body, $contact["url"]); @@ -2614,20 +2674,19 @@ class Diaspora { return false; } - $inner_aes_key = random_string(32); + $inner_aes_key = openssl_random_pseudo_bytes(32); $b_inner_aes_key = base64_encode($inner_aes_key); - $inner_iv = random_string(16); + $inner_iv = openssl_random_pseudo_bytes(16); $b_inner_iv = base64_encode($inner_iv); - $outer_aes_key = random_string(32); + $outer_aes_key = openssl_random_pseudo_bytes(32); $b_outer_aes_key = base64_encode($outer_aes_key); - $outer_iv = random_string(16); + $outer_iv = openssl_random_pseudo_bytes(16); $b_outer_iv = base64_encode($outer_iv); $handle = self::my_handle($user); - $padded_data = pkcs5_pad($msg,16); - $inner_encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $padded_data, MCRYPT_MODE_CBC, $inner_iv); + $inner_encrypted = self::aes_encrypt($inner_aes_key, $inner_iv, $msg); $b64_data = base64_encode($inner_encrypted); @@ -2649,9 +2708,8 @@ class Diaspora { "author_id" => $handle)); $decrypted_header = xml::from_array($xmldata, $xml, true); - $decrypted_header = pkcs5_pad($decrypted_header,16); - $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $outer_aes_key, $decrypted_header, MCRYPT_MODE_CBC, $outer_iv); + $ciphertext = self::aes_encrypt($outer_aes_key, $outer_iv, $decrypted_header); $outer_json = json_encode(array("iv" => $b_outer_iv, "key" => $b_outer_aes_key)); @@ -2741,7 +2799,7 @@ class Diaspora { $a = get_app(); $enabled = intval(get_config("system", "diaspora_enabled")); - if(!$enabled) + if (!$enabled) return 200; $logid = random_string(4); @@ -3080,14 +3138,14 @@ class Diaspora { $body = html_entity_decode(bb2diaspora($body)); // Adding the title - if(strlen($title)) + if (strlen($title)) $body = "## ".html_entity_decode($title)."\n\n".$body; if ($item["attach"]) { $cnt = preg_match_all('/href=\"(.*?)\"(.*?)title=\"(.*?)\"/ism', $item["attach"], $matches, PREG_SET_ORDER); - if(cnt) { + if (cnt) { $body .= "\n".t("Attachments:")."\n"; - foreach($matches as $mtch) + foreach ($matches as $mtch) $body .= "[".$mtch[3]."](".$mtch[1].")\n"; } } @@ -3567,7 +3625,7 @@ class Diaspora { if ($searchable === 'true') { $dob = '1000-00-00'; - if (($profile['dob']) && ($profile['dob'] != '0000-00-00')) + if (($profile['dob']) && ($profile['dob'] > '0001-01-01')) $dob = ((intval($profile['dob'])) ? intval($profile['dob']) : '1000') .'-'. datetime_convert('UTC','UTC',$profile['dob'],'m-d'); $about = $profile['about']; @@ -3580,7 +3638,7 @@ class Diaspora { $kw = str_replace(' ',' ',$kw); $arr = explode(' ',$profile['pub_keywords']); if (count($arr)) { - for($x = 0; $x < 5; $x ++) { + for ($x = 0; $x < 5; $x ++) { if (trim($arr[$x])) $tags .= '#'. trim($arr[$x]) .' '; } @@ -3602,7 +3660,7 @@ class Diaspora { "searchable" => $searchable, "tag_string" => $tags); - foreach($recips as $recip) { + foreach ($recips as $recip) { logger("Send updated profile data for user ".$uid." to contact ".$recip["id"], LOGGER_DEBUG); self::build_and_transmit($profile, $recip, "profile", $message, false, "", true); } @@ -3625,17 +3683,20 @@ class Diaspora { } $r = q("SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1", intval($contact['uid'])); - if(!$r) + if (!dbm::is_result($r)) { return false; + } $contact["uprvkey"] = $r[0]['prvkey']; $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", intval($post_id)); - if (!$r) + if (!dbm::is_result($r)) { return false; + } - if (!in_array($r[0]["verb"], array(ACTIVITY_LIKE, ACTIVITY_DISLIKE))) + if (!in_array($r[0]["verb"], array(ACTIVITY_LIKE, ACTIVITY_DISLIKE))) { return false; + } $message = self::construct_like($r[0], $contact); $message["author_signature"] = self::signature($contact, $message);