diff --git a/build/frontend-legacy/webpack.modules.cjs b/build/frontend-legacy/webpack.modules.cjs
index 05384ed27f7..b7e557f3dad 100644
--- a/build/frontend-legacy/webpack.modules.cjs
+++ b/build/frontend-legacy/webpack.modules.cjs
@@ -16,6 +16,7 @@ module.exports = {
files_fileinfo: path.join(__dirname, 'core/src', 'files/fileinfo.js'),
install: path.join(__dirname, 'core/src', 'install.ts'),
login: path.join(__dirname, 'core/src', 'login.js'),
+ login_flow: path.join(__dirname, 'core/src', 'login-flow.ts'),
main: path.join(__dirname, 'core/src', 'main.js'),
maintenance: path.join(__dirname, 'core/src', 'maintenance.js'),
'public-page-menu': path.resolve(__dirname, 'core/src', 'public-page-menu.ts'),
diff --git a/core/Controller/ClientFlowLoginController.php b/core/Controller/ClientFlowLoginController.php
index 4464af890c4..0e83ef283a9 100644
--- a/core/Controller/ClientFlowLoginController.php
+++ b/core/Controller/ClientFlowLoginController.php
@@ -25,6 +25,7 @@ use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\StandaloneTemplateResponse;
+use OCP\AppFramework\Services\IInitialState;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Authentication\Exceptions\InvalidTokenException;
use OCP\Authentication\Token\IToken;
@@ -35,11 +36,11 @@ use OCP\IL10N;
use OCP\IRequest;
use OCP\ISession;
use OCP\IURLGenerator;
-use OCP\IUser;
use OCP\IUserSession;
use OCP\Security\ICrypto;
use OCP\Security\ISecureRandom;
use OCP\Session\Exceptions\SessionNotAvailableException;
+use OCP\Util;
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
class ClientFlowLoginController extends Controller {
@@ -61,6 +62,7 @@ class ClientFlowLoginController extends Controller {
private IEventDispatcher $eventDispatcher,
private ITimeFactory $timeFactory,
private IConfig $config,
+ private IInitialState $initialState,
) {
parent::__construct($appName, $request);
}
@@ -135,24 +137,36 @@ class ClientFlowLoginController extends Controller {
$csp->addAllowedFormActionDomain('nc://*');
}
+ $this->initialState->provideInitialState('loginFlowState', 'auth');
+ $this->initialState->provideInitialState('loginFlowAuth', [
+ 'client' => $clientName,
+ 'clientIdentifier' => $clientIdentifier,
+ 'instanceName' => $this->defaults->getName(),
+ 'stateToken' => $stateToken,
+ 'serverHost' => $this->getServerPath(),
+ 'oauthState' => $this->session->get('oauth.state'),
+ 'direct' => (bool)$direct,
+ 'providedRedirectUri' => $providedRedirectUri,
+ 'loginRedirectUrl' => $this->urlGenerator->linkToRoute(
+ 'core.ClientFlowLogin.grantPage',
+ [
+ 'stateToken' => $stateToken,
+ 'clientIdentifier' => $clientIdentifier,
+ 'oauthState' => $this->session->get('oauth.state'),
+ 'user' => $user,
+ 'direct' => $direct,
+ 'providedRedirectUri' => $providedRedirectUri,
+ ]),
+ 'appTokenUrl' => $this->urlGenerator->linkToRouteAbsolute('core.ClientFlowLogin.apptokenRedirect'),
+ ]);
+
+
+ Util::addScript('core', 'login_flow');
$response = new StandaloneTemplateResponse(
$this->appName,
- 'loginflow/authpicker',
- [
- 'client' => $clientName,
- 'clientIdentifier' => $clientIdentifier,
- 'instanceName' => $this->defaults->getName(),
- 'urlGenerator' => $this->urlGenerator,
- 'stateToken' => $stateToken,
- 'serverHost' => $this->getServerPath(),
- 'oauthState' => $this->session->get('oauth.state'),
- 'user' => $user,
- 'direct' => $direct,
- 'providedRedirectUri' => $providedRedirectUri,
- ],
- 'guest'
+ 'loginflow',
+ renderAs: 'guest'
);
-
$response->setContentSecurityPolicy($csp);
return $response;
}
@@ -188,26 +202,31 @@ class ClientFlowLoginController extends Controller {
$csp->addAllowedFormActionDomain('nc://*');
}
- /** @var IUser $user */
$user = $this->userSession->getUser();
+ \assert($user !== null);
+ $this->initialState->provideInitialState('loginFlowState', 'grant');
+ $this->initialState->provideInitialState('loginFlowGrant', [
+ 'actionUrl' => $this->urlGenerator->linkToRouteAbsolute(
+ 'core.ClientFlowLogin.generateAppPassword',
+ ),
+ 'client' => $clientName,
+ 'clientIdentifier' => $clientIdentifier,
+ 'instanceName' => $this->defaults->getName(),
+ 'stateToken' => $stateToken,
+ 'serverHost' => $this->getServerPath(),
+ 'oauthState' => $this->session->get('oauth.state'),
+ 'direct' => $direct,
+ 'providedRedirectUri' => $providedRedirectUri,
+ 'userDisplayName' => $user->getDisplayName(),
+ 'userId' => $user->getUID(),
+ ]);
+
+ Util::addScript('core', 'login_flow');
$response = new StandaloneTemplateResponse(
$this->appName,
- 'loginflow/grant',
- [
- 'userId' => $user->getUID(),
- 'userDisplayName' => $user->getDisplayName(),
- 'client' => $clientName,
- 'clientIdentifier' => $clientIdentifier,
- 'instanceName' => $this->defaults->getName(),
- 'urlGenerator' => $this->urlGenerator,
- 'stateToken' => $stateToken,
- 'serverHost' => $this->getServerPath(),
- 'oauthState' => $this->session->get('oauth.state'),
- 'direct' => $direct,
- 'providedRedirectUri' => $providedRedirectUri,
- ],
- 'guest'
+ 'loginflow',
+ renderAs: 'guest'
);
$response->setContentSecurityPolicy($csp);
diff --git a/core/Controller/ClientFlowLoginV2Controller.php b/core/Controller/ClientFlowLoginV2Controller.php
index 8c0c1e8179d..9a1694a93be 100644
--- a/core/Controller/ClientFlowLoginV2Controller.php
+++ b/core/Controller/ClientFlowLoginV2Controller.php
@@ -26,16 +26,17 @@ use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\StandaloneTemplateResponse;
+use OCP\AppFramework\Services\IInitialState;
use OCP\Authentication\Exceptions\InvalidTokenException;
use OCP\Defaults;
use OCP\IL10N;
use OCP\IRequest;
use OCP\ISession;
use OCP\IURLGenerator;
-use OCP\IUser;
use OCP\IUserSession;
use OCP\Security\ISecureRandom;
use OCP\Server;
+use OCP\Util;
/**
* @psalm-import-type CoreLoginFlowV2Credentials from ResponseDefinitions
@@ -58,6 +59,7 @@ class ClientFlowLoginV2Controller extends Controller {
private Defaults $defaults,
private ?string $userId,
private IL10N $l10n,
+ private IInitialState $initialState,
) {
parent::__construct($appName, $request);
}
@@ -122,18 +124,21 @@ class ClientFlowLoginV2Controller extends Controller {
);
$this->session->set(self::STATE_NAME, $stateToken);
+ $this->initialState->provideInitialState('loginFlowState', 'auth');
+ $this->initialState->provideInitialState('loginFlowAuth', [
+ 'client' => $flow->getClientName(),
+ 'instanceName' => $this->defaults->getName(),
+ 'stateToken' => $stateToken,
+ 'loginRedirectUrl' => $this->urlGenerator->linkToRouteAbsolute('core.ClientFlowLoginV2.grantPage', ['stateToken' => $stateToken, 'user' => $user, 'direct' => $direct]),
+ 'appTokenUrl' => $this->urlGenerator->linkToRouteAbsolute('core.ClientFlowLoginV2.apptokenRedirect'),
+ ]);
+
+
+ Util::addScript('core', 'login_flow');
return new StandaloneTemplateResponse(
$this->appName,
- 'loginflowv2/authpicker',
- [
- 'client' => $flow->getClientName(),
- 'instanceName' => $this->defaults->getName(),
- 'urlGenerator' => $this->urlGenerator,
- 'stateToken' => $stateToken,
- 'user' => $user,
- 'direct' => $direct,
- ],
- 'guest'
+ 'loginflow',
+ renderAs: 'guest'
);
}
@@ -161,22 +166,26 @@ class ClientFlowLoginV2Controller extends Controller {
return $this->loginTokenForbiddenClientResponse();
}
- /** @var IUser $user */
$user = $this->userSession->getUser();
+ \assert($user !== null);
+ $this->initialState->provideInitialState('loginFlowState', 'grant');
+ $this->initialState->provideInitialState('loginFlowGrant', [
+ 'actionUrl' => $this->urlGenerator->linkToRouteAbsolute('core.ClientFlowLoginV2.generateAppPassword'),
+ 'userId' => $user->getUID(),
+ 'userDisplayName' => $user->getDisplayName(),
+ 'client' => $flow->getClientName(),
+ 'instanceName' => $this->defaults->getName(),
+ 'stateToken' => $stateToken,
+ 'direct' => $direct === 1,
+ ]);
+
+
+ Util::addScript('core', 'login_flow');
return new StandaloneTemplateResponse(
$this->appName,
- 'loginflowv2/grant',
- [
- 'userId' => $user->getUID(),
- 'userDisplayName' => $user->getDisplayName(),
- 'client' => $flow->getClientName(),
- 'instanceName' => $this->defaults->getName(),
- 'urlGenerator' => $this->urlGenerator,
- 'stateToken' => $stateToken,
- 'direct' => $direct,
- ],
- 'guest'
+ 'loginflow',
+ renderAs: 'guest'
);
}
@@ -260,11 +269,12 @@ class ClientFlowLoginV2Controller extends Controller {
private function handleFlowDone(bool $result): StandaloneTemplateResponse {
if ($result) {
+ Util::addScript('core', 'login_flow');
+ $this->initialState->provideInitialState('loginFlowState', 'done');
return new StandaloneTemplateResponse(
$this->appName,
- 'loginflowv2/done',
- [],
- 'guest'
+ 'loginflow',
+ renderAs: 'guest'
);
}
diff --git a/core/js/login/authpicker.js b/core/js/login/authpicker.js
deleted file mode 100644
index 3c612400f1d..00000000000
--- a/core/js/login/authpicker.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-jQuery(document).ready(function() {
- $('#app-token-login').click(function(e) {
- e.preventDefault()
- $(this).addClass('hidden')
- $('#redirect-link').addClass('hidden')
- $('#app-token-login-field').removeClass('hidden')
- })
-
- document.getElementById('login-form').addEventListener('submit', function(e) {
- e.preventDefault()
- document.location.href = e.target.attributes.action.value
- })
-
- $('#login-form input').removeAttr('disabled')
-})
diff --git a/core/js/login/grant.js b/core/js/login/grant.js
deleted file mode 100644
index c71ccbbee1b..00000000000
--- a/core/js/login/grant.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-const form = document.querySelector('form')
-form.addEventListener('submit', function(event) {
- const wrapper = document.getElementById('submit-wrapper')
- if (wrapper === null) {
- return
- }
-
- if (OC.PasswordConfirmation.requiresPasswordConfirmation()) {
- // stop the event
- event.preventDefault()
- event.stopPropagation()
-
- // handle password confirmation
- OC.PasswordConfirmation.requirePasswordConfirmation(function() {
- // when password is confirmed we submit the form
- form.submit()
- })
-
- return false
- }
-
- Array.from(wrapper.getElementsByClassName('icon-confirm-white')).forEach(function(el) {
- el.classList.remove('icon-confirm-white')
- el.classList.add(OCA.Theming && OCA.Theming.inverted ? 'icon-loading-small' : 'icon-loading-small-dark')
- el.disabled = true
- })
-})
diff --git a/core/src/components/LoginFlow/LoginFlowAuthAppToken.vue b/core/src/components/LoginFlow/LoginFlowAuthAppToken.vue
new file mode 100644
index 00000000000..37df3fcb22d
--- /dev/null
+++ b/core/src/components/LoginFlow/LoginFlowAuthAppToken.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
diff --git a/core/src/components/LoginFlow/LoginFlowContainer.vue b/core/src/components/LoginFlow/LoginFlowContainer.vue
new file mode 100644
index 00000000000..9f0b8e11a28
--- /dev/null
+++ b/core/src/components/LoginFlow/LoginFlowContainer.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
+ {{ heading }}
+
+ {{ t('core', 'You can close this window.') }}
+
+ {{ t('core', 'You are about to grant "{client}" access to your {instanceName} account.', { client, instanceName }) }}
+
- t('Please log in before granting %1$s access to your %2$s account.', [ - '' . \OCP\Util::sanitizeHTML($_['client']) . '', - \OCP\Util::sanitizeHTML($_['instanceName']) - ])) ?> -
- -- t('If you are not trying to set up a new device or app, someone is trying to trick you into granting them access to your data. In this case do not proceed and instead contact your system administrator.')) ?> -
--
- - - - - - t('Alternative log in using app password')) ?> - -- t('Currently logged in as %1$s (%2$s).', [ - $_['userDisplayName'], - $_['userId'], - ])) ?> -
-- t('You are about to grant %1$s access to your %2$s account.', [ - '' . \OCP\Util::sanitizeHTML($_['client']) . '', - \OCP\Util::sanitizeHTML($_['instanceName']) - ])) ?> -
- --
- -- t('Please log in before granting %1$s access to your %2$s account.', [ - '' . \OCP\Util::sanitizeHTML($_['client']) . '', - \OCP\Util::sanitizeHTML($_['instanceName']) - ])) ?> -
- -- t('If you are not trying to set up a new device or app, someone is trying to trick you into granting them access to your data. In this case do not proceed and instead contact your system administrator.')) ?> -
--
- - - - - - t('Alternative log in using app password')) ?> - -
- t('Your client should now be connected!')) ?>
- t('You can close this window.')) ?>
-
- t('Currently logged in as %1$s (%2$s).', [ - $_['userDisplayName'], - $_['userId'], - ])) ?> -
-- t('You are about to grant %1$s access to your %2$s account.', [ - '' . \OCP\Util::sanitizeHTML($_['client']) . '', - \OCP\Util::sanitizeHTML($_['instanceName']) - ])) ?> -
- --
- -