From a5796f9e62a8430a45f037ba2b6aa73f072e318d Mon Sep 17 00:00:00 2001 From: Jeremy Dormitzer Date: Mon, 28 Jan 2019 09:41:18 -0500 Subject: [PATCH] Add a global prefix to generated ids --- src/Config/ActivityPubConfig.php | 24 +++++++++++++---- src/Config/ActivityPubConfigBuilder.php | 35 +++++++++++++++++++++++++ src/Config/ActivityPubModule.php | 3 ++- src/Objects/IdProvider.php | 18 ++++++++++--- test/Objects/IdProviderTest.php | 27 ++++++++++--------- 5 files changed, 86 insertions(+), 21 deletions(-) diff --git a/src/Config/ActivityPubConfig.php b/src/Config/ActivityPubConfig.php index 9fa1f56..25f7cd1 100644 --- a/src/Config/ActivityPubConfig.php +++ b/src/Config/ActivityPubConfig.php @@ -34,6 +34,11 @@ class ActivityPubConfig */ private $jsonLdContext; + /** + * @var string + */ + private $idPathPrefix; + /** * Don't call this directly - instead, use * ActivityPubConfig->createBuilder()->build() @@ -47,6 +52,7 @@ class ActivityPubConfig $this->dbPrefix = $builder->getDbPrefix(); $this->authFunction = $builder->getAuthFunction(); $this->jsonLdContext = $builder->getJsonLdContext(); + $this->idPathPrefix = $builder->getIdPathPrefix(); } public function createBuilder() @@ -55,7 +61,7 @@ class ActivityPubConfig } /** - * @var array + * @return array */ public function getDbConnectionParams() { @@ -63,7 +69,7 @@ class ActivityPubConfig } /** - * @var bool + * @return bool */ public function getIsDevMode() { @@ -71,7 +77,7 @@ class ActivityPubConfig } /** - * @var string + * @return string */ public function getDbPrefix() { @@ -80,7 +86,7 @@ class ActivityPubConfig } /** - * @var Callable + * @return Callable */ public function getAuthFunction() { @@ -88,11 +94,19 @@ class ActivityPubConfig } /** - * @var array + * @return array */ public function getJsonLdContext() { return $this->jsonLdContext; } + + /** + * @return string + */ + public function getIdPathPrefix() + { + return $this->idPathPrefix; + } } ?> diff --git a/src/Config/ActivityPubConfigBuilder.php b/src/Config/ActivityPubConfigBuilder.php index 35e8ac0..57fb37f 100644 --- a/src/Config/ActivityPubConfigBuilder.php +++ b/src/Config/ActivityPubConfigBuilder.php @@ -3,6 +3,7 @@ namespace ActivityPub\Config; use ActivityPub\Config\ActivityPubConfig; use ActivityPub\Objects\ContextProvider; +use ActivityPub\Objects\IdProvider; /** * The ActivityPubConfigBuilder is a builder class to create ActivityPub config data @@ -19,6 +20,8 @@ use ActivityPub\Objects\ContextProvider; */ class ActivityPubConfigBuilder { + const DEFAULT_ID_PATH_PREFIX = 'ap'; + /** * @var array */ @@ -44,6 +47,11 @@ class ActivityPubConfigBuilder */ private $jsonLdContext; + /** + * @var string + */ + private $idPathPrefix; + /** * Creates a new ActivityPubConfig instance with default values * @@ -57,6 +65,7 @@ class ActivityPubConfigBuilder return false; }; $this->jsonLDContext = ContextProvider::DEFAULT_CONTEXT; + $this->idPathPrefix = IdProvider::DEFAULT_ID_PATH_PREFIX; } /** @@ -191,9 +200,35 @@ class ActivityPubConfigBuilder return $this; } + /** + * @return array + */ public function getJsonLdContext() { return $this->jsonLdContext; } + + /** + * The `idPathPrefix` is a string that is prepended to all ids generated by + * by the ActivityPub library. For example, if the `idPathPrefix` is 'ap', + * the library will generate ids that look like 'https://example.com/ap/note/1'. + * + * Default: 'ap' + * @param string $idPathPrefix The id path prefix + * @return ActivityPubConfigBuilder The builder instance + */ + public function setIdPathPrefix( string $idPathPrefix ) + { + $this->idPathPrefix = $idPathPrefix; + return $this; + } + + /** + * @return string + */ + public function getIdPathPrefix() + { + return $this->idPathPrefix; + } } ?> diff --git a/src/Config/ActivityPubModule.php b/src/Config/ActivityPubModule.php index 96f622e..c5eeeb7 100644 --- a/src/Config/ActivityPubModule.php +++ b/src/Config/ActivityPubModule.php @@ -88,7 +88,8 @@ class ActivityPubModule $this->injector->register( IdProvider::class, IdProvider::class ) ->addArgument( new Reference( ObjectsService::class ) ) - ->addArgument( new Reference( RandomProvider::class ) ); + ->addArgument( new Reference( RandomProvider::class ) ) + ->addArgument( $config->getIdPathPrefix() ); $this->injector->register( GetController::class, GetController::class ) ->addArgument( new Reference( ObjectsService::class ) ) diff --git a/src/Objects/IdProvider.php b/src/Objects/IdProvider.php index 732adbe..489a09f 100644 --- a/src/Objects/IdProvider.php +++ b/src/Objects/IdProvider.php @@ -10,6 +10,7 @@ use Symfony\Component\HttpFoundation\Request; */ class IdProvider { + const DEFAULT_ID_PATH_PREFIX = 'ap'; const ID_LENGTH = 12; /** @@ -22,10 +23,21 @@ class IdProvider */ private $randomProvider; - public function __construct( ObjectsService $objectsService, RandomProvider $randomProvider ) + /** + * $pathPrefix gets prepended to all generated id paths + * + * It should not have a leading or a trailing slash. + * @var string + */ + private $pathPrefix; + + public function __construct( ObjectsService $objectsService, + RandomProvider $randomProvider, + string $pathPrefix ) { $this->objectsService = $objectsService; $this->randomProvider = $randomProvider; + $this->pathPrefix = $pathPrefix; } /** @@ -34,14 +46,14 @@ class IdProvider * Ids look like "https://$host/$path/$randomString" * @param Request $request The current request * @param string $path The path for the the id URL, just before the random string - * Default: "object" + * and after the path prefix. Default: "object" * @return string The new id */ public function getId( Request $request, string $path = "objects" ) { $baseUri = $request->getSchemeAndHttpHost(); if ( ! empty( $path ) ) { - $baseUri = $baseUri . "/$path"; + $baseUri = $baseUri . "/{$this->pathPrefix}/$path"; } $rnd = $this->randomProvider->randomString( self::ID_LENGTH ); $id = $baseUri . "/$rnd"; diff --git a/test/Objects/IdProviderTest.php b/test/Objects/IdProviderTest.php index bbe3ffa..8bfedad 100644 --- a/test/Objects/IdProviderTest.php +++ b/test/Objects/IdProviderTest.php @@ -16,14 +16,17 @@ class IdProviderTest extends TestCase public function setUp() { $this->objectsService = $this->createMock( ObjectsService::class ); - $this->objectsService->method( 'query' )->will( $this->returnCallback( function( $query) { - $existsId = sprintf( 'https://example.com/objects/%s', self::EXISTING_ID_STR ); - if ( array_key_exists( 'id', $query ) && $query['id'] == $existsId ) { - return array( 'existingObject' ); - } else { - return array(); - } - } ) ); + $this->objectsService->method( 'query' ) + ->will( $this->returnCallback( function( $query) { + $existsId = sprintf( + 'https://example.com/ap/objects/%s', self::EXISTING_ID_STR + ); + if ( array_key_exists( 'id', $query ) && $query['id'] == $existsId ) { + return array( 'existingObject' ); + } else { + return array(); + } + } ) ); } public function testIdProvider() @@ -32,18 +35,18 @@ class IdProviderTest extends TestCase array( 'id' => 'providesId', 'providedRnd' => array( 'foo' ), - 'expectedId' => 'https://example.com/objects/foo', + 'expectedId' => 'https://example.com/ap/objects/foo', ), array( 'id' => 'checksForExisting', 'providedRnd' => array( self::EXISTING_ID_STR, 'bar' ), - 'expectedId' => 'https://example.com/objects/bar', + 'expectedId' => 'https://example.com/ap/objects/bar', ), array( 'id' => 'addsPath', 'providedRnd' => array( 'foo' ), 'path' => 'notes', - 'expectedId' => 'https://example.com/notes/foo', + 'expectedId' => 'https://example.com/ap/notes/foo', ), ); foreach ( $testCases as $testCase ) { @@ -52,7 +55,7 @@ class IdProviderTest extends TestCase array( $randomProvider->method( 'randomString' ), 'willReturnOnConsecutiveCalls' ), $testCase['providedRnd'] ); - $idProvider = new IdProvider( $this->objectsService, $randomProvider ); + $idProvider = new IdProvider( $this->objectsService, $randomProvider, 'ap' ); $request = Request::create( 'https://example.com' ); $id = ''; if ( array_key_exists( 'path', $testCase ) ) {