activitypub-1.0.x-dev/src/EventSubscriber/WebfingerProfileSubscriber.php
src/EventSubscriber/WebfingerProfileSubscriber.php
<?php
namespace Drupal\activitypub\EventSubscriber;
use Drupal\activitypub\Services\ActivityPubUtilityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Url;
use Drupal\user\UserInterface;
use Drupal\webfinger\Event\WebfingerResponseEvent;
use Drupal\webfinger\JsonRdLink;
use Drupal\webfinger\WebfingerEvents;
use Drupal\webfinger\WebfingerParameters;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Language\Language;
/**
* Webfinger subscriber.
*/
class WebfingerProfileSubscriber implements EventSubscriberInterface {
/**
* The user storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $userStorage;
/**
* The actor storage.
*
* @var \Drupal\activitypub\Entity\Storage\ActivityPubActorStorageInterface
*/
protected $actorStorage;
/**
* A logger instance.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* The ActivityPub Utility service
*
* @var \Drupal\activitypub\Services\ActivityPubUtilityInterface
*/
protected $activityPubUtility;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* WebfingerProfileSubscriber constructor
*
* @param \Drupal\activitypub\Services\ActivityPubUtilityInterface $activitypub_utility
* The Activitypub utility service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager service.
* @param \Psr\Log\LoggerInterface $logger
* A logger instance.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function __construct(ActivityPubUtilityInterface $activitypub_utility, EntityTypeManagerInterface $entity_type_manager, LoggerInterface $logger, LanguageManagerInterface $language_manager) {
$this->activityPubUtility = $activitypub_utility;
$this->userStorage = $entity_type_manager->getStorage('user');
$this->actorStorage = $entity_type_manager->getStorage('activitypub_actor');
$this->languageManager = $language_manager;
$this->logger = $logger;
}
/**
* Builds a profile response.
*
* @param \Drupal\webfinger\Event\WebfingerResponseEvent $event
* The event to process.
*
* @throws \Exception
*/
public function onBuildResponseBuildProfile(WebfingerResponseEvent $event) {
$undefined_lang = $this->languageManager->getLanguage(Language::LANGCODE_NOT_SPECIFIED);
$json_rd = $event->getJsonRd();
$request = $event->getRequest();
$params = $event->getParams();
$response_cacheability = $event->getResponseCacheability();
$subject = $request->query->get('resource') ?: '';
if (!empty($subject)) {
$json_rd->setSubject($subject);
}
// Determine if there is a user account path for a requested name.
if (isset($params[WebfingerParameters::ACCOUNT_KEY_NAME]) && ($actor = $this->getActor($params[WebfingerParameters::ACCOUNT_KEY_NAME])) && ($user = $this->getUserByUid($actor->getOwnerId()))) {
$response_cacheability->addCacheContexts(['user']);
$url = Url::fromRoute('entity.user.canonical', ['user' => $user->id()], ['absolute' => TRUE, 'language' => $undefined_lang])->toString(TRUE);
$response_cacheability->addCacheableDependency($url);
$account_href = $url->getGeneratedUrl();
// Add alias if it's still empty.
if (empty($json_rd->getAliases())) {
$json_rd->addAlias($account_href);
}
$add_profile_link = TRUE;
$links = $json_rd->getLinks();
/** @var JsonRdLink $link */
foreach ($links as $link) {
if ($link->getRel() == 'http://webfinger.net/rel/profile-page') {
$add_profile_link = FALSE;
}
}
if ($add_profile_link) {
$link = new JsonRdLink();
$link->setRel('http://webfinger.net/rel/profile-page')
->setType('text/html')
->setHref($account_href);
$json_rd->addLink($link);
}
$url = Url::fromRoute('activitypub.user.self', ['user' => $user->id(), 'activitypub_actor' => $actor->getName()], ['absolute' => TRUE])->toString(TRUE);
$response_cacheability->addCacheableDependency($url);
$self_href = $url->getGeneratedUrl();
$link = new JsonRdLink();
$link->setRel('self')
->setType('application/activity+json')
->setHref($self_href);
$json_rd->addLink($link);
if ($image_style_url = $this->activityPubUtility->getActivityPubUserImage($user)) {
$link = new JsonRdLink();
$link->setRel('http://webfinger.net/rel/avatar')
->setHref($image_style_url);
$json_rd->addLink($link);
}
$interaction_link = $event->getRequest()->getSchemeAndHttpHost().$event->getRequest()->getBasePath() . '/activitypub/authorize_interaction?uri={uri}';
$link = new JsonRdLink();
$link->setRel("http://ostatus.org/schema/1.0/subscribe")
->setType('template')
->setHref($interaction_link);
$json_rd->addLink($link);
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
$events[WebfingerEvents::WEBFINGER_BUILD_RESPONSE][] = ['onBuildResponseBuildProfile', 10];
return $events;
}
/**
* Get the actor by name.
*
* @param $name
*
* @return \Drupal\activitypub\Entity\ActivityPubActorInterface|NULL
*/
protected function getActor($name) {
return $this->actorStorage->loadActorByName($name);
}
/**
* Gets the user.
*
* @param int $uid
* The uid of a requested account.
* @return \Drupal\user\UserInterface|null
* A fully-loaded user object upon successful user load or FALSE if user
* cannot be loaded
*/
protected function getUserByUid($uid): ?UserInterface {
/** @var \Drupal\user\UserInterface $user */
$user = $this->userStorage->load($uid);
return $user ? $user : NULL;
}
}
