From e3db06429991c4797e1fc5ea9f5897da24394eaf Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Mon, 7 Jan 2019 18:25:16 -0100 Subject: [PATCH 1/6] generate route Signed-off-by: Maxence Lange --- appinfo/routes.php | 2 + lib/Controller/OStatusController.php | 77 ++++++++++++++++++++++++++++ lib/webfinger.php | 5 ++ 3 files changed, 84 insertions(+) create mode 100644 lib/Controller/OStatusController.php diff --git a/appinfo/routes.php b/appinfo/routes.php index 8b28ae27..554144c5 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -54,6 +54,8 @@ return [ ['name' => 'ActivityPub#followers', 'url' => '/@{username}/followers', 'verb' => 'GET'], ['name' => 'ActivityPub#following', 'url' => '/@{username}/following', 'verb' => 'GET'], + ['name' => 'OStatus#subscribe', 'url' => '/ostatus/follow/{uri}', 'verb' => 'GET'], + ['name' => 'SocialPub#displayPost', 'url' => '/@{username}/{postId}', 'verb' => 'GET'], ['name' => 'Local#streamHome', 'url' => '/api/v1/stream/home', 'verb' => 'GET'], diff --git a/lib/Controller/OStatusController.php b/lib/Controller/OStatusController.php new file mode 100644 index 00000000..e079d3ff --- /dev/null +++ b/lib/Controller/OStatusController.php @@ -0,0 +1,77 @@ + + * @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\Controller; + + +use daita\MySmallPhpTools\Traits\Nextcloud\TNCDataResponse; +use OCA\Social\AppInfo\Application; +use OCA\Social\Service\MiscService; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Response; +use OCP\IRequest; + + +class OStatusController extends Controller { + + + use TNCDataResponse; + + + /** @var MiscService */ + private $miscService; + + + /** + * OStatusController constructor. + * + * @param IRequest $request + * @param MiscService $miscService + */ + public function __construct(IRequest $request, MiscService $miscService) { + parent::__construct(Application::APP_NAME, $request); + + $this->miscService = $miscService; + } + + + /** + * @NoCSRFRequired + * @PublicPage + * + * @param string $uri + * + * @return Response + */ + public function subscribe(string $uri): Response { + return $this->success([$uri]); + } + +} + diff --git a/lib/webfinger.php b/lib/webfinger.php index 8a50b82c..7794abad 100644 --- a/lib/webfinger.php +++ b/lib/webfinger.php @@ -83,6 +83,11 @@ $finger = [ 'rel' => 'self', 'type' => 'application/activity+json', 'href' => $href + ], + [ + 'rel' => 'http://ostatus.org/schema/1.0/subscribe', + 'template' => urldecode( + $href = $urlGenerator->linkToRouteAbsolute('social.OStatus.subscribe', ['uri' => '{uri}'])) ] ] ]; From 0257466aa1ebf867925db710cd726fcb02ee2593 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Mon, 7 Jan 2019 20:40:37 -0100 Subject: [PATCH 2/6] fixing tag Signed-off-by: Maxence Lange --- lib/Controller/OStatusController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Controller/OStatusController.php b/lib/Controller/OStatusController.php index e079d3ff..8d22b680 100644 --- a/lib/Controller/OStatusController.php +++ b/lib/Controller/OStatusController.php @@ -63,7 +63,7 @@ class OStatusController extends Controller { /** * @NoCSRFRequired - * @PublicPage + * @NoAdminRequired * * @param string $uri * From df1ad48a8d103d915168f8e63fa563c512b0a3e2 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Tue, 8 Jan 2019 08:37:28 -0100 Subject: [PATCH 3/6] get actor info from uri Signed-off-by: Maxence Lange --- lib/Controller/OStatusController.php | 32 ++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/Controller/OStatusController.php b/lib/Controller/OStatusController.php index 8d22b680..ef5db40f 100644 --- a/lib/Controller/OStatusController.php +++ b/lib/Controller/OStatusController.php @@ -30,8 +30,22 @@ declare(strict_types=1); namespace OCA\Social\Controller; +use daita\MySmallPhpTools\Exceptions\MalformedArrayException; use daita\MySmallPhpTools\Traits\Nextcloud\TNCDataResponse; +use Exception; use OCA\Social\AppInfo\Application; +use OCA\Social\Exceptions\CacheActorDoesNotExistException; +use OCA\Social\Exceptions\InvalidOriginException; +use OCA\Social\Exceptions\InvalidResourceException; +use OCA\Social\Exceptions\ItemUnknownException; +use OCA\Social\Exceptions\RedundancyLimitException; +use OCA\Social\Exceptions\RequestContentException; +use OCA\Social\Exceptions\RequestNetworkException; +use OCA\Social\Exceptions\RequestResultSizeException; +use OCA\Social\Exceptions\RequestServerException; +use OCA\Social\Exceptions\RetrieveAccountFormatException; +use OCA\Social\Exceptions\SocialAppConfigException; +use OCA\Social\Service\CacheActorService; use OCA\Social\Service\MiscService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\Response; @@ -44,6 +58,9 @@ class OStatusController extends Controller { use TNCDataResponse; + /** @var CacheActorService */ + private $cacheActorService; + /** @var MiscService */ private $miscService; @@ -52,11 +69,15 @@ class OStatusController extends Controller { * OStatusController constructor. * * @param IRequest $request + * @param CacheActorService $cacheActorService * @param MiscService $miscService */ - public function __construct(IRequest $request, MiscService $miscService) { + public function __construct( + IRequest $request, CacheActorService $cacheActorService, MiscService $miscService + ) { parent::__construct(Application::APP_NAME, $request); + $this->cacheActorService = $cacheActorService; $this->miscService = $miscService; } @@ -70,7 +91,14 @@ class OStatusController extends Controller { * @return Response */ public function subscribe(string $uri): Response { - return $this->success([$uri]); + + try { + $actor = $this->cacheActorService->getFromAccount($uri); + + return $this->success([$actor]); + } catch (Exception $e) { + return $this->fail($e); + } } } From 910583e12233d3282f5aeeb678c6aa420f25be0f Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Tue, 8 Jan 2019 09:25:57 -0100 Subject: [PATCH 4/6] get link for remote to follow local account Signed-off-by: Maxence Lange --- appinfo/routes.php | 1 + lib/Controller/OStatusController.php | 63 ++++++++++++++++++++++------ lib/Service/AccountService.php | 1 + lib/Service/CurlService.php | 33 +++++++++++---- 4 files changed, 78 insertions(+), 20 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index 554144c5..fad134fd 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -55,6 +55,7 @@ return [ ['name' => 'ActivityPub#following', 'url' => '/@{username}/following', 'verb' => 'GET'], ['name' => 'OStatus#subscribe', 'url' => '/ostatus/follow/{uri}', 'verb' => 'GET'], + ['name' => 'OStatus#getLink', 'url' => '/api/v1/ostatus/link/{local}/{account}', 'verb' => 'GET'], ['name' => 'SocialPub#displayPost', 'url' => '/@{username}/{postId}', 'verb' => 'GET'], diff --git a/lib/Controller/OStatusController.php b/lib/Controller/OStatusController.php index ef5db40f..5d6b0f77 100644 --- a/lib/Controller/OStatusController.php +++ b/lib/Controller/OStatusController.php @@ -30,22 +30,15 @@ declare(strict_types=1); namespace OCA\Social\Controller; -use daita\MySmallPhpTools\Exceptions\MalformedArrayException; +use daita\MySmallPhpTools\Exceptions\ArrayNotFoundException; use daita\MySmallPhpTools\Traits\Nextcloud\TNCDataResponse; +use daita\MySmallPhpTools\Traits\TArrayTools; use Exception; use OCA\Social\AppInfo\Application; -use OCA\Social\Exceptions\CacheActorDoesNotExistException; -use OCA\Social\Exceptions\InvalidOriginException; -use OCA\Social\Exceptions\InvalidResourceException; -use OCA\Social\Exceptions\ItemUnknownException; -use OCA\Social\Exceptions\RedundancyLimitException; -use OCA\Social\Exceptions\RequestContentException; -use OCA\Social\Exceptions\RequestNetworkException; -use OCA\Social\Exceptions\RequestResultSizeException; -use OCA\Social\Exceptions\RequestServerException; use OCA\Social\Exceptions\RetrieveAccountFormatException; -use OCA\Social\Exceptions\SocialAppConfigException; +use OCA\Social\Service\AccountService; use OCA\Social\Service\CacheActorService; +use OCA\Social\Service\CurlService; use OCA\Social\Service\MiscService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\Response; @@ -56,11 +49,18 @@ class OStatusController extends Controller { use TNCDataResponse; + use TArrayTools; /** @var CacheActorService */ private $cacheActorService; + /** @var AccountService */ + private $accountService; + + /** @var CurlService */ + private $curlService; + /** @var MiscService */ private $miscService; @@ -70,14 +70,19 @@ class OStatusController extends Controller { * * @param IRequest $request * @param CacheActorService $cacheActorService + * @param AccountService $accountService + * @param CurlService $curlService * @param MiscService $miscService */ public function __construct( - IRequest $request, CacheActorService $cacheActorService, MiscService $miscService + IRequest $request, CacheActorService $cacheActorService, AccountService $accountService, + CurlService $curlService, MiscService $miscService ) { parent::__construct(Application::APP_NAME, $request); $this->cacheActorService = $cacheActorService; + $this->accountService = $accountService; + $this->curlService = $curlService; $this->miscService = $miscService; } @@ -101,5 +106,39 @@ class OStatusController extends Controller { } } + + /** + * @NoCSRFRequired + * @NoAdminRequired + * + * @param string $local + * @param string $account + * + * @return Response + */ + public function getLink(string $local, string $account): Response { + + try { + $following = $this->accountService->getActor($local); + $result = $this->curlService->webfingerAccount($account); + + try { + $link = $this->extractArray( + 'rel', 'http://ostatus.org/schema/1.0/subscribe', + $this->getArray('links', $result) + ); + } catch (ArrayNotFoundException $e) { + throw new RetrieveAccountFormatException(); + } + + $template = $this->get('template', $link, ''); + $url = str_replace('{uri}', $following->getAccount(), $template); + + return $this->success(['url' => $url]); + } catch (Exception $e) { + return $this->fail($e); + } + } + } diff --git a/lib/Service/AccountService.php b/lib/Service/AccountService.php index 497b732b..13dde24d 100644 --- a/lib/Service/AccountService.php +++ b/lib/Service/AccountService.php @@ -161,6 +161,7 @@ class AccountService { * @throws NoUserException * @throws SocialAppConfigException * @throws UrlCloudException + * @throws ItemUnknownException */ public function getActorFromUserId(string $userId, bool $create = false): Person { $this->miscService->confirmUserId($userId); diff --git a/lib/Service/CurlService.php b/lib/Service/CurlService.php index 923596d1..c9b0c1c1 100644 --- a/lib/Service/CurlService.php +++ b/lib/Service/CurlService.php @@ -90,21 +90,15 @@ class CurlService { /** * @param string $account * - * @return Person - * @throws InvalidOriginException + * @return array * @throws InvalidResourceException - * @throws MalformedArrayException - * @throws RedundancyLimitException * @throws RequestContentException - * @throws RetrieveAccountFormatException * @throws RequestNetworkException * @throws RequestResultSizeException * @throws RequestServerException - * @throws SocialAppConfigException - * @throws ItemUnknownException * @throws RequestResultNotJsonException */ - public function retrieveAccount(string $account): Person { + public function webfingerAccount(string $account): array { $account = $this->withoutBeginAt($account); // we consider an account is like an email @@ -122,6 +116,29 @@ class CurlService { $request->setAddress($host); $result = $this->request($request); + return $result; + } + + + /** + * @param string $account + * + * @return Person + * @throws InvalidOriginException + * @throws InvalidResourceException + * @throws MalformedArrayException + * @throws RedundancyLimitException + * @throws RequestContentException + * @throws RetrieveAccountFormatException + * @throws RequestNetworkException + * @throws RequestResultSizeException + * @throws RequestServerException + * @throws SocialAppConfigException + * @throws ItemUnknownException + */ + public function retrieveAccount(string $account): Person { + $result = $this->webfingerAccount($account); + try { $link = $this->extractArray('rel', 'self', $this->getArray('links', $result)); } catch (ArrayNotFoundException $e) { From 5f0fa2cbc1b83fc7f3146ac06feb783227455c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 5 Feb 2019 14:55:21 +0100 Subject: [PATCH 5/6] Implement frontend for ostatus popup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Controller/OStatusController.php | 25 ++++++++- src/ostatus.js | 41 +++++++++++++++ src/views/OStatus.vue | 78 ++++++++++++++++++++++++++++ templates/ostatus.php | 28 ++++++++++ webpack.common.js | 7 ++- 5 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 src/ostatus.js create mode 100644 src/views/OStatus.vue create mode 100644 templates/ostatus.php diff --git a/lib/Controller/OStatusController.php b/lib/Controller/OStatusController.php index 5d6b0f77..31eda483 100644 --- a/lib/Controller/OStatusController.php +++ b/lib/Controller/OStatusController.php @@ -42,7 +42,10 @@ use OCA\Social\Service\CurlService; use OCA\Social\Service\MiscService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\Response; +use OCP\AppFramework\Http\TemplateResponse; use OCP\IRequest; +use OCP\IUserManager; +use OCP\IUserSession; class OStatusController extends Controller { @@ -64,6 +67,9 @@ class OStatusController extends Controller { /** @var MiscService */ private $miscService; + /** @var IUserManager */ + private $userSession; + /** * OStatusController constructor. @@ -76,7 +82,7 @@ class OStatusController extends Controller { */ public function __construct( IRequest $request, CacheActorService $cacheActorService, AccountService $accountService, - CurlService $curlService, MiscService $miscService + CurlService $curlService, MiscService $miscService, IUserSession $userSession ) { parent::__construct(Application::APP_NAME, $request); @@ -84,6 +90,7 @@ class OStatusController extends Controller { $this->accountService = $accountService; $this->curlService = $curlService; $this->miscService = $miscService; + $this->userSession = $userSession; } @@ -131,10 +138,24 @@ class OStatusController extends Controller { throw new RetrieveAccountFormatException(); } + $user = $this->userSession->getUser(); + if ($user === null) { + return $this->fail('Failed to retrieve current user'); + } + $template = $this->get('template', $link, ''); $url = str_replace('{uri}', $following->getAccount(), $template); - return $this->success(['url' => $url]); + return new TemplateResponse('social', 'ostatus', [ + 'serverData' => [ + 'url' => $url, + 'account' => $account, + 'currentUser' => [ + 'uid' => $user->getUID(), + 'displayName' => $user->getDisplayName(), + ] + ] + ], 'guest'); } catch (Exception $e) { return $this->fail($e); } diff --git a/src/ostatus.js b/src/ostatus.js new file mode 100644 index 00000000..b02f6b7e --- /dev/null +++ b/src/ostatus.js @@ -0,0 +1,41 @@ +/* + * @copyright Copyright (c) 2019 Julius Härtl + * + * @author Julius Härtl + * + * @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 . + * + */ + +import Vue from 'vue' +import store from './store' +import OStatus from './views/OStatus' + +// eslint-disable-next-line +__webpack_nonce__ = btoa(OC.requestToken) +// eslint-disable-next-line +__webpack_public_path__ = OC.linkTo('social', 'js/') + +Vue.prototype.t = t +Vue.prototype.n = n +Vue.prototype.OC = OC +Vue.prototype.OCA = OCA + +/* eslint-disable-next-line no-new */ +new Vue({ + render: h => h(OStatus), + store: store +}).$mount('#vue-content') diff --git a/src/views/OStatus.vue b/src/views/OStatus.vue new file mode 100644 index 00000000..dcda26b1 --- /dev/null +++ b/src/views/OStatus.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/templates/ostatus.php b/templates/ostatus.php new file mode 100644 index 00000000..dac1a5d0 --- /dev/null +++ b/templates/ostatus.php @@ -0,0 +1,28 @@ + + * + * @author Julius Härtl + * + * @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 . + * + */ + +script('social', 'ostatus'); +style('social', 'style'); +?> + +
diff --git a/webpack.common.js b/webpack.common.js index 65c22909..baaf5b52 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -3,11 +3,14 @@ const VueLoaderPlugin = require('vue-loader/lib/plugin'); module.exports = { - entry: path.join(__dirname, 'src', 'main.js'), + entry: { + social: path.join(__dirname, 'src', 'main.js'), + ostatus: path.join(__dirname, 'src', 'ostatus.js'), + }, output: { path: path.resolve(__dirname, './js'), publicPath: '/js/', - filename: 'social.js', + filename: '[name].js', chunkFilename: '[name].[chunkhash].js' }, module: { From bc542a613fa1cdcff9a5d7410a2d46cffc0c5122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 6 Feb 2019 11:48:46 +0100 Subject: [PATCH 6/6] Implement following a remote from the public pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- appinfo/routes.php | 1 + lib/Controller/OStatusController.php | 55 ++++++++++++++------ src/components/ProfileInfo.vue | 7 ++- src/views/OStatus.vue | 77 ++++++++++++++++++++++++---- 4 files changed, 113 insertions(+), 27 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index fad134fd..2b64e712 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -55,6 +55,7 @@ return [ ['name' => 'ActivityPub#following', 'url' => '/@{username}/following', 'verb' => 'GET'], ['name' => 'OStatus#subscribe', 'url' => '/ostatus/follow/{uri}', 'verb' => 'GET'], + ['name' => 'OStatus#followRemote', 'url' => '/api/v1/ostatus/followRemote/{local}', 'verb' => 'GET'], ['name' => 'OStatus#getLink', 'url' => '/api/v1/ostatus/link/{local}/{account}', 'verb' => 'GET'], ['name' => 'SocialPub#displayPost', 'url' => '/@{username}/{postId}', 'verb' => 'GET'], diff --git a/lib/Controller/OStatusController.php b/lib/Controller/OStatusController.php index 31eda483..182c4a3d 100644 --- a/lib/Controller/OStatusController.php +++ b/lib/Controller/OStatusController.php @@ -107,7 +107,20 @@ class OStatusController extends Controller { try { $actor = $this->cacheActorService->getFromAccount($uri); - return $this->success([$actor]); + $user = $this->userSession->getUser(); + if ($user === null) { + return $this->fail('Failed to retrieve current user'); + } + + return new TemplateResponse('social', 'ostatus', [ + 'serverData' => [ + 'account' => $actor->getAccount(), + 'currentUser' => [ + 'uid' => $user->getUID(), + 'displayName' => $user->getDisplayName(), + ] + ] + ], 'guest'); } catch (Exception $e) { return $this->fail($e); } @@ -117,6 +130,30 @@ class OStatusController extends Controller { /** * @NoCSRFRequired * @NoAdminRequired + * @PublicPage + * + * @param string $local + * @return Response + */ + public function followRemote(string $local): Response { + try { + $following = $this->accountService->getActor($local); + + return new TemplateResponse('social', 'ostatus', [ + 'serverData' => [ + 'local' => $local, + 'account' => $following->getAccount() + ] + ], 'guest'); + } catch (\Exception $e) { + return $this->fail($e); + } + } + + /** + * @NoCSRFRequired + * @NoAdminRequired + * @PublicPage * * @param string $local * @param string $account @@ -138,24 +175,10 @@ class OStatusController extends Controller { throw new RetrieveAccountFormatException(); } - $user = $this->userSession->getUser(); - if ($user === null) { - return $this->fail('Failed to retrieve current user'); - } - $template = $this->get('template', $link, ''); $url = str_replace('{uri}', $following->getAccount(), $template); - return new TemplateResponse('social', 'ostatus', [ - 'serverData' => [ - 'url' => $url, - 'account' => $account, - 'currentUser' => [ - 'uid' => $user->getUID(), - 'displayName' => $user->getDisplayName(), - ] - ] - ], 'guest'); + return $this->success(['url' => $url]); } catch (Exception $e) { return $this->fail($e); } diff --git a/src/components/ProfileInfo.vue b/src/components/ProfileInfo.vue index 439da6df..e1352084 100644 --- a/src/components/ProfileInfo.vue +++ b/src/components/ProfileInfo.vue @@ -35,6 +35,9 @@

+