]> git.mxchange.org Git - friendica.git/commitdiff
We can now manage relay servers and can send content to them
authorMichael <heluecht@pirati.ca>
Tue, 15 Sep 2020 17:45:19 +0000 (17:45 +0000)
committerMichael <heluecht@pirati.ca>
Tue, 15 Sep 2020 17:45:19 +0000 (17:45 +0000)
doc/tools.md
src/Console/Relay.php [new file with mode: 0644]
src/Core/Console.php
src/Protocol/ActivityPub/Receiver.php
src/Protocol/ActivityPub/Transmitter.php
src/Worker/Notifier.php

index 8746e9c15021810e5db1f67eae97470a8b6b325f..86be0b492d92469971dba93b7ce429328b9d4453 100644 (file)
@@ -27,6 +27,7 @@ The console provides the following commands:
 * typo:                   Checks for parse errors in Friendica files
 * postupdate:             Execute pending post update scripts (can last days)
 * storage:                Manage storage backend
+* relay:                  Manage ActivityPub relais
 
 Please consult *bin/console help* on the command line interface of your server for details about the commands.
 
diff --git a/src/Console/Relay.php b/src/Console/Relay.php
new file mode 100644 (file)
index 0000000..e1da56d
--- /dev/null
@@ -0,0 +1,150 @@
+<?php
+/**
+ * @copyright Copyright (C) 2020, Friendica
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Console;
+
+use Asika\SimpleConsole\CommandArgsException;
+use Friendica\App;
+use Friendica\Database\DBA;
+use Friendica\Model\APContact;
+use Friendica\Model\Contact;
+use Friendica\Protocol\ActivityPub\Transmitter;
+
+/**
+ * tool to access the system config from the CLI
+ *
+ * With this script you can access the system configuration of your node from
+ * the CLI. You can do both, reading current values stored in the database and
+ * set new values to config variables.
+ *
+ * Usage:
+ *   If you specify no parameters at the CLI, the script will list all config
+ *   variables defined.
+ *
+ *   If you specify one parameter, the script will list all config variables
+ *   defined in this section of the configuration (e.g. "system").
+ *
+ *   If you specify two parameters, the script will show you the current value
+ *   of the named configuration setting. (e.g. "system loglevel")
+ *
+ *   If you specify three parameters, the named configuration setting will be
+ *   set to the value of the last parameter. (e.g. "system loglevel 0" will
+ *   disable logging)
+ */
+class Relay extends \Asika\SimpleConsole\Console
+{
+       protected $helpOptions = ['h', 'help', '?'];
+
+       /**
+        * @var App\Mode
+        */
+       private $appMode;
+
+       protected function getHelp()
+       {
+               $help = <<<HELP
+console relay - Manage ActivityPub relay configuration
+Synopsis
+       bin/console relay [-h|--help|-?] [-v]
+       bin/console relay add <actor> [-h|--help|-?] [-v]
+       bin/console relay remove <actoor> [-h|--help|-?] [-v]
+
+Description
+       bin/console relay
+               Lists all active relais
+
+       bin/console relay add <actor>
+               Add a relay actor
+
+       bin/console relay remove <actoor>
+               Remove a relay actor
+
+Options
+    -h|--help|-? Show help information
+    -v           Show more debug information.
+HELP;
+               return $help;
+       }
+
+       public function __construct(App\Mode $appMode, array $argv = null)
+       {
+               parent::__construct($argv);
+
+               $this->appMode = $appMode;
+       }
+
+       protected function doExecute()
+       {
+               if ($this->getOption('v')) {
+                       $this->out('Executable: ' . $this->executable);
+                       $this->out('Class: ' . __CLASS__);
+                       $this->out('Arguments: ' . var_export($this->args, true));
+                       $this->out('Options: ' . var_export($this->options, true));
+               }
+
+               if (count($this->args) > 2) {
+                       throw new CommandArgsException('Too many arguments');
+               }
+
+               if (count($this->args) == 1) {
+                       throw new CommandArgsException('Too few arguments');
+               }
+
+               if (count($this->args) == 0) {
+                       $contacts = DBA::select('apcontact', ['url'],
+                       ["`type` = ? AND `url` IN (SELECT `url` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?))",
+                               'Application', 0, Contact::FOLLOWER, Contact::FRIEND]);
+                       while ($contact = DBA::fetch($contacts)) {
+                               $this->out($contact['url']);
+                       }
+                       DBA::close($contacts);
+               }
+
+               if (count($this->args) == 2) {
+                       $mode = $this->getArgument(0);
+                       $actor = $this->getArgument(1);
+
+                       $apcontact = APContact::getByURL($actor);
+                       if (empty($apcontact) || ($apcontact['type'] != 'Application')) {
+                               $this->out($actor . ' is no relay actor');
+                               return 1;
+                       }
+
+                       if ($mode == 'add') {
+                               if (Transmitter::sendRelayFollow($actor)) {
+                                       $this->out('Successfully added ' . $actor);
+                               } else {
+                                       $this->out($actor . " couldn't be added");
+                               }
+                       } elseif ($mode == 'remove') {
+                               if (Transmitter::sendRelayUndoFollow($actor)) {
+                                       $this->out('Successfully removed ' . $actor);
+                               } else {
+                                       $this->out($actor . " couldn't be removed");
+                               }
+                       } else {
+                               throw new CommandArgsException($mode . ' is no valid command');
+                       }
+               }
+
+               return 0;
+       }
+}
index e08ea7f422b39db7b5e6f719b5df3a30cee0706d..575a67503312b86b385c9e585224ffd3f986b4dd 100644 (file)
@@ -64,6 +64,7 @@ Commands:
        postupdate             Execute pending post update scripts (can last days)
        serverblock            Manage blocked servers
        storage                Manage storage backend
