From cbb54b6dfa3157f544a4539f22672a27e4ebc92b Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Tue, 8 Nov 2022 10:40:20 -0100 Subject: [PATCH 1/3] confirmation popup Signed-off-by: Maxence Lange --- appinfo/routes.php | 1 + lib/Controller/OAuthController.php | 57 +++++++++++++++++++++++++----- templates/oauth2.php | 26 ++++++++++++++ 3 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 templates/oauth2.php diff --git a/appinfo/routes.php b/appinfo/routes.php index 90ef2f44..861bcb93 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -70,6 +70,7 @@ return [ ['name' => 'OAuth#nodeinfo2', 'url' => '/.well-known/nodeinfo/2.0', 'verb' => 'GET'], ['name' => 'OAuth#apps', 'url' => '/api/v1/apps', 'verb' => 'POST'], ['name' => 'OAuth#authorize', 'url' => '/oauth/authorize', 'verb' => 'GET'], + ['name' => 'OAuth#authorizing', 'url' => '/oauth/authorize', 'verb' => 'POST'], ['name' => 'OAuth#token', 'url' => '/oauth/token', 'verb' => 'POST'], // Api for 3rd party diff --git a/lib/Controller/OAuthController.php b/lib/Controller/OAuthController.php index 05836f99..238cb402 100644 --- a/lib/Controller/OAuthController.php +++ b/lib/Controller/OAuthController.php @@ -45,6 +45,7 @@ use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\Response; +use OCP\AppFramework\Http\TemplateResponse; use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUserSession; @@ -172,13 +173,57 @@ class OAuthController extends Controller { string $redirect_uri, string $response_type, string $scope = 'read' + ): Response { + try { + $user = $this->userSession->getUser(); + + // check actor exists + $this->accountService->getActorFromUserId($user->getUID()); + + if ($response_type !== 'code') { + throw new ClientNotFoundException('invalid response type'); + } + + // check client exists in db + $this->clientService->getFromClientId($client_id); + + return new TemplateResponse(Application::APP_NAME, 'oauth2', [ + 'request' => + [ + 'clientId' => $client_id, + 'redirectUri' => $redirect_uri, + 'responseType' => $response_type, + 'scope' => $scope + ] + ]); + + } catch (Exception $e) { + $this->logger->notice($e->getMessage() . ' ' . get_class($e)); + + return new TemplateResponse( + Application::APP_NAME, + 'oauth2', + ['error' => $e->getMessage()] + ); + } + } + + + /** + * @NoAdminRequired + */ + public function authorizing( + string $client_id, + string $redirect_uri, + string $response_type, + string $scope = 'read' ): DataResponse { try { $user = $this->userSession->getUser(); $account = $this->accountService->getActorFromUserId($user->getUID()); if ($response_type !== 'code') { - return new DataResponse(['error' => 'invalid_type'], Http::STATUS_BAD_REQUEST); + throw new ClientNotFoundException('invalid response type'); } $client = $this->clientService->getFromClientId($client_id); @@ -204,18 +249,12 @@ class OAuthController extends Controller { // TODO : finalize result if no redirect_url return new DataResponse( - [ - 'code' => $code, - // 'access_token' => '', - // "token_type" => "Bearer", - // "scope" => "read write follow push", - // "created_at" => 1573979017 - ], Http::STATUS_OK + ['code' => $code], Http::STATUS_OK ); } catch (Exception $e) { $this->logger->notice($e->getMessage() . ' ' . get_class($e)); - return new DataResponse(['error' => $e->getMessage()], Http::STATUS_UNAUTHORIZED); + return new DataResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST); } } diff --git a/templates/oauth2.php b/templates/oauth2.php new file mode 100644 index 00000000..2b192b05 --- /dev/null +++ b/templates/oauth2.php @@ -0,0 +1,26 @@ + + * + * @author Jonas Sulzer + * @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 . + * + */ + + +\OCP\Util::addScript('social', 'social-oauth2'); From fb266f056d2540e884ab56479c4ae47c5262637e Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Mon, 21 Nov 2022 14:53:49 +0100 Subject: [PATCH 2/3] Implement UI Signed-off-by: Carl Schwan --- lib/Controller/OAuthController.php | 20 +++---- src/oauth.js | 38 ++++++++++++ src/views/OAuth2Authorize.vue | 95 ++++++++++++++++++++++++++++++ templates/oauth2.php | 4 +- webpack.common.js | 3 +- 5 files changed, 145 insertions(+), 15 deletions(-) create mode 100644 src/oauth.js create mode 100644 src/views/OAuth2Authorize.vue diff --git a/lib/Controller/OAuthController.php b/lib/Controller/OAuthController.php index 238cb402..c1c20ec2 100644 --- a/lib/Controller/OAuthController.php +++ b/lib/Controller/OAuthController.php @@ -46,6 +46,7 @@ use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\TemplateResponse; +use OCP\AppFramework\Services\IInitialState; use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUserSession; @@ -60,6 +61,7 @@ class OAuthController extends Controller { private ClientService $clientService; private ConfigService $configService; private LoggerInterface $logger; + private IInitialState $initialState; public function __construct( IRequest $request, @@ -70,7 +72,8 @@ class OAuthController extends Controller { CacheActorService $cacheActorService, ClientService $clientService, ConfigService $configService, - LoggerInterface $logger + LoggerInterface $logger, + IInitialState $initialState ) { parent::__construct(Application::APP_NAME, $request); @@ -82,6 +85,7 @@ class OAuthController extends Controller { $this->clientService = $clientService; $this->configService = $configService; $this->logger = $logger; + $this->initialState = $initialState; $body = file_get_contents('php://input'); $logger->debug('[OAuthController] input: ' . $body); @@ -174,7 +178,6 @@ class OAuthController extends Controller { string $response_type, string $scope = 'read' ): Response { - try { $user = $this->userSession->getUser(); // check actor exists @@ -185,7 +188,8 @@ class OAuthController extends Controller { } // check client exists in db - $this->clientService->getFromClientId($client_id); + $client = $this->clientService->getFromClientId($client_id); + $this->initialState->provideInitialState('appName', $client->getAppName()); return new TemplateResponse(Application::APP_NAME, 'oauth2', [ 'request' => @@ -196,16 +200,6 @@ class OAuthController extends Controller { 'scope' => $scope ] ]); - - } catch (Exception $e) { - $this->logger->notice($e->getMessage() . ' ' . get_class($e)); - - return new TemplateResponse( - Application::APP_NAME, - 'oauth2', - ['error' => $e->getMessage()] - ); - } } diff --git a/src/oauth.js b/src/oauth.js new file mode 100644 index 00000000..7138183e --- /dev/null +++ b/src/oauth.js @@ -0,0 +1,38 @@ +/** + * @copyright 2022 Carl Schwan + * @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 OAuth2Authorize from './views/OAuth2Authorize.vue' + +// CSP config for webpack dynamic chunk loading +// eslint-disable-next-line +__webpack_nonce__ = btoa(OC.requestToken) + +// Correct the root of the app for chunk loading +// OC.linkTo matches the apps folders +// 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 + +new Vue({ + render: h => h(OAuth2Authorize), +}).$mount('#social-oauth2') diff --git a/src/views/OAuth2Authorize.vue b/src/views/OAuth2Authorize.vue new file mode 100644 index 00000000..0732f1ec --- /dev/null +++ b/src/views/OAuth2Authorize.vue @@ -0,0 +1,95 @@ + + + + + + + diff --git a/templates/oauth2.php b/templates/oauth2.php index 2b192b05..9cb80a07 100644 --- a/templates/oauth2.php +++ b/templates/oauth2.php @@ -22,5 +22,7 @@ * */ +\OCP\Util::addScript('social', 'social-oauth'); +?> -\OCP\Util::addScript('social', 'social-oauth2'); +
diff --git a/webpack.common.js b/webpack.common.js index dcacd5d9..48fef45f 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -8,7 +8,8 @@ webpackConfig.entry = { social: path.join(__dirname, 'src', 'main.js'), ostatus: path.join(__dirname, 'src', 'ostatus.js'), profilePage: path.join(__dirname, 'src', 'profile.js'), - dashboard: path.join(__dirname, 'src', 'dashboard.js'), + dashboard: path.join(__dirname, 'src', 'dashboard.js'), + oauth: path.join(__dirname, 'src', 'oauth.js'), } module.exports = webpackConfig From 58ca8655231af322f3ab4c291ad774d6bf960805 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Mon, 21 Nov 2022 15:58:36 +0100 Subject: [PATCH 3/3] Fix csrf error Signed-off-by: Carl Schwan --- src/views/OAuth2Authorize.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/views/OAuth2Authorize.vue b/src/views/OAuth2Authorize.vue index 0732f1ec..01041d5a 100644 --- a/src/views/OAuth2Authorize.vue +++ b/src/views/OAuth2Authorize.vue @@ -24,6 +24,9 @@ {{ t('social', '{appDisplayName} would like permission to access your account. It is a third party application.', {appDisplayName: appName}) }} {{ t('social', 'If you do not trust it, then you should not authorize it.') }}

+
{{ t('social', 'Authorize') }} @@ -53,7 +56,7 @@ export default { }, computed: { homeUrl() { - generateUrl('/apps/social/') + return generateUrl('/apps/social/') }, }, }