]> git.mxchange.org Git - friendica.git/blobdiff - src/Protocol/Relay.php
Merge pull request #13238 from annando/issue-13221
[friendica.git] / src / Protocol / Relay.php
index 8679bbec5bf1ee50f87fc8d49c1a5457d863ad9d..c5131fb3fd75eb82b915dcb9c86e10219493e0f3 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @copyright Copyright (C) 2010-2022, the Friendica project
+ * @copyright Copyright (C) 2010-2023, the Friendica project
  *
  * @license GNU AGPL version 3 or any later version
  *
@@ -29,6 +29,7 @@ use Friendica\DI;
 use Friendica\Model\APContact;
 use Friendica\Model\Contact;
 use Friendica\Model\GServer;
+use Friendica\Model\Item;
 use Friendica\Model\Post;
 use Friendica\Model\Search;
 use Friendica\Model\Tag;
@@ -55,7 +56,7 @@ class Relay
         * @param string $url
         * @return boolean "true" is the post is wanted by the system
         */
-       public static function isSolicitedPost(array $tags, string $body, int $authorid, string $url, string $network = '')
+       public static function isSolicitedPost(array $tags, string $body, int $authorid, string $url, string $network = '', int $causerid = 0): bool
        {
                $config = DI::config();
 
@@ -76,6 +77,15 @@ class Relay
                        return false;
                }
 
+               if (!empty($causerid)) {
+                       $contact = Contact::getById($causerid, ['url']);
+                       $causer = $contact['url'] ?? '';
+               } else {
+                       $causer = '';
+               }
+
+               $body = ActivityPub\Processor::normalizeMentionLinks($body);
+
                $systemTags = [];
                $userTags = [];
                $denyTags = [];
@@ -107,38 +117,74 @@ class Relay
                        foreach ($tags as $tag) {
                                $tag = mb_strtolower($tag);
                                if (in_array($tag, $denyTags)) {
-                                       Logger::info('Unwanted hashtag found - rejected', ['hashtag' => $tag, 'network' => $network, 'url' => $url]);
+                                       Logger::info('Unwanted hashtag found - rejected', ['hashtag' => $tag, 'network' => $network, 'url' => $url, 'causer' => $causer]);
                                        return false;
                                }
 
                                if (in_array($tag, $tagList)) {
-                                       Logger::info('Subscribed hashtag found - accepted', ['hashtag' => $tag, 'network' => $network, 'url' => $url]);
+                                       Logger::info('Subscribed hashtag found - accepted', ['hashtag' => $tag, 'network' => $network, 'url' => $url, 'causer' => $causer]);
                                        return true;
                                }
 
                                // We check with "strpos" for performance issues. Only when this is true, the regular expression check is used
                                // RegExp is taken from here: https://medium.com/@shiba1014/regex-word-boundaries-with-unicode-207794f6e7ed
                                if ((strpos($content, $tag) !== false) && preg_match('/(?<=[\s,.:;"\']|^)' . preg_quote($tag, '/') . '(?=[\s,.:;"\']|$)/', $content)) {
-                                       Logger::info('Subscribed hashtag found in content - accepted', ['hashtag' => $tag, 'network' => $network, 'url' => $url]);
+                                       Logger::info('Subscribed hashtag found in content - accepted', ['hashtag' => $tag, 'network' => $network, 'url' => $url, 'causer' => $causer]);
                                        return true;
                                }
                        }
                }
 
+               if (!self::isWantedLanguage($body)) {
+                       Logger::info('Unwanted or Undetected language found - rejected', ['network' => $network, 'url' => $url, 'causer' => $causer]);
+                       return false;
+               }
+
                if ($scope == self::SCOPE_ALL) {
-                       Logger::info('Server accept all posts - accepted', ['network' => $network, 'url' => $url]);
+                       Logger::info('Server accept all posts - accepted', ['network' => $network, 'url' => $url, 'causer' => $causer]);
                        return true;
                }
 
-               Logger::info('No matching hashtags found - rejected', ['network' => $network, 'url' => $url]);
+               Logger::info('No matching hashtags found - rejected', ['network' => $network, 'url' => $url, 'causer' => $causer]);
                return false;
        }
 
