From 8939581cce315400a92de4e447c8fa5e767edf5f Mon Sep 17 00:00:00 2001 From: landrok Date: Fri, 5 Apr 2024 14:06:39 +0200 Subject: [PATCH] [Fix] Actor: add missing Server injection in WebFinger discovery --- src/ActivityPhp/Server/Actor.php | 25 +++++------ src/ActivityPhp/Server/Actor/ActorFactory.php | 23 +++++----- src/ActivityPhp/Server/Actor/Outbox.php | 43 ++++++++++--------- .../Server/Http/WebFingerFactory.php | 12 +++--- src/ActivityPhp/Type/Ontology/Mastodon.php | 5 +++ 5 files changed, 57 insertions(+), 51 deletions(-) diff --git a/src/ActivityPhp/Server/Actor.php b/src/ActivityPhp/Server/Actor.php index a48ec75..7e3c17e 100644 --- a/src/ActivityPhp/Server/Actor.php +++ b/src/ActivityPhp/Server/Actor.php @@ -19,7 +19,7 @@ /** * A server-oriented actor object - */ + */ class Actor { /** @@ -36,7 +36,7 @@ class Actor * Construct an Actor instance based upon a WebFinger discovery if * an handle-like is provided. Otherwise, it checks an ActivityPhp * profile id if it's an URL. - * + * * @param string $handle URL or a WebFinger handle * @param \ActivityPhp\Server $server */ @@ -45,12 +45,13 @@ public function __construct(string $handle, Server $server) $this->server = $server; $url = null; + WebFinger::setServer($this->server); + // Is a valid handle? if ($this->isHandle($handle)) { // testing only $scheme = $this->server->config('instance.debug') ? 'http' : 'https'; - WebFinger::setServer($this->server); $webfinger = WebFinger::get($handle, $scheme); $url = $webfinger->getProfileId(); // Is an id? @@ -69,7 +70,7 @@ public function __construct(string $handle, Server $server) /** * Check that a string is a valid handle - * + * * @param string $handle * @return bool */ @@ -94,7 +95,7 @@ private function createActor(string $url) /** * Get ActivityStream Actor - * + * * @param null|string $property * @return \ActivityPhp\Type\Extended\AbstractActor * | string @@ -111,20 +112,20 @@ public function get($property = null) /** * Get Actor's public key PEM - * + * * @return string|null */ public function getPublicKeyPem() { - if (!isset($this->actor->publicKey) - || !is_array($this->actor->publicKey) - || !isset($this->actor->publicKey['publicKeyPem']) + if (! isset($this->actor->publicKey) + || ! is_array($this->actor->publicKey) + || ! isset($this->actor->publicKey['publicKeyPem']) ) { $this->server->logger()->info( 'Public key not found', [$this->actor->toArray()] ); - return false; + return false; } return $this->actor->publicKey['publicKeyPem']; @@ -132,7 +133,7 @@ public function getPublicKeyPem() /** * Get WebFinger bound to a profile - * + * * @return \ActivityPhp\Server\Http\WebFinger */ public function webfinger() @@ -141,7 +142,7 @@ public function webfinger() $scheme = $this->server->config('instance.debug') ? 'http' : 'https'; - $port = !is_null(parse_url($this->actor->id, PHP_URL_PORT)) + $port = ! is_null(parse_url($this->actor->id, PHP_URL_PORT)) ? ':' . parse_url($this->actor->id, PHP_URL_PORT) : ''; diff --git a/src/ActivityPhp/Server/Actor/ActorFactory.php b/src/ActivityPhp/Server/Actor/ActorFactory.php index 46c8b52..b162045 100644 --- a/src/ActivityPhp/Server/Actor/ActorFactory.php +++ b/src/ActivityPhp/Server/Actor/ActorFactory.php @@ -17,7 +17,7 @@ use Exception; /** - * \ActivityPhp\Server\ActorFactory provides a factory for server-side + * \ActivityPhp\Server\ActorFactory provides a factory for server-side * actor. */ abstract class ActorFactory @@ -29,7 +29,7 @@ abstract class ActorFactory /** * Create an actor from its profile url - * + * * @param string $url * @return \ActivityPhp\Type\Extended\AbstractActor * @throws \Exception if actor does not exist @@ -42,8 +42,7 @@ public static function create(string $url) ) { return self::createLocalActor($url); } - - + $content = json_decode( (new Request( self::$server->config('http.timeout'), @@ -52,9 +51,9 @@ public static function create(string $url) true ); - if (!is_array($content) - || !count($content) - || !isset($content['type']) + if (! is_array($content) + || ! count($content) + || ! isset($content['type']) ) { throw new Exception('Actor fetching failed'); } @@ -66,7 +65,7 @@ public static function create(string $url) // ActivityPhp profile foreach (['id', 'preferredUsername'] as $property) { if ($actor->has($property) - && !is_null($actor->$property) + && ! is_null($actor->$property) ) { continue; } @@ -81,7 +80,7 @@ public static function create(string $url) /** * Inject a server instance - * + * * @param \ActivityPhp\Server $server */ public static function setServer(Server $server) @@ -91,7 +90,7 @@ public static function setServer(Server $server) /** * Create an actor type from a profile id - * + * * @param string $url * @return string */ @@ -106,7 +105,7 @@ public static function createLocalActor(string $url) /** * Parse an actor handle from a profile id - * + * * @param string $url * @return string */ @@ -119,7 +118,7 @@ public static function extractHandle(string $url) $pattern ); - if (!preg_match("#{$pattern}#", $url, $matches)) { + if (! preg_match("#{$pattern}#", $url, $matches)) { throw new Exception( sprintf( 'Failed to extract username from URL "%s", pattern="%s"', diff --git a/src/ActivityPhp/Server/Actor/Outbox.php b/src/ActivityPhp/Server/Actor/Outbox.php index d35210a..9c37968 100644 --- a/src/ActivityPhp/Server/Actor/Outbox.php +++ b/src/ActivityPhp/Server/Actor/Outbox.php @@ -1,5 +1,7 @@ server->logger()->info( - $this->actor->webfinger()->getHandle() . ':' . __METHOD__, + $this->actor->webfinger()->getHandle() . ':' . __METHOD__, [$url] ); @@ -60,12 +61,12 @@ public function getPage(string $url) /** * Fetch an outbox - * + * * @return \ActivityPhp\Type\Core\OrderedCollection */ public function get() { - if (!is_null($this->orderedCollection)) { + if (! is_null($this->orderedCollection)) { return $this->orderedCollection; } @@ -74,25 +75,25 @@ public function get() ); $url = $this->actor->get('outbox'); - + if (is_null($url)) { $this->server->logger()->warning( - $this->actor->webfinger()->getHandle() + $this->actor->webfinger()->getHandle() . ': Outbox is not defined' ); return; - } - + } + $this->orderedCollection = Type::create( Helper::fetch($url) ); - + return $this->orderedCollection; } /** * Post a message to the world - * + * * @param \Symfony\Component\HttpFoundation\Request $request * @return \Symfony\Component\HttpFoundation\Response */ @@ -106,8 +107,8 @@ public function post(Request $request) ); // Check current actor can post - - + + // Get content $payload = Util::decodeJson( (string)$request->getContent() @@ -125,10 +126,10 @@ public function post(Request $request) return new Response('', 400); } - + // Log $this->getServer()->logger()->debug( - $this->actor->get()->preferredUsername. ':' . __METHOD__ . '(starting)', + $this->actor->get()->preferredUsername. ':' . __METHOD__ . '(starting)', $activity->toArray() ); @@ -137,9 +138,9 @@ public function post(Request $request) $activity = $this->wrapObject($activity); } - // Clients submitting the following activities to an outbox MUST - // provide the object property in the activity: - // Create, Update, Delete, Follow, + // Clients submitting the following activities to an outbox MUST + // provide the object property in the activity: + // Create, Update, Delete, Follow, // Add, Remove, Like, Block, Undo if (!isset($activity->object)) { throw new Exception( @@ -172,7 +173,7 @@ public function post(Request $request) // Log $this->getServer()->logger()->debug( - $this->actor->get()->preferredUsername. ':' . __METHOD__ . '(posted)', + $this->actor->get()->preferredUsername. ':' . __METHOD__ . '(posted)', $activity->toArray() ); diff --git a/src/ActivityPhp/Server/Http/WebFingerFactory.php b/src/ActivityPhp/Server/Http/WebFingerFactory.php index a7cae0f..cde19d5 100644 --- a/src/ActivityPhp/Server/Http/WebFingerFactory.php +++ b/src/ActivityPhp/Server/Http/WebFingerFactory.php @@ -17,7 +17,7 @@ /** * A simple WebFinger discoverer tool - */ + */ class WebFingerFactory { const WEBFINGER_URL = '%s://%s%s/.well-known/webfinger?resource=acct:%s'; @@ -28,14 +28,14 @@ class WebFingerFactory protected static $server; /** - * @var array An array of key => value. + * @var array An array of key => value. * Keys are handle, values are WebFinger instances. */ protected static $webfingers = []; /** * Get a profile via WebFinger protocol - * + * * @param string $handle * @param string $scheme Only for testing purpose * @return \ActivityPhp\Server\Http\WebFinger @@ -43,7 +43,7 @@ class WebFingerFactory */ public static function get(string $handle, string $scheme = 'https') { - if (!preg_match( + if (! preg_match( '/^@?(?P[\w\-\.]+)@(?P[\w\.\-]+)(?P:[\d]+)?$/', $handle, $matches @@ -74,7 +74,7 @@ public static function get(string $handle, string $scheme = 'https') ))->get($url) ); - if (!is_array($content) || !count($content)) { + if (! is_array($content) || ! count($content)) { throw new Exception('WebFinger fetching has failed'); } @@ -85,7 +85,7 @@ public static function get(string $handle, string $scheme = 'https') /** * Inject a server instance - * + * * @param \ActivityPhp\Server $server */ public static function setServer(Server $server) diff --git a/src/ActivityPhp/Type/Ontology/Mastodon.php b/src/ActivityPhp/Type/Ontology/Mastodon.php index 924daef..30f8edb 100644 --- a/src/ActivityPhp/Type/Ontology/Mastodon.php +++ b/src/ActivityPhp/Type/Ontology/Mastodon.php @@ -35,6 +35,11 @@ abstract class Mastodon extends OntologyBase 'height', 'focalPoint', ], + 'Emoji' => [ + 'name', + 'updated', + 'icon', + ], 'Hashtag' => [ 'href' ],