X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FProtocol%2FPortableContact.php;h=def8f1b628bc3b667636843c9d701f2bf331c5fb;hb=775324bd07cb0f0a7f0994ee5ec25bd691ca929f;hp=7243da523f9d2e6078b1d4371f66b519838c68ea;hpb=53e9203d37ee0c1a2afed0faf295e3c622ac2e17;p=friendica.git diff --git a/src/Protocol/PortableContact.php b/src/Protocol/PortableContact.php index 7243da523f..def8f1b628 100644 --- a/src/Protocol/PortableContact.php +++ b/src/Protocol/PortableContact.php @@ -20,16 +20,20 @@ use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\GContact; use Friendica\Model\Profile; +use Friendica\Module\Register; use Friendica\Network\Probe; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\Strings; use Friendica\Util\XML; -require_once 'include/dba.php'; - class PortableContact { + const DISABLED = 0; + const USERS = 1; + const USERS_GCONTACTS = 2; + const USERS_GCONTACTS_FALLBACK = 3; + /** * @brief Fetch POCO data * @@ -46,7 +50,7 @@ class PortableContact * Once the global contact is stored add (if necessary) the contact linkage which associates * the given uid, cid to the global contact entry. There can be many uid/cid combinations * pointing to the same global contact id. - * + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function loadWorker($cid, $uid = 0, $zcid = 0, $url = null) { @@ -61,12 +65,10 @@ class PortableContact * @param integer $uid User ID * @param integer $zcid Global Contact ID * @param integer $url POCO address that should be polled - * + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function load($cid, $uid, $zcid, $url) { - $a = get_app(); - if ($cid) { if (!$url || !$uid) { $contact = DBA::selectFirst('contact', ['poco', 'uid'], ['id' => $cid]); @@ -84,7 +86,7 @@ class PortableContact return; } - $url = $url . (($uid) ? '/@me/@all?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation' : '?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation') ; + $url = $url . (($uid) ? '/@me/@all?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation' : '?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation'); Logger::log('load: ' . $url, Logger::DEBUG); @@ -232,7 +234,6 @@ class PortableContact $friendica = preg_replace("=(https?://)(.*)/profile/(.*)=ism", "$1$2", $profile); if ($friendica != $profile) { $server_url = $friendica; - $network = Protocol::DFRN; } } @@ -240,7 +241,6 @@ class PortableContact $diaspora = preg_replace("=(https?://)(.*)/u/(.*)=ism", "$1$2", $profile); if ($diaspora != $profile) { $server_url = $diaspora; - $network = Protocol::DIASPORA; } } @@ -248,7 +248,6 @@ class PortableContact $red = preg_replace("=(https?://)(.*)/channel/(.*)=ism", "$1$2", $profile); if ($red != $profile) { $server_url = $red; - $network = Protocol::DIASPORA; } } @@ -257,7 +256,6 @@ class PortableContact $mastodon = preg_replace("=(https?://)(.*)/users/(.*)=ism", "$1$2", $profile); if ($mastodon != $profile) { $server_url = $mastodon; - $network = Protocol::OSTATUS; } } @@ -266,7 +264,6 @@ class PortableContact $ostatus = preg_replace("=(https?://)(.*)/user/(.*)=ism", "$1$2", $profile); if ($ostatus != $profile) { $server_url = $ostatus; - $network = Protocol::OSTATUS; } } @@ -275,7 +272,6 @@ class PortableContact $base = preg_replace("=(https?://)(.*?)/(.*)=ism", "$1$2", $profile); if ($base != $profile) { $server_url = $base; - $network = Protocol::PHANTOM; } } @@ -336,7 +332,7 @@ class PortableContact $server_url = Strings::normaliseLink(self::detectServer($profile)); } - if (!in_array($gcontacts[0]["network"], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::FEED, Protocol::OSTATUS, ""])) { + if (!in_array($gcontacts[0]["network"], [Protocol::DFRN, Protocol::DIASPORA, Protocol::FEED, Protocol::OSTATUS, ""])) { Logger::log("Profile ".$profile.": Network type ".$gcontacts[0]["network"]." can't be checked", Logger::DEBUG); return false; } @@ -509,8 +505,15 @@ class PortableContact $last_updated = ""; foreach ($entries as $entry) { - $published = DateTimeFormat::utc($xpath->query('atom:published/text()', $entry)->item(0)->nodeValue); - $updated = DateTimeFormat::utc($xpath->query('atom:updated/text()' , $entry)->item(0)->nodeValue); + $published_item = $xpath->query('atom:published/text()', $entry)->item(0); + $updated_item = $xpath->query('atom:updated/text()' , $entry)->item(0); + $published = isset($published_item->nodeValue) ? DateTimeFormat::utc($published_item->nodeValue) : null; + $updated = isset($updated_item->nodeValue) ? DateTimeFormat::utc($updated_item->nodeValue) : null; + + if (!isset($published) || !isset($updated)) { + Logger::notice('Invalid entry for XPath.', ['entry' => $entry, 'profile' => $profile]); + continue; + } if ($last_updated < $published) { $last_updated = $published; @@ -611,8 +614,6 @@ class PortableContact */ private static function detectPocoData(array $data) { - $server = false; - if (!isset($data['entry'])) { return false; } @@ -645,6 +646,7 @@ class PortableContact * * @param string $server_url address of the server * @return array Server data + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function fetchNodeinfo($server_url) { @@ -663,7 +665,7 @@ class PortableContact $nodeinfo2_url = ''; foreach ($nodeinfo['links'] as $link) { - if (!is_array($link) || empty($link['rel'])) { + if (!is_array($link) || empty($link['rel']) || empty($link['href'])) { Logger::log('Invalid nodeinfo format for ' . $server_url, Logger::DEBUG); continue; } @@ -698,6 +700,7 @@ class PortableContact * * @param string $nodeinfo_url address of the nodeinfo path * @return array Server data + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function parseNodeinfo1($nodeinfo_url) { @@ -715,10 +718,10 @@ class PortableContact $server = []; - $server['register_policy'] = REGISTER_CLOSED; + $server['register_policy'] = Register::CLOSED; if (is_bool($nodeinfo['openRegistrations']) && $nodeinfo['openRegistrations']) { - $server['register_policy'] = REGISTER_OPEN; + $server['register_policy'] = Register::OPEN; } if (is_array($nodeinfo['software'])) { @@ -734,7 +737,7 @@ class PortableContact } } - if (is_array($nodeinfo['metadata']) && isset($nodeinfo['metadata']['nodeName'])) { + if (isset($nodeinfo['metadata']['nodeName'])) { $server['site_name'] = $nodeinfo['metadata']['nodeName']; } @@ -746,7 +749,7 @@ class PortableContact $friendica = false; $gnusocial = false; - if (is_array($nodeinfo['protocols']['inbound'])) { + if (!empty($nodeinfo['protocols']['inbound']) && is_array($nodeinfo['protocols']['inbound'])) { foreach ($nodeinfo['protocols']['inbound'] as $inbound) { if ($inbound == 'diaspora') { $diaspora = true; @@ -782,6 +785,7 @@ class PortableContact * * @param string $nodeinfo_url address of the nodeinfo path * @return array Server data + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function parseNodeinfo2($nodeinfo_url) { @@ -798,10 +802,10 @@ class PortableContact $server = []; - $server['register_policy'] = REGISTER_CLOSED; + $server['register_policy'] = Register::CLOSED; if (is_bool($nodeinfo['openRegistrations']) && $nodeinfo['openRegistrations']) { - $server['register_policy'] = REGISTER_OPEN; + $server['register_policy'] = Register::OPEN; } if (is_array($nodeinfo['software'])) { @@ -817,7 +821,7 @@ class PortableContact } } - if (is_array($nodeinfo['metadata']) && isset($nodeinfo['metadata']['nodeName'])) { + if (isset($nodeinfo['metadata']['nodeName'])) { $server['site_name'] = $nodeinfo['metadata']['nodeName']; } @@ -1000,7 +1004,7 @@ class PortableContact $server_url = str_replace("http://", "https://", $server_url); // We set the timeout to 20 seconds since this operation should be done in no time if the server was vital - $curlResult = Network::curl($server_url."/.well-known/host-meta", false, $redirects, ['timeout' => 20]); + $curlResult = Network::curl($server_url."/.well-known/host-meta", false, ['timeout' => 20]); // Quit if there is a timeout. // But we want to make sure to only quit if we are mostly sure that this server url fits. @@ -1017,7 +1021,7 @@ class PortableContact $server_url = str_replace("https://", "http://", $server_url); // We set the timeout to 20 seconds since this operation should be done in no time if the server was vital - $curlResult = Network::curl($server_url."/.well-known/host-meta", false, $redirects, ['timeout' => 20]); + $curlResult = Network::curl($server_url."/.well-known/host-meta", false, ['timeout' => 20]); // Quit if there is a timeout if ($curlResult->isTimeout()) { @@ -1201,16 +1205,16 @@ class PortableContact if (!empty($data['register_policy'])) { switch ($data['register_policy']) { case "REGISTER_OPEN": - $register_policy = REGISTER_OPEN; + $register_policy = Register::OPEN; break; case "REGISTER_APPROVE": - $register_policy = REGISTER_APPROVE; + $register_policy = Register::APPROVE; break; case "REGISTER_CLOSED": default: - $register_policy = REGISTER_CLOSED; + $register_policy = Register::CLOSED; break; } } @@ -1276,11 +1280,11 @@ class PortableContact } if (!$closed && !$private and $inviteonly) { - $register_policy = REGISTER_APPROVE; + $register_policy = Register::APPROVE; } elseif (!$closed && !$private) { - $register_policy = REGISTER_OPEN; + $register_policy = Register::OPEN; } else { - $register_policy = REGISTER_CLOSED; + $register_policy = Register::CLOSED; } } } @@ -1314,9 +1318,9 @@ class PortableContact } if (!empty($data['registrations_open']) && $data['registrations_open']) { - $register_policy = REGISTER_OPEN; + $register_policy = Register::OPEN; } else { - $register_policy = REGISTER_CLOSED; + $register_policy = Register::CLOSED; } } } @@ -1375,14 +1379,29 @@ class PortableContact $site_name = $data['site_name']; } - $info = $data['info']; - if (in_array($data['register_policy'], ['REGISTER_CLOSED', 'REGISTER_APPROVE', 'REGISTER_OPEN'])) { - $register_policy = constant($data['register_policy']); - } else { - Logger::log("Register policy '{$data['register_policy']}' from $server_url is invalid."); - $register_policy = REGISTER_CLOSED; // set a default value + $info = defaults($data, 'info', ''); + + $register_policy = defaults($data, 'register_policy', 'REGISTER_CLOSED'); + switch ($register_policy) { + case 'REGISTER_OPEN': + $register_policy = Register::OPEN; + break; + + case 'REGISTER_APPROVE': + $register_policy = Register::APPROVE; + break; + + default: + Logger::log("Register policy '$register_policy' from $server_url is invalid."); + // Defaulting to closed + + case 'REGISTER_CLOSED': + case 'REGISTER_INVITATION': + $register_policy = Register::CLOSED; + break; } - $platform = $data['platform']; + + $platform = defaults($data, 'platform', ''); } } } @@ -1445,6 +1464,7 @@ class PortableContact * @brief Fetch relay data from a given server url * * @param string $server_url address of the server + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function discoverRelay($server_url) { @@ -1519,6 +1539,7 @@ class PortableContact /** * @brief Returns a list of all known servers * @return array List of server urls + * @throws Exception */ public static function serverlist() { @@ -1543,6 +1564,7 @@ class PortableContact * @brief Fetch server list from remote servers and adds them when they are new. * * @param string $poco URL to the POCO endpoint + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function fetchServerlist($poco) { @@ -1602,7 +1624,7 @@ class PortableContact if (!empty($accesstoken)) { $api = 'https://instances.social/api/1.0/instances/list?count=0'; $header = ['Authorization: Bearer '.$accesstoken]; - $curlResult = Network::curl($api, false, $redirects, ['headers' => $header]); + $curlResult = Network::curl($api, false, ['headers' => $header]); if ($curlResult->isSuccess()) { $servers = json_decode($curlResult->getBody(), true); @@ -1635,21 +1657,19 @@ class PortableContact public static function discoverSingleServer($id) { - $r = q("SELECT `poco`, `nurl`, `url`, `network` FROM `gserver` WHERE `id` = %d", intval($id)); + $server = DBA::selectFirst('gserver', ['poco', 'nurl', 'url', 'network'], ['id' => $id]); - if (!DBA::isResult($r)) { + if (!DBA::isResult($server)) { return false; } - $server = $r[0]; - // Discover new servers out there (Works from Friendica version 3.5.2) self::fetchServerlist($server["poco"]); // Fetch all users from the other server $url = $server["poco"] . "/?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation"; - Logger::log("Fetch all users from the server " . $server["url"], Logger::DEBUG); + Logger::info("Fetch all users from the server " . $server["url"]); $curlResult = Network::curl($url); @@ -1660,7 +1680,7 @@ class PortableContact self::discoverServer($data, 2); } - if (Config::get('system', 'poco_discovery') > 1) { + if (Config::get('system', 'poco_discovery') >= self::USERS_GCONTACTS) { $timeframe = Config::get('system', 'poco_discovery_since'); if ($timeframe == 0) { @@ -1677,7 +1697,7 @@ class PortableContact $curlResult = Network::curl($url); if ($curlResult->isSuccess() && !empty($curlResult->getBody())) { - Logger::log("Fetch all global contacts from the server " . $server["nurl"], Logger::DEBUG); + Logger::info("Fetch all global contacts from the server " . $server["nurl"]); $data = json_decode($curlResult->getBody(), true); if (!empty($data)) { @@ -1685,8 +1705,8 @@ class PortableContact } } - if (!$success && (Config::get('system', 'poco_discovery') > 2)) { - Logger::log("Fetch contacts from users of the server " . $server["nurl"], Logger::DEBUG); + if (!$success && !empty($data) && Config::get('system', 'poco_discovery') >= self::USERS_GCONTACTS_FALLBACK) { + Logger::info("Fetch contacts from users of the server " . $server["nurl"]); self::discoverServerUsers($data, $server); } } @@ -1777,7 +1797,7 @@ class PortableContact $curlResult = Network::curl($url); if ($curlResult->isSuccess()) { - $data = json_decode($curlResult["body"], true); + $data = json_decode($curlResult->getBody(), true); if (!empty($data)) { self::discoverServer($data, 3);