diff --git a/.gitignore b/.gitignore index ec1c218c..205c5938 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ js/ node_modules/ vendor/ img/twemoji/ +composer/* +!composer/composer.json +!composer/composer.lock diff --git a/Makefile b/Makefile index 6622d868..c83a940f 100644 --- a/Makefile +++ b/Makefile @@ -64,9 +64,9 @@ clean: clean-dev: rm -rf node_modules -# composer packages -composer: - composer install --prefer-dist +build-composer: + composer install --prefer-dist --working-dir composer + composer update --prefer-dist --working-dir composer # releasing to github release: appstore github-release github-upload @@ -88,7 +88,7 @@ github-upload: --file $(build_dir)/$(app_name)-$(version).tar.gz # creating .tar.gz + signature -appstore: dev-setup lint build-js-production composer +appstore: dev-setup lint build-js-production build-composer mkdir -p $(sign_dir) rsync -a \ --exclude=/build \ @@ -101,8 +101,8 @@ appstore: dev-setup lint build-js-production composer --exclude=/.babelrc.js \ --exclude=/.drone.yml \ --exclude=/.eslintrc.js \ - --exclude=/composer.json \ - --exclude=/composer.lock \ + --exclude=/composer/composer.json \ + --exclude=/composer/composer.lock \ --exclude=/src \ --exclude=/node_modules \ --exclude=/webpack.*.js \ diff --git a/appinfo/app.php b/appinfo/app.php deleted file mode 100644 index 5a8c2071..00000000 --- a/appinfo/app.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @copyright 2018, Maxence Lange - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\Social\AppInfo; - - -require_once __DIR__ . '/autoload.php'; - - -/** @var Application $app */ -$app = \OC::$server->query(Application::class); - -$app->checkUpgradeStatus(); - - diff --git a/appinfo/autoload.php b/appinfo/autoload.php deleted file mode 100644 index 3427325f..00000000 --- a/appinfo/autoload.php +++ /dev/null @@ -1,37 +0,0 @@ - - * @copyright 2018, Maxence Lange - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\Social\AppInfo; - -$composerDir = __DIR__ . '/../vendor/'; - -if (is_dir($composerDir) && file_exists($composerDir . 'autoload.php')) { - require_once $composerDir . 'autoload.php'; -} - diff --git a/appinfo/info.xml b/appinfo/info.xml index 70e44372..84a72e5b 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -35,7 +35,7 @@ pgsql sqlite mysql - + diff --git a/composer.json b/composer/composer.json similarity index 76% rename from composer.json rename to composer/composer.json index f009f3b3..2e394046 100644 --- a/composer.json +++ b/composer/composer.json @@ -12,6 +12,15 @@ "config": { "platform": { "php": "7.0.0" + }, + "vendor-dir": ".", + "optimize-autoloader": true, + "classmap-authoritative": true, + "autoloader-suffix": "Social" + }, + "autoload": { + "psr-4": { + "OCA\\Social\\": "../lib/" } }, "require": { diff --git a/composer.lock b/composer/composer.lock similarity index 97% rename from composer.lock rename to composer/composer.lock index 758e0955..c03b7b1b 100644 --- a/composer.lock +++ b/composer/composer.lock @@ -1,7 +1,7 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], "content-hash": "f93a783c86bad53b0b8486db3fc61380", @@ -12,12 +12,12 @@ "source": { "type": "git", "url": "https://github.com/daita/my-small-php-tools.git", - "reference": "d8778803612af20699c7efb0637bfe62478e596c" + "reference": "4e602526c3afbba7255ae4764037562075ef030f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/daita/my-small-php-tools/zipball/d8778803612af20699c7efb0637bfe62478e596c", - "reference": "d8778803612af20699c7efb0637bfe62478e596c", + "url": "https://api.github.com/repos/daita/my-small-php-tools/zipball/4e602526c3afbba7255ae4764037562075ef030f", + "reference": "4e602526c3afbba7255ae4764037562075ef030f", "shasum": "" }, "require": { @@ -40,7 +40,7 @@ } ], "description": "My small PHP Tools", - "time": "2020-03-18T23:09:45+00:00" + "time": "2020-08-06T13:26:28+00:00" }, { "name": "friendica/json-ld", @@ -243,6 +243,7 @@ ], "description": "This tool check syntax of PHP files about 20x faster than serial check.", "homepage": "https://github.com/JakubOnderka/PHP-Parallel-Lint", + "abandoned": "php-parallel-lint/php-parallel-lint", "time": "2018-02-24T15:31:20+00:00" }, { @@ -853,6 +854,7 @@ "keywords": [ "tokenizer" ], + "abandoned": true, "time": "2017-11-27T05:48:46+00:00" }, { @@ -1560,16 +1562,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.17.0", + "version": "v1.18.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9" + "reference": "1c302646f6efc070cd46856e600e5e0684d6b454" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e94c8b1bbe2bc77507a1056cdb06451c75b427f9", - "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454", + "reference": "1c302646f6efc070cd46856e600e5e0684d6b454", "shasum": "" }, "require": { @@ -1581,7 +1583,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.17-dev" + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -1614,7 +1620,21 @@ "polyfill", "portable" ], - "time": "2020-05-12T16:14:59+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" }, { "name": "theseer/tokenizer", @@ -1658,23 +1678,24 @@ }, { "name": "webmozart/assert", - "version": "1.8.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6" + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/ab2cb0b3b559010b75981b1bdce728da3ee90ad6", - "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6", + "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0", + "php": "^5.3.3 || ^7.0 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { + "phpstan/phpstan": "<0.12.20", "vimeo/psalm": "<3.9.1" }, "require-dev": { @@ -1702,7 +1723,7 @@ "check", "validate" ], - "time": "2020-04-18T12:12:48+00:00" + "time": "2020-07-08T17:02:28+00:00" } ], "aliases": [], @@ -1716,5 +1737,6 @@ "platform-dev": [], "platform-overrides": { "php": "7.0.0" - } + }, + "plugin-api-version": "1.1.0" } diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 18996bac..87301824 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -31,13 +31,20 @@ declare(strict_types=1); namespace OCA\Social\AppInfo; +use Closure; use OC\DB\SchemaWrapper; +use OC\WellKnown\Event\WellKnownEvent; +use OCA\Social\Listeners\WellKnownListener; use OCA\Social\Notification\Notifier; use OCA\Social\Service\ConfigService; use OCA\Social\Service\UpdateService; use OCP\AppFramework\App; -use OCP\AppFramework\IAppContainer; +use OCP\AppFramework\Bootstrap\IBootContext; +use OCP\AppFramework\Bootstrap\IBootstrap; +use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\AppFramework\QueryException; +use OCP\IServerContainer; +use Throwable; /** @@ -45,22 +52,12 @@ use OCP\AppFramework\QueryException; * * @package OCA\Social\AppInfo */ -class Application extends App { +class Application extends App implements IBootstrap { const APP_NAME = 'social'; - /** @var ConfigService */ - private $configService; - - /** @var UpdateService */ - private $updateService; - - /** @var IAppContainer */ - private $container; - - /** * Application constructor. * @@ -68,41 +65,59 @@ class Application extends App { */ public function __construct(array $params = []) { parent::__construct(self::APP_NAME, $params); - - $this->container = $this->getContainer(); - - $manager = $this->container->getServer() - ->getNotificationManager(); - $manager->registerNotifierService(Notifier::class); } /** - * + * @param IRegistrationContext $context */ - public function checkUpgradeStatus() { - $upgradeChecked = $this->container->getServer() - ->getConfig() - ->getAppValue(Application::APP_NAME, 'update_checked', ''); + public function register(IRegistrationContext $context): void { + // TODO: nc21, uncomment + // $context->registerEventListener(WellKnownEvent::class, WellKnownListener::class); + } + + + /** + * @param IBootContext $context + */ + public function boot(IBootContext $context): void { + $manager = $context->getServerContainer() + ->getNotificationManager(); + $manager->registerNotifierService(Notifier::class); + + try { + $context->injectFn(Closure::fromCallable([$this, 'checkUpgradeStatus'])); + } catch (Throwable $e) { + } + } + + + /** + * Register Navigation Tab + * + * @param IServerContainer $container + */ + protected function checkUpgradeStatus(IServerContainer $container) { + $upgradeChecked = $container->getConfig() + ->getAppValue(Application::APP_NAME, 'update_checked', ''); if ($upgradeChecked === '0.3') { return; } try { - $this->configService = $this->container->query(ConfigService::class); - $this->updateService = $this->container->query(UpdateService::class); + $configService = $container->query(ConfigService::class); + $updateService = $container->query(UpdateService::class); } catch (QueryException $e) { return; } - $server = $this->container->getServer(); - $schema = new SchemaWrapper($server->getDatabaseConnection()); + $schema = new SchemaWrapper($container->getDatabaseConnection()); if ($schema->hasTable('social_a2_stream')) { - $this->updateService->checkUpdateStatus(); + $updateService->checkUpdateStatus(); } - $this->configService->setAppValue('update_checked', '0.3'); + $configService->setAppValue('update_checked', '0.3'); } } diff --git a/lib/Db/StreamActionsRequest.php b/lib/Db/StreamActionsRequest.php index 99cf906d..2bacf14b 100644 --- a/lib/Db/StreamActionsRequest.php +++ b/lib/Db/StreamActionsRequest.php @@ -96,9 +96,7 @@ class StreamActionsRequest extends StreamActionsRequestBuilder { $this->limitToActorId($qb, $action->getActorId()); $this->limitToStreamId($qb, $action->getStreamId()); - $count = $qb->execute(); - - return $count; + return $qb->execute(); } diff --git a/lib/Listeners/WellKnownListener.php b/lib/Listeners/WellKnownListener.php new file mode 100644 index 00000000..8eb18c64 --- /dev/null +++ b/lib/Listeners/WellKnownListener.php @@ -0,0 +1,83 @@ + + * @copyright 2020, Maxence Lange + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Social\Listeners; + + +use OC\WellKnown\Event\WellKnownEvent; +use OCA\Social\Exceptions\CacheActorDoesNotExistException; +use OCA\Social\Exceptions\SocialAppConfigException; +use OCA\Social\Exceptions\UnauthorizedFediverseException; +use OCA\Social\Service\WellKnownService; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\WellKnown\IWellKnownManager; + + +/** + * Class WellKnownListener + * + * @package OCA\Social\Listeners + */ +class WellKnownListener implements IEventListener { + + + private $wellKnownService; + + + /** + * WellKnownListener constructor. + * + * @param WellKnownService $wellKnownService + */ + public function __construct(WellKnownService $wellKnownService) { + $this->wellKnownService = $wellKnownService; + } + + + /** + * @param Event $event + */ + public function handle(Event $event): void { + if (!$event instanceof WellKnownEvent) { + return; + } + + $wellKnown = $event->getWellKnown(); + if ($wellKnown->getService() === IWellKnownManager::WEBFINGER) { + try { + $this->wellKnownService->webfinger($wellKnown); + } catch (CacheActorDoesNotExistException | SocialAppConfigException | UnauthorizedFediverseException $e) { + } + } + } + +} + diff --git a/lib/Model/WebfingerLink.php b/lib/Model/WebfingerLink.php new file mode 100644 index 00000000..5e44f593 --- /dev/null +++ b/lib/Model/WebfingerLink.php @@ -0,0 +1,148 @@ + + * @copyright 2018, Maxence Lange + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Social\Model; + +use JsonSerializable; + + +/** + * Class WebfingerLink + * + * @package OCA\Social\Model + */ +class WebfingerLink implements JsonSerializable { + + + /** @var string */ + private $href = ''; + + /** @var string */ + private $rel = ''; + + /** @var string */ + private $template = ''; + + /** @var string */ + private $type = ''; + + + /** + * @return string + */ + public function getHref(): string { + return $this->href; + } + + /** + * @param string $value + * + * @return WebfingerLink + */ + public function setHref(string $value): self { + $this->href = $value; + + return $this; + } + + + /** + * @return string + */ + public function getType(): string { + return $this->type; + } + + /** + * @param string $value + * + * @return WebfingerLink + */ + public function setType(string $value): self { + $this->type = $value; + + return $this; + } + + + /** + * @return string + */ + public function getRel(): string { + return $this->rel; + } + + /** + * @param string $value + * + * @return WebfingerLink + */ + public function setRel(string $value): self { + $this->rel = $value; + + return $this; + } + + + /** + * @return string + */ + public function getTemplate(): string { + return $this->template; + } + + /** + * @param string $value + * + * @return WebfingerLink + */ + public function setTemplate(string $value): self { + $this->template = $value; + + return $this; + } + + + /** + * @return array + */ + public function jsonSerialize(): array { + $data = [ + 'rel' => $this->getRel(), + 'type' => $this->getType(), + 'template' => $this->getTemplate(), + 'href' => $this->getHref() + ]; + + return array_filter($data); + } + +} + diff --git a/lib/Service/ActorService.php b/lib/Service/ActorService.php index 429ebf88..a8fe47d1 100644 --- a/lib/Service/ActorService.php +++ b/lib/Service/ActorService.php @@ -36,6 +36,7 @@ use OCA\Social\Db\CacheActorsRequest; use OCA\Social\Db\CacheDocumentsRequest; use OCA\Social\Exceptions\CacheActorDoesNotExistException; use OCA\Social\Exceptions\CacheDocumentDoesNotExistException; +use OCA\Social\Exceptions\ItemAlreadyExistsException; use OCA\Social\Exceptions\ItemUnknownException; use OCA\Social\Model\ActivityPub\Actor\Person; @@ -92,6 +93,8 @@ class ActorService { /** * @param Person $actor + * + * @throws ItemAlreadyExistsException */ public function cacheLocalActor(Person $actor) { $actor->setLocal(true); @@ -108,6 +111,8 @@ class ActorService { /** * @param Person $actor + * + * @throws ItemAlreadyExistsException */ public function save(Person $actor) { $this->cacheDocumentIfNeeded($actor); @@ -119,6 +124,7 @@ class ActorService { * @param Person $actor * * @return int + * @throws ItemAlreadyExistsException */ public function update(Person $actor): int { $this->cacheDocumentIfNeeded($actor); @@ -129,6 +135,8 @@ class ActorService { /** * @param Person $actor + * + * @throws ItemAlreadyExistsException */ private function cacheDocumentIfNeeded(Person $actor) { if ($actor->hasIcon()) { diff --git a/lib/Service/CacheActorService.php b/lib/Service/CacheActorService.php index f049c99a..b448a682 100644 --- a/lib/Service/CacheActorService.php +++ b/lib/Service/CacheActorService.php @@ -50,6 +50,7 @@ use OCA\Social\Exceptions\RetrieveAccountFormatException; use OCA\Social\Exceptions\SocialAppConfigException; use OCA\Social\Exceptions\UnauthorizedFediverseException; use OCA\Social\Model\ActivityPub\Actor\Person; +use OCP\IURLGenerator; class CacheActorService { @@ -58,12 +59,18 @@ class CacheActorService { use TArrayTools; + /** @var IURLGenerator */ + private $urlGenerator; + /** @var CacheActorsRequest */ private $cacheActorsRequest; /** @var CurlService */ private $curlService; + /** @var FediverseService */ + private $fediverseService; + /** @var ConfigService */ private $configService; @@ -74,17 +81,21 @@ class CacheActorService { /** * CacheService constructor. * + * @param IUrlGenerator $urlGenerator * @param CacheActorsRequest $cacheActorsRequest * @param CurlService $curlService + * @param FediverseService $fediverseService * @param ConfigService $configService * @param MiscService $miscService */ public function __construct( - CacheActorsRequest $cacheActorsRequest, CurlService $curlService, - ConfigService $configService, MiscService $miscService + IUrlGenerator $urlGenerator, CacheActorsRequest $cacheActorsRequest, CurlService $curlService, + FediverseService $fediverseService, ConfigService $configService, MiscService $miscService ) { + $this->urlGenerator = $urlGenerator; $this->cacheActorsRequest = $cacheActorsRequest; $this->curlService = $curlService; + $this->fediverseService = $fediverseService; $this->configService = $configService; $this->miscService = $miscService; } @@ -166,8 +177,9 @@ class CacheActorService { */ public function getFromLocalAccount(string $account): Person { $instance = ''; + $account = ltrim($account, '@'); if (strrpos($account, '@')) { - list($account, $instance) = explode('@', $account); + list($account, $instance) = explode('@', $account, 2); } if ($instance === '' diff --git a/lib/Service/WellKnownService.php b/lib/Service/WellKnownService.php new file mode 100644 index 00000000..2ce5342f --- /dev/null +++ b/lib/Service/WellKnownService.php @@ -0,0 +1,132 @@ + + * @copyright 2018, Maxence Lange + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Social\Service; + + +use OC\Webfinger\Event\WebfingerEvent; +use OCA\Social\Db\CacheActorsRequest; +use OCA\Social\Exceptions\CacheActorDoesNotExistException; +use OCA\Social\Exceptions\SocialAppConfigException; +use OCA\Social\Exceptions\UnauthorizedFediverseException; +use OCA\Social\Model\WebfingerLink; +use OCP\IURLGenerator; +use OCP\WellKnown\Model\IWellKnown; + +class WellKnownService { + + + /** @var IURLGenerator */ + private $urlGenerator; + + /** @var CacheActorsRequest */ + private $cacheActorsRequest; + + /** @var CacheActorService */ + private $cacheActorService; + + /** @var FediverseService */ + private $fediverseService; + + /** @var ConfigService */ + private $configService; + + /** @var MiscService */ + private $miscService; + + + /** + * WebfingerService constructor. + * + * @param IURLGenerator $urlGenerator + * @param CacheActorsRequest $cacheActorsRequest + * @param CacheActorService $cacheActorService + * @param FediverseService $fediverseService + * @param ConfigService $configService + * @param MiscService $miscService + */ + public function __construct( + IURLGenerator $urlGenerator, CacheActorsRequest $cacheActorsRequest, + CacheActorService $cacheActorService, FediverseService $fediverseService, + ConfigService $configService, MiscService $miscService + ) { + $this->urlGenerator = $urlGenerator; + $this->cacheActorsRequest = $cacheActorsRequest; + $this->cacheActorService = $cacheActorService; + $this->fediverseService = $fediverseService; + $this->configService = $configService; + $this->miscService = $miscService; + + } + + + /** + * @param IWellKnown $wellKnown + * + * @throws CacheActorDoesNotExistException + * @throws SocialAppConfigException + * @throws UnauthorizedFediverseException + */ + public function webfinger(IWellKnown $wellKnown) { + $this->fediverseService->jailed(); + + $subject = $wellKnown->getSubject(); + + if (strpos($subject, 'acct:') === 0) { + $subject = substr($subject, 5); + } + + try { + $actor = $this->cacheActorService->getFromLocalAccount($subject); + } catch (CacheActorDoesNotExistException $e) { + $actor = $this->cacheActorsRequest->getFromId($subject); + if (!$actor->isLocal()) { + throw new CacheActorDoesNotExistException(); + } + } + + $href = $this->configService->getSocialUrl() . '@' . $actor->getPreferredUsername(); + $href = rtrim($href, '/'); + + $linkPerson = new WebfingerLink(); + $linkPerson->setRel('self'); + $linkPerson->setType('application/activity+json'); + $linkPerson->setHref($href); + + $linkOstatus = new WebfingerLink(); + $linkOstatus->setRel('http://ostatus.org/schema/1.0/subscribe'); + $subscribe = $this->urlGenerator->linkToRouteAbsolute('social.OStatus.subscribe') . '?uri={uri}'; + $linkOstatus->setTemplate($subscribe); + + $wellKnown->addLinkSerialized($linkPerson) + ->addLinkSerialized($linkOstatus); + } + +} +