From feeea74aea2ddcdf42f7301f995edd23a20827ee Mon Sep 17 00:00:00 2001 From: Jeremy Dormitzer Date: Fri, 25 Jan 2019 21:15:13 -0500 Subject: [PATCH] Require inbox requests to be signed by the activity actor --- src/Controllers/PostController.php | 27 ++++++++++++---- test/Controllers/PostControllerTest.php | 42 ++++++++++++++++++------- 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/Controllers/PostController.php b/src/Controllers/PostController.php index e9eae65..9261862 100644 --- a/src/Controllers/PostController.php +++ b/src/Controllers/PostController.php @@ -51,17 +51,21 @@ class PostController $object = $results[0]; $inboxField = $object->getReferencingField( 'inbox' ); if ( $inboxField ) { - $actorWithInbox = $inboxField->getObject(); + $activity = json_decode( $request->getContent(), true ); + if ( ! $activity || ! array_key_exists( 'actor', $activity ) ) { + throw new BadRequestHttpException(); + } + $activityActor = $this->getActivityActor( $activity ); + if ( ! $activityActor) { + throw new BadRequestHttpException(); + } if ( ! $request->attributes->has( 'signed' ) || - ! $this->authorized( $request, $actorWithInbox ) ) { + ! $this->authorized( $request, $activityActor ) ) { throw new UnauthorizedHttpException( 'Signature realm="ActivityPub",headers="(request-target) host date"' ); } - $activity = json_decode( $request->getContent(), true ); - if ( ! $activity ) { - throw new BadRequestHttpException(); - } + $actorWithInbox = $inboxField->getObject(); $event = new InboxActivityEvent( $activity, $actorWithInbox, $request ); $this->eventDispatcher->dispatch( InboxActivityEvent::NAME, $event ); return; @@ -85,6 +89,17 @@ class PostController throw new MethodNotAllowedHttpException( array( Request::METHOD_GET ) ); } + private function getActivityActor( array $activity ) + { + xdebug_break(); + $actor = $activity['actor']; + if ( is_array( $actor ) && array_key_exists( 'id', $actor ) ) { + return $this->objectsService->dereference( $actor['id'] ); + } else if ( is_string( $actor ) ) { + return $this->objectsService->dereference( $actor ); + } + } + private function authorized( Request $request, ActivityPubObject $activityActor ) { if ( ! $request->attributes->has( 'actor' ) ) { diff --git a/test/Controllers/PostControllerTest.php b/test/Controllers/PostControllerTest.php index 13687ec..e90c124 100644 --- a/test/Controllers/PostControllerTest.php +++ b/test/Controllers/PostControllerTest.php @@ -31,6 +31,9 @@ class PostControllerTest extends TestCase 'id' => 'https://example.com/actor/1/outbox', ), ), + 'https://elsewhere.com/actor/1' => array( + 'id' => 'https://elsewhere.com/actor/1', + ), ); const REFS = array( 'https://example.com/actor/1/inbox' => array( @@ -67,34 +70,46 @@ class PostControllerTest extends TestCase } } ) ); + $objectsService->method( 'dereference' )->will( + $this->returnCallback( function( $id ) { + if ( array_key_exists( $id, self::OBJECTS ) ) { + return TestActivityPubObject::fromArray( self::OBJECTS[$id] ); + } else { + return null; + } + } ) + ); $testCases = array( array( 'id' => 'basicInboxTest', 'request' => $this->makeRequest( 'https://example.com/actor/1/inbox', Request::METHOD_POST, - '{"type": "Create"}', + '{"type": "Create", "actor": "https://elsewhere.com/actor/1"}', array( 'signed' => true, 'actor' => TestActivityPubObject::fromArray( - self::OBJECTS['https://example.com/actor/1'] + self::OBJECTS['https://elsewhere.com/actor/1'] ), ) ), 'expectedEventName' => InboxActivityEvent::NAME, 'expectedEvent' => new InboxActivityEvent( - array( 'type' => 'Create' ), + array( + 'type' => 'Create', + 'actor' => 'https://elsewhere.com/actor/1' + ), TestActivityPubObject::fromArray( self::OBJECTS['https://example.com/actor/1'] ), $this->makeRequest( 'https://example.com/actor/1/inbox', Request::METHOD_POST, - '{"type": "Create"}', + '{"type": "Create", "actor": "https://elsewhere.com/actor/1"}', array( 'signed' => true, 'actor' => TestActivityPubObject::fromArray( - self::OBJECTS['https://example.com/actor/1'] + self::OBJECTS['https://elsewhere.com/actor/1'] ), ) ) @@ -135,10 +150,10 @@ class PostControllerTest extends TestCase 'request' => $this->makeRequest( 'https://example.com/actor/1/inbox', Request::METHOD_POST, - '{"type": "Create"}', + '{"type": "Create", "actor": "https://elsewhere.com/actor/1"}', array( 'actor' => TestActivityPubObject::fromArray( - self::OBJECTS['https://example.com/actor/1'] + self::OBJECTS['https://elsewhere.com/actor/1'] ), ) ), @@ -149,7 +164,7 @@ class PostControllerTest extends TestCase 'request' => $this->makeRequest( 'https://example.com/actor/1/inbox', Request::METHOD_POST, - '{"type": "Create"}', + '{"type": "Create", "actor": "https://elsewhere.com/actor/1"}', array() ), 'expectedException' => UnauthorizedHttpException::class, @@ -159,10 +174,11 @@ class PostControllerTest extends TestCase 'request' => $this->makeRequest( 'https://example.com/actor/notreal/inbox', Request::METHOD_POST, - '{"type": "Create"}', + '{"type": "Create", "actor": "https://elsewhere.com/actor/1"}', array( + 'signed' => true, 'actor' => TestActivityPubObject::fromArray( - self::OBJECTS['https://example.com/actor/1'] + self::OBJECTS['https://elsewhere.com/actor/1'] ), ) ), @@ -175,8 +191,9 @@ class PostControllerTest extends TestCase Request::METHOD_POST, '', array( + 'signed' => true, 'actor' => TestActivityPubObject::fromArray( - self::OBJECTS['https://example.com/actor/1'] + self::OBJECTS['https://elsewhere.com/actor/1'] ), ) ), @@ -189,8 +206,9 @@ class PostControllerTest extends TestCase Request::METHOD_POST, 'this is not JSON', array( + 'signed' => 'true', 'actor' => TestActivityPubObject::fromArray( - self::OBJECTS['https://example.com/actor/1'] + self::OBJECTS['https://elsewhere.com/actor/1'] ), ) ),