+       /**
+        * Detect the language of a post and decide if the post should be accepted
+        *
+        * @param string $body
+        * @return boolean
+        */
+       public static function isWantedLanguage(string $body)
+       {
+               $languages = [];
+               foreach (Item::getLanguageArray($body, 10) as $language => $reliability) {
+                       if ($reliability > 0) {
+                               $languages[] = $language;
+                       }
+               }
+
+               Logger::debug('Got languages', ['languages' => $languages, 'body' => $body]);
+
+               if (!empty($languages)) {
+                       if (in_array($languages[0], DI::config()->get('system', 'relay_deny_languages'))) {
+                               Logger::info('Unwanted language found', ['language' => $languages[0]]);
+                               return false;
+                       }
+               } elseif (DI::config()->get('system', 'relay_deny_undetected_language')) {
+                       Logger::info('Undetected language found', ['body' => $body]);
+                       return false;
+               }
+
+               return true;
+       }
+
        /**
         * Update or insert a relay contact
         *
         * @param array $gserver Global server record
         * @param array $fields  Optional network specific fields
+        * @return void
         * @throws \Exception
         */
        public static function updateContact(array $gserver, array $fields = [])
@@ -146,7 +192,7 @@ class Relay
                if (in_array($gserver['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN])) {
                        $system = APContact::getByURL($gserver['url'] . '/friendica');
                        if (!empty($system['sharedinbox'])) {
-                               Logger::info('Sucessfully probed for relay contact', ['server' => $gserver['url']]);
+                               Logger::info('Successfully probed for relay contact', ['server' => $gserver['url']]);
                                $id = Contact::updateFromProbeByURL($system['url']);
                                Logger::info('Updated relay contact', ['server' => $gserver['url'], 'id' => $id]);
                                return;
@@ -198,6 +244,7 @@ class Relay
         * The relay contact is a technical contact entry that exists once per server.
         *
         * @param array $contact of the relay contact
+        * @return void
         */
        public static function markForArchival(array $contact)
        {
@@ -229,15 +276,14 @@ class Relay
         * @param integer $item_id  id of the item that is sent
         * @param array   $contacts Previously fetched contacts
         * @param array   $networks Networks of the relay servers
-        *
         * @return array of relay servers
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         */
-       public static function getDirectRelayList(int $item_id)
+       public static function getDirectRelayList(int $item_id): array
        {
                $serverlist = [];
 
-               if (!DI::config()->get("system", "relay_directly", false)) {
+               if (!DI::config()->get('system', 'relay_directly', false)) {
                        return [];
                }
 
@@ -272,7 +318,7 @@ class Relay
                        DBA::close($tagserver);
                }
 
-               // All adresses with the given id
+               // All addresses with the given id
                if (!empty($tagserverlist)) {
                        $servers = DBA::select('gserver', ['id', 'url', 'network'], ['relay-subscribe' => true, 'relay-scope' => 'tags', 'id' => $tagserverlist]);
                        while ($server = DBA::fetch($servers)) {
@@ -302,10 +348,10 @@ class Relay
         * Return a list of relay servers
         *
         * @param array $fields Field list
-        * @return array 
-        * @throws Exception 
+        * @return array List of relay servers
+        * @throws Exception
         */
-       public static function getList($fields = []):array
+       public static function getList(array $fields = []): array
        {
                return DBA::selectToArray('apcontact', $fields,
                        ["`type` = ? AND `url` IN (SELECT `url` FROM `contact` WHERE `uid` = ? AND `rel` = ?)", 'Application', 0, Contact::FRIEND]);
@@ -316,7 +362,7 @@ class Relay
         *
         * @param array $gserver Global server record
         * @param array $fields  Fieldlist
-        * @return array with the contact
+        * @return array|bool Array with the contact or false on error
         * @throws \Exception
         */
        private static function getContact(array $gserver, array $fields = ['batch', 'id', 'url', 'name', 'network', 'protocol', 'archive', 'blocked'])
@@ -344,12 +390,14 @@ class Relay
 
        /**
         * Resubscribe to all relay servers
+        *
+        * @return void
         */
        public static function reSubscribe()
        {
                foreach (self::getList() as $server) {
                        $success = ActivityPub\Transmitter::sendRelayFollow($server['url']);
                        Logger::debug('Resubscribed', ['profile' => $server['url'], 'success' => $success]);
-               }       
+               }
        }
 }