From cb3abbdc3c163ec067aa04e70e1389adbd5bfb8b Mon Sep 17 00:00:00 2001 From: Jeremy Dormitzer Date: Sat, 27 Apr 2019 16:03:41 -0400 Subject: [PATCH] Implement activity forwarding --- .../ActivityPersister.php | 3 + src/ActivityEventHandlers/DeliveryHandler.php | 63 ++++++++++++++++++- src/Objects/ObjectsService.php | 4 +- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/ActivityEventHandlers/ActivityPersister.php b/src/ActivityEventHandlers/ActivityPersister.php index 114d092..ae063a1 100644 --- a/src/ActivityEventHandlers/ActivityPersister.php +++ b/src/ActivityEventHandlers/ActivityPersister.php @@ -45,6 +45,9 @@ class ActivityPersister implements EventSubscriberInterface public function persistActivityToInbox( InboxActivityEvent $event ) { $activity = $event->getActivity(); + if ( ! $this->objectsService->getObject( $activity['id'] ) ) { + $event->getRequest()->attributes->set( 'firstTimeSeen', true ); + } $receivingActor = $event->getReceivingActor(); if ( $receivingActor->hasField( 'inbox' ) ) { $this->collectionsService->addItem( $receivingActor['inbox'], $activity ); diff --git a/src/ActivityEventHandlers/DeliveryHandler.php b/src/ActivityEventHandlers/DeliveryHandler.php index 08daedb..09e5717 100644 --- a/src/ActivityEventHandlers/DeliveryHandler.php +++ b/src/ActivityEventHandlers/DeliveryHandler.php @@ -7,6 +7,7 @@ use ActivityPub\Entities\ActivityPubObject; use ActivityPub\Objects\CollectionIterator; use ActivityPub\Objects\ObjectsService; use ActivityPub\Utils\DateTimeProvider; +use ActivityPub\Utils\Util; use GuzzleHttp\Client; use GuzzleHttp\Psr7\Request; use Psr\Log\LoggerInterface; @@ -62,7 +63,52 @@ class DeliveryHandler implements EventSubscriberInterface public function handleInboxForwarding( InboxActivityEvent $event ) { - + // Forward the activity if: + // - this is the first time we've seen the activity + // - AND the values of to, cc, or audience contain a Collection that we own + // - AND (according to Kaninii) if the 'object' of the activity is NOT an actor + // - AND the values of inReplyTo, object, target, or tag are objects that we own, recursing through + // the objects in these value chains up to some reasonable limit + $activity = $event->getActivity(); + if ( ! $event->getRequest()->attributes->get( 'firstTimeSeen' ) ) { + $this->logger->debug( + 'Not forwarding activity because we\'ve seen it before', array( 'activity' => $activity ) + ); + return; + } + if ( array_key_exists( 'object', $activity ) && $this->isActor( $activity['object'] ) ) { + $this->logger->debug( + 'Not forwarding activity with an actor as its object', array( 'activity' => $activity ) + ); + return; + } + $forwardingTargets = array(); + $recipients = array_intersect( $activity, array_flip( array( 'to', 'cc', 'audience' ) ) ); + foreach ( $recipients as $recip ) { + $recipId = $recip; + if ( is_array( $recipId ) && array_key_exists( 'id', $recipId ) ) { + $recipId = $recipId['id']; + } + if ( is_string( $recipId ) ) { + $recipient = $this->objectsService->dereference( $recipId ); + if ( + $recipient->hasField( 'type' ) && + in_array( $recipient['type'], array( 'Collection', 'OrderedCollection') ) && + Util::isLocalUri( $recipient['id'] ) + ) { + $forwardingTargets = array_unique( array_merge( + $forwardingTargets, $this->resolveRecipient( $recipient ) + ) ); + } + } + } + if ( count( $forwardingTargets ) === 0 ) { + $this->logger->debug( + 'No collections we own in recipients, not forwarding', array( 'activity' => $activity ) + ); + return; + } + // TODO recurse through inReplyTo, object, target, and tags looking for object we own } public function deliverActivity( OutboxActivityEvent $event ) @@ -169,4 +215,19 @@ class DeliveryHandler implements EventSubscriberInterface } return array(); } + + private function isActor( $objectId ) + { + if ( is_array( $objectId ) && array_key_exists( 'id', $objectId ) ) { + $objectId = $objectId['id']; + } + if ( ! is_string( $objectId ) ) { + return false; + } + $object = $this->objectsService->dereference( $objectId ); + if ( ! $object ) { + return false; + } + return $object->hasField( 'inbox' ) && $object->hasField( 'outbox' ); + } } \ No newline at end of file diff --git a/src/Objects/ObjectsService.php b/src/Objects/ObjectsService.php index 436d2c8..66505b7 100644 --- a/src/Objects/ObjectsService.php +++ b/src/Objects/ObjectsService.php @@ -68,13 +68,13 @@ class ObjectsService /** * Gets an object from the DB by its ActivityPub id * - * For internal use only - external callers should use dereference() + * You probably want dereference() instead of this. * * @param string $id The object's id * @return ActivityPubObject|null The object or null * if no object exists with that id */ - protected function getObject( $id ) + public function getObject( $id ) { $results = $this->query( array( 'id' => $id ) ); if ( !empty( $results ) ) {