]> git.mxchange.org Git - friendica.git/commitdiff
Ckeck for host differences of fetched objects
authorMichael <heluecht@pirati.ca>
Sat, 10 Feb 2024 04:58:11 +0000 (04:58 +0000)
committerMichael <heluecht@pirati.ca>
Sat, 10 Feb 2024 04:58:11 +0000 (04:58 +0000)
src/Protocol/ActivityPub/Processor.php
src/Util/JsonLD.php

index 9b1c84bbb187cb5c0c00f973a47f5f4d1c844d3c..35ae4e504ddb66d0797cfc2e60f4707e0f9829be 100644 (file)
@@ -1538,6 +1538,11 @@ class Processor
                }
 
                $object = HTTPSignature::fetch($url, $uid);
+
+               if (!empty($object)) {
+                       $object = self::refetchObjectOnHostDifference($object, $url);
+               }
+
                if (empty($object)) {
                        Logger::notice('Activity was not fetchable, aborting.', ['url' => $url, 'uid' => $uid]);
                        // We perform negative caching.
@@ -1549,6 +1554,11 @@ class Processor
                        Logger::notice('Activity has got not id, aborting. ', ['url' => $url, 'object' => $object]);
                        return [];
                }
+
+               if (!self::isValidObject($object, $url)) {
+                       return [];
+               }
+
                DI::cache()->set($cachekey, $object, Duration::FIVE_MINUTES);
 
                Logger::debug('Activity was fetched successfully', ['url' => $url, 'uid' => $uid]);
@@ -1594,6 +1604,11 @@ class Processor
                }
 
                $object = json_decode($body, true);
+
+               if (!empty($object)) {
+                       $object = self::refetchObjectOnHostDifference($object, $url);
+               }
+
                if (empty($object) || !is_array($object)) {
                        $element = explode(';', $curlResult->getContentType());
                        if (!in_array($element[0], ['application/activity+json', 'application/ld+json', 'application/json'])) {
@@ -1604,6 +1619,10 @@ class Processor
                        return '';
                }
 
+               if (!self::isValidObject($object, $url)) {
+                       return '';
+               }
+
                $ldobject = JsonLD::compact($object);
 
                $signer = [];
@@ -1693,6 +1712,79 @@ class Processor
                return $activity['id'];
        }
 
+       private static function refetchObjectOnHostDifference(array $object, string $url): array
+       {
+               $ldobject = JsonLD::compact($object);
+               if (empty($ldobject)) {
+                       Logger::info('Invalid object', ['url' => $url]);
+                       return $object;
+               }
+
+               $id = JsonLD::fetchElement($ldobject, '@id');
+               if (empty($id)) {
+                       Logger::info('No id found in object', ['url' => $url, 'object' => $object]);
+                       return $object;
+               }
+
+               $url_host = parse_url($url, PHP_URL_HOST);
+               $id_host  = parse_url($id, PHP_URL_HOST);
+
+               if ($id_host == $url_host) {
+                       return $object;
+               }
+
+               Logger::notice('Refetch activity because of a host mismatch between requested and received id', ['url-host' => $url_host, 'id-host' => $id_host, 'url' => $url, 'id' => $id]);
+               return HTTPSignature::fetch($id);
+       }
+
+       private static function isValidObject(array $object): bool
+       {
+               $ldobject = JsonLD::compact($object);
+               if (empty($ldobject)) {
+                       Logger::info('Invalid object');
+                       return false;
+               }
+
+               $id = JsonLD::fetchElement($ldobject, '@id');
+               if (empty($id)) {
+                       Logger::info('No id found in object');
+                       return false;
+               }
+
+               $type          = JsonLD::fetchElement($ldobject, '@type');
+               $object_id     = JsonLD::fetchElement($ldobject, 'as:object', '@id');
+               $object_type   = JsonLD::fetchElement($ldobject, 'as:object', '@type');
+               $actor         = JsonLD::fetchElement($ldobject, 'as:actor', '@id');
+               $attributed_to = JsonLD::fetchElement($ldobject, 'as:attributedTo', '@id');
+
+               $id_host  = parse_url($id, PHP_URL_HOST);
+
+               if (!empty($actor) && !in_array($type, Receiver::CONTENT_TYPES) && !empty($object_id)) {
+                       $actor_host = parse_url($actor, PHP_URL_HOST);
+                       if ($actor_host != $id_host) {
+                               Logger::notice('Host mismatch between received id and actor', ['id-host' => $id_host, 'actor-host' => $actor_host, 'id' => $id, 'type' => $type, 'object-id' => $object_id, 'object_type' => $object_type, 'actor' => $actor, 'attributed_to' => $attributed_to]);
+                               return false;
+                       }
+                       if (!empty($object_type)) {
+                               $object_attributed_to = JsonLD::fetchElement($ldobject['as:object'], 'as:attributedTo', '@id');
+                               $attributed_to_host   = parse_url($object_attributed_to, PHP_URL_HOST);
+                               $object_id_host       = parse_url($object_id, PHP_URL_HOST);
+                               if (!empty($attributed_to_host) && ($attributed_to_host != $object_id_host)) {
+                                       Logger::notice('Host mismatch between received object id and attributed actor', ['id-object-host' => $object_id_host, 'attributed-host' => $attributed_to_host, 'id' => $id, 'type' => $type, 'object-id' => $object_id, 'object_type' => $object_type, 'actor' => $actor, 'object_attributed_to' => $object_attributed_to]);
+                                       return false;
+                               }
+                       }
+               } elseif (!empty($attributed_to)) {
+                       $attributed_to_host = parse_url($attributed_to, PHP_URL_HOST);
+                       if ($attributed_to_host != $id_host) {
+                               Logger::notice('Host mismatch between received id and attributed actor', ['id-host' => $id_host, 'attributed-host' => $attributed_to_host, 'id' => $id, 'type' => $type, 'object-id' => $object_id, 'object_type' => $object_type, 'actor' => $actor, 'attributed_to' => $attributed_to]);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+
        private static function getActivityForObject(array $object, string $actor): array
        {
                if (!empty($object['published'])) {
index f1d4da3f5b4d91852ebf3a9a9002720ac011cf73..8b709332173b1a9b21f807330c6ec605e6f2ed8d 100644 (file)
@@ -26,6 +26,7 @@ use Friendica\Core\Logger;
 use Exception;
 use Friendica\Core\System;
 use Friendica\DI;
+use Friendica\Protocol\ActivityPub;
 
 /**
  * This class contain methods to work with JsonLD data
@@ -179,6 +180,10 @@ class JsonLD
 
                $orig_json = $json;
 
+               if (empty($json['@context'])) {
+                       $json['@context'] = ActivityPub::CONTEXT;
+               }
+
                // Preparation for adding possibly missing content to the context
                if (!empty($json['@context']) && is_string($json['@context'])) {
                        $json['@context'] = [$json['@context']];