+       relay                  Manage ActivityPub relais
 
 Options:
        -h|--help|-? Show help information
@@ -92,6 +93,7 @@ HELP;
                'postupdate'             => Friendica\Console\PostUpdate::class,
                'serverblock'            => Friendica\Console\ServerBlock::class,
                'storage'                => Friendica\Console\Storage::class,
+               'relay'                  => Friendica\Console\Relay::class,
        ];
 
        /**
index 05c3abc01b7e27aafc984de4971fcb1007e82106..d5164b5cc326522bd7e5e9bbeb3200343a093c75 100644 (file)
@@ -163,11 +163,13 @@ class Receiver
 
                if ($type != 'as:Announce') {
                        Logger::info('Not an announcement', ['activity' => $activity]);
+                       return;
                }
 
                $object_id = JsonLD::fetchElement($activity, 'as:object', '@id');
                if (empty($object_id)) {
                        Logger::info('No object id found', ['activity' => $activity]);
+                       return;
                }
 
                Logger::info('Got relayed message id', ['id' => $object_id]);
index 91042c06bb963554a4b517a0fd115f20d6dc9af8..dae783bd74d4edb5ac70de55ab89c4eef6c64923 100644 (file)
@@ -61,6 +61,68 @@ require_once 'mod/share.php';
  */
 class Transmitter
 {
+       /**
+        * Add relay servers to the list of inboxes
+        *
+        * @param array $inboxes
+        * @return array inboxes with added relay servers
+        */
+       public static function addRelayServerInboxes(array $inboxes)
+       {
+               $contacts = DBA::select('apcontact', ['inbox'],
+                       ["`type` = ? AND `url` IN (SELECT `url` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?))",
+                               'Application', 0, Contact::FOLLOWER, Contact::FRIEND]);
+               while ($contact = DBA::fetch($contacts)) {
+                       $inboxes[] = $contact['inbox'];
+               }
+               DBA::close($contacts);
+
+               return $inboxes;
+       }
+
+       /**
+        * Subscribe to a relay
+        *
+        * @param string $url Subscribe actor url
+        * @return bool success
+        */
+       public static function sendRelayFollow(string $url)
+       {
+               $contact_id = Contact::getIdForURL($url);
+               if (!$contact_id) {
+                       return false;
+               }
+
+               $activity_id = ActivityPub\Transmitter::activityIDFromContact($contact_id);
+               $success = ActivityPub\Transmitter::sendActivity('Follow', $url, 0, $activity_id);
+               if ($success) {
+                       DBA::update('contact', ['rel' => Contact::FRIEND], ['id' => $contact_id]);
+               }
+
+               return $success;
+       }
+
+       /**
+        * Unsubscribe from a relay
+        *
+        * @param string $url Subscribe actor url
+        * @return bool success
+        */
+       public static function sendRelayUndoFollow(string $url)
+       {
+               $contact_id = Contact::getIdForURL($url);
+               if (!$contact_id) {
+                       return false;
+               }
+
+               $success = self::sendContactUndo($url, $contact_id, 0);
+               if ($success) {
+                       DBA::update('contact', ['rel' => Contact::SHARING], ['id' => $contact_id]);
+               }
+
+               return $success;
+       }
+       
        /**
         * Collects a list of contacts of the given owner
         *
@@ -1917,18 +1979,19 @@ class Transmitter
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         * @throws \ImagickException
         * @throws \Exception
+        * @return bool success
         */
        public static function sendContactUndo($target, $cid, $uid)
        {
                $profile = APContact::getByURL($target);
                if (empty($profile['inbox'])) {
                        Logger::warning('No inbox found for target', ['target' => $target, 'profile' => $profile]);
-                       return;
+                       return false;
                }
 
                $object_id = self::activityIDFromContact($cid);
                if (empty($object_id)) {
-                       return;
+                       return false;
                }
 
                $id = DI::baseUrl() . '/activity/' . System::createGUID();
@@ -1947,7 +2010,7 @@ class Transmitter
                Logger::log('Sending undo to ' . $target . ' for user ' . $uid . ' with id ' . $id, Logger::DEBUG);
 
                $signed = LDSignature::sign($data, $owner);
-               HTTPSignature::transmit($signed, $profile['inbox'], $uid);
+               return HTTPSignature::transmit($signed, $profile['inbox'], $uid);
        }
 
        private static function prependMentions($body, int $uriid)
index 3ee75bbb0af6267ff63ced6a0190d9da80affa84..69b684feb7cbff6b5bd6018a6329710f94ed09b1 100644 (file)
@@ -786,6 +786,11 @@ class Notifier
 
                if ($target_item['origin']) {
                        $inboxes = ActivityPub\Transmitter::fetchTargetInboxes($target_item, $uid);
+
+                       if (in_array($target_item['private'], [Item::PUBLIC])) {
+                               $inboxes = ActivityPub\Transmitter::addRelayServerInboxes($inboxes);
+                       }
+
                        Logger::log('Origin item ' . $target_item['id'] . ' with URL ' . $target_item['uri'] . ' will be distributed.', Logger::DEBUG);
                } elseif (Item::isForumPost($target_item, $owner)) {
                        $inboxes = ActivityPub\Transmitter::fetchTargetInboxes($target_item, $uid, false, 0, true);