]> git.mxchange.org Git - friendica.git/commitdiff
Table "apcontact" is now in use / added functionality to handle JSON-LD
authorMichael <heluecht@pirati.ca>
Thu, 20 Sep 2018 05:00:49 +0000 (05:00 +0000)
committerMichael <heluecht@pirati.ca>
Thu, 20 Sep 2018 05:00:49 +0000 (05:00 +0000)
src/Network/Probe.php
src/Protocol/ActivityPub.php

index 0e9219c5a615b8b095f1068b827f060f640d27c4..c0c627bfe911e01d07b32b585402a27132f9ed46 100644 (file)
@@ -336,7 +336,7 @@ class Probe
                }
 
                if (in_array(defaults($data, 'network', ''), ['', Protocol::PHANTOM])) {
-                       $ap_profile = ActivityPub::fetchProfile($uri);
+                       $ap_profile = ActivityPub::probeProfile($uri);
                        if (!empty($ap_profile) && ($ap_profile['network'] == Protocol::ACTIVITYPUB)) {
                                $data = $ap_profile;
                        }
index ffde0eff00d0df465a993c8c2e0ff02cb6a4a337..4a2394a24b2ba5f1a2fbb9f2b8d1e9a82c17b788 100644 (file)
@@ -19,7 +19,8 @@ use Friendica\Util\DateTimeFormat;
 use Friendica\Util\Crypto;
 use Friendica\Content\Text\BBCode;
 use Friendica\Content\Text\HTML;
-use Friendica\Network\Probe;
+use Friendica\Core\Cache;
+use digitalbazaar\jsonld;
 
 /**
  * @brief ActivityPub Protocol class
@@ -57,6 +58,51 @@ class ActivityPub
 {
        const PUBLIC = 'https://www.w3.org/ns/activitystreams#Public';
 
+public static function jsonld_document_loader($url)
+{
+       $recursion = 0;
+
+       $x = debug_backtrace();
+       if ($x) {
+               foreach ($x as $n) {
+                       if ($n['function'] === __FUNCTION__)  {
+                               $recursion ++;
+                       }
+               }
+       }
+
+       if ($recursion > 5) {
+               logger('jsonld bomb detected at: ' . $url);
+               exit();
+       }
+
+       $result = Cache::get('jsonld_document_loader:' . $url);
+       if (!is_null($result)) {
+               return $result;
+       }
+
+       $data = jsonld_default_document_loader($url);
+       Cache::set('jsonld_document_loader:' . $url, $data, CACHE_DAY);
+       return $data;
+}
+
+       public static function compactJsonLD($json)
+       {
+               jsonld_set_document_loader('Friendica\Protocol\ActivityPub::jsonld_document_loader');
+
+               $context = (object)['as' => 'https://www.w3.org/ns/activitystreams',
+                       'w3sec' => 'https://w3id.org/security',
+                       'ostatus' => (object)['@id' => 'http://ostatus.org#', '@type' => '@id'],
+                       'vcard' => (object)['@id' => 'http://www.w3.org/2006/vcard/ns#', '@type' => '@id'],
+                       'uuid' => (object)['@id' => 'http://schema.org/identifier', '@type' => '@id']];
+
+               $jsonobj = json_decode(json_encode($json));
+
+               $compacted = jsonld_compact($jsonobj, $context);
+
+               return json_decode(json_encode($compacted), true);
+       }
+
        public static function isRequest()
        {
                return stristr(defaults($_SERVER, 'HTTP_ACCEPT', ''), 'application/activity+json') ||
@@ -167,8 +213,8 @@ class ActivityPub
                                if ($term['type'] != TERM_MENTION) {
                                        continue;
                                }
-                               $profile = Probe::uri($term['url'], Protocol::ACTIVITYPUB);
-                               if ($profile['network'] == Protocol::ACTIVITYPUB) {
+                               $profile = self::fetchprofile($term['url']);
+                               if (!empty($profile)) {
                                        $data['cc'][] = $profile['url'];
                                }
                        }
@@ -221,9 +267,9 @@ class ActivityPub
                                if ($term['type'] != TERM_MENTION) {
                                        continue;
                                }
-                               $profile = Probe::uri($term['url'], Protocol::ACTIVITYPUB);
-                               if ($profile['network'] == Protocol::ACTIVITYPUB) {
-                                       $target = defaults($profile, 'batch', $profile['notify']);
+                               $profile = self::fetchprofile($term['url']);
+                               if (!empty($profile)) {
+                                       $target = defaults($profile, 'sharedinbox', $profile['inbox']);
                                        $inboxes[$target] = $target;
                                }
                        }
@@ -239,9 +285,9 @@ class ActivityPub
                                $cid = Contact::getIdForURL($term['url'], $item['uid']);
                                if (!empty($cid) && in_array($cid, $receiver_list)) {
                                        $contact = DBA::selectFirst('contact', ['url'], ['id' => $cid, 'network' => Protocol::ACTIVITYPUB]);
-                                       $profile = Probe::uri($contact['url'], Protocol::ACTIVITYPUB);
-                                       if ($profile['network'] == Protocol::ACTIVITYPUB) {
-                                               $target = defaults($profile, 'batch', $profile['notify']);
+                                       $profile = self::fetchprofile($contact['url']);
+                                       if (!empty($profile['network'])) {
+                                               $target = defaults($profile, 'sharedinbox', $profile['inbox']);
                                                $inboxes[$target] = $target;
                                        }
                                }
@@ -249,21 +295,21 @@ class ActivityPub
 
                        foreach ($receiver_list as $receiver) {
                                $contact = DBA::selectFirst('contact', ['url'], ['id' => $receiver, 'network' => Protocol::ACTIVITYPUB]);
-                               $profile = Probe::uri($contact['url'], Protocol::ACTIVITYPUB);
-                               if ($profile['network'] == Protocol::ACTIVITYPUB) {
-                                       $target = defaults($profile, 'batch', $profile['notify']);
+                               $profile = self::fetchprofile($contact['url']);
+                               if (!empty($profile['network'])) {
+                                       $target = defaults($profile, 'sharedinbox', $profile['inbox']);
                                        $inboxes[$target] = $target;
                                }
                        }
                }
 
-               $profile = Probe::uri($target, Protocol::ACTIVITYPUB);
-               if (!empty($profile['batch'])) {
-                       unset($inboxes[$profile['batch']]);
+               $profile = self::fetchprofile($item['author-link']);
+               if (!empty($profile['sharedinbox'])) {
+                       unset($inboxes[$profile['sharedinbox']]);
                }
 
-               if (!empty($profile['notify'])) {
-                       unset($inboxes[$profile['notify']]);
+               if (!empty($profile['inbox'])) {
+                       unset($inboxes[$profile['inbox']]);
                }
 
                return $inboxes;
@@ -389,7 +435,7 @@ class ActivityPub
 
        public static function transmitActivity($activity, $target, $uid)
        {
-               $profile = Probe::uri($target, Protocol::ACTIVITYPUB);
+               $profile = self::fetchprofile($target);
 
                $owner = User::getOwnerDataById($uid);
 
@@ -401,12 +447,12 @@ class ActivityPub
                        'to' => $profile['url']];
 
                logger('Sending activity ' . $activity . ' to ' . $target . ' for user ' . $uid, LOGGER_DEBUG);
-               return self::transmit($data,  $profile['notify'], $uid);
+               return self::transmit($data,  $profile['inbox'], $uid);
        }
 
        public static function transmitContactAccept($target, $id, $uid)
        {
-               $profile = Probe::uri($target, Protocol::ACTIVITYPUB);
+               $profile = self::fetchprofile($target);
 
                $owner = User::getOwnerDataById($uid);
                $data = ['@context' => 'https://www.w3.org/ns/activitystreams',
@@ -419,12 +465,12 @@ class ActivityPub
                        'to' => $profile['url']];
 
                logger('Sending accept to ' . $target . ' for user ' . $uid . ' with id ' . $id, LOGGER_DEBUG);
-               return self::transmit($data,  $profile['notify'], $uid);
+               return self::transmit($data,  $profile['inbox'], $uid);
        }
 
        public static function transmitContactReject($target, $id, $uid)
        {
-               $profile = Probe::uri($target, Protocol::ACTIVITYPUB);
+               $profile = self::fetchprofile($target);
 
                $owner = User::getOwnerDataById($uid);
                $data = ['@context' => 'https://www.w3.org/ns/activitystreams',
@@ -437,12 +483,12 @@ class ActivityPub
                        'to' => $profile['url']];
 
                logger('Sending reject to ' . $target . ' for user ' . $uid . ' with id ' . $id, LOGGER_DEBUG);
-               return self::transmit($data,  $profile['notify'], $uid);
+               return self::transmit($data,  $profile['inbox'], $uid);
        }
 
        public static function transmitContactUndo($target, $uid)
        {
-               $profile = Probe::uri($target, Protocol::ACTIVITYPUB);
+               $profile = self::fetchprofile($target);
 
                $id = System::baseUrl() . '/activity/' . System::createGUID();
 
@@ -457,7 +503,7 @@ class ActivityPub
                        'to' => $profile['url']];
 
                logger('Sending undo to ' . $target . ' for user ' . $uid . ' with id ' . $id, LOGGER_DEBUG);
-               return self::transmit($data,  $profile['notify'], $uid);
+               return self::transmit($data,  $profile['inbox'], $uid);
        }
 
        /**
@@ -616,11 +662,11 @@ class ActivityPub
        {
                $url = (strpos($id, '#') ? substr($id, 0, strpos($id, '#')) : $id);
 
-               $profile = Probe::uri($url, Protocol::ACTIVITYPUB);
+               $profile = self::fetchprofile($url);
                if (!empty($profile)) {
                        return $profile['pubkey'];
                } elseif ($url != $actor) {
-                       $profile = Probe::uri($actor, Protocol::ACTIVITYPUB);
+                       $profile = self::fetchprofile($actor);
                        if (!empty($profile)) {
                                return $profile['pubkey'];
                        }
@@ -663,14 +709,29 @@ class ActivityPub
                return $ret;
        }
 
-       /**
-        * Fetches a profile from the given url
-        *
-        * @param string $url profile url
-        * @return array
-        */
-       public static function fetchProfile($url)
+       public static function fetchprofile($url, $update = false)
        {
+               if (empty($url)) {
+                       return false;
+               }
+
+               if (!$update) {
+                       $apcontact = DBA::selectFirst('apcontact', [], ['url' => $url]);
+                       if (DBA::isResult($apcontact)) {
+                               return $apcontact;
+                       }
+
+                       $apcontact = DBA::selectFirst('apcontact', [], ['alias' => $url]);
+                       if (DBA::isResult($apcontact)) {
+                               return $apcontact;
+                       }
+
+                       $apcontact = DBA::selectFirst('apcontact', [], ['addr' => $url]);
+                       if (DBA::isResult($apcontact)) {
+                               return $apcontact;
+                       }
+               }
+
                if (empty(parse_url($url, PHP_URL_SCHEME))) {
                        $url = self::addrToUrl($url);
                        if (empty($url)) {
@@ -704,7 +765,19 @@ class ActivityPub
                unset($parts['path']);
                $apcontact['addr'] = $apcontact['nick'] . '@' . str_replace('//', '', Network::unparseURL($parts));
 
-               $apcontact['pubkey'] = self::processElement($data, 'publicKey', 'publicKeyPem');
+               $apcontact['pubkey'] = trim(self::processElement($data, 'publicKey', 'publicKeyPem'));
+
+               // To-Do
+               // manuallyApprovesFollowers
+
+               // Unhandled
+               // @context, tag, attachment, image, nomadicLocations, signature, following, followers, featured, movedTo, liked
+
+               // Unhandled from Misskey
+               // sharedInbox, isCat
+
+               // Unhandled from Kroeg
+               // kroeg:blocks, updated
 
                // Check if the address is resolvable
                if (self::addrToUrl($apcontact['addr']) == $apcontact['url']) {
@@ -723,7 +796,22 @@ class ActivityPub
 
                DBA::update('apcontact', $apcontact, ['url' => $url], true);
 
-               // Array that is compatible to Probe::uri
+               return $apcontact;
+       }
+
+       /**
+        * Fetches a profile from the given url into an array that is compatible to Probe::uri
+        *
+        * @param string $url profile url
+        * @return array
+        */
+       public static function probeProfile($url)
+       {
+               $apcontact = self::fetchprofile($url, true);
+               if (empty($apcontact)) {
+                       return false;
+               }
+
                $profile = ['network' => Protocol::ACTIVITYPUB];
                $profile['nick'] = $apcontact['nick'];
                $profile['name'] = $apcontact['name'];
@@ -749,18 +837,6 @@ class ActivityPub
                        }
                }
 
-               // To-Do
-               // type, manuallyApprovesFollowers
-
-               // Unhandled
-               // @context, tag, attachment, image, nomadicLocations, signature, following, followers, featured, movedTo, liked
-
-               // Unhandled from Misskey
-               // sharedInbox, isCat
-
-               // Unhandled from Kroeg
-               // kroeg:blocks, updated
-
                return $profile;
        }
 
@@ -953,8 +1029,8 @@ class ActivityPub
                $receivers = [];
 
                if (!empty($actor)) {
-                       $data = self::fetchContent($actor);
-                       $followers = defaults($data, 'followers', '');
+                       $profile = self::fetchprofile($actor);
+                       $followers = defaults($profile, 'followers', '');
 
                        logger('Actor: ' . $actor . ' - Followers: ' . $followers, LOGGER_DEBUG);
                } else {
@@ -1365,7 +1441,7 @@ class ActivityPub
                $activity['id'] = $object['id'];
                $activity['to'] = defaults($object, 'to', []);
                $activity['cc'] = defaults($object, 'cc', []);
-               $activity['actor'] = $activity['author'];
+               $activity['actor'] = $child['author'];
                $activity['object'] = $object;
                $activity['published'] = $object['published'];
                $activity['type'] = 'Create';