]> git.mxchange.org Git - friendica.git/blobdiff - src/Protocol/PortableContact.php
Merge pull request #7647 from annando/inter-transport
[friendica.git] / src / Protocol / PortableContact.php
index 374eb02ae07bbc75bb5760c291a99c95ff3929d4..def8f1b628bc3b667636843c9d701f2bf331c5fb 100644 (file)
@@ -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]);
@@ -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,15 +1379,29 @@ class PortableContact
                                                $site_name = $data['site_name'];
                                        }
 
-                                       $info = $data['info'];
-                                       $register_policy = defaults($data, 'register_policy', REGISTER_CLOSED);
-                                       if (in_array($register_policy, ['REGISTER_CLOSED', 'REGISTER_APPROVE', 'REGISTER_OPEN'])) {
-                                               $register_policy = constant($data['register_policy']);
-                                       } else {
-                                               Logger::log("Register policy '$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', '');
                                }
                        }
                }
@@ -1446,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)
        {
@@ -1520,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()
        {
@@ -1544,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)
        {
@@ -1603,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);
@@ -1636,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);
 
@@ -1661,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) {
@@ -1678,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)) {
@@ -1686,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);
                                }
                        }
@@ -1778,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);