Merge pull request #57526 from nextcloud/refactor/loginflow-to-vue
Some checks are pending
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Integration sqlite / changes (push) Waiting to run
Integration sqlite / integration-sqlite (master, 8.4, main, --tags ~@large files_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, capabilities_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, collaboration_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, comments_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, dav_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, federation_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, file_conversions) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, files_reminders) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, filesdrop_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, ldap_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, openldap_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, openldap_numerical_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, remoteapi_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, routing_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, setup_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, sharees_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, sharing_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, theming_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, videoverification_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite-summary (push) Blocked by required conditions
Psalm static code analysis / static-code-analysis (push) Waiting to run
Psalm static code analysis / static-code-analysis-security (push) Waiting to run
Psalm static code analysis / static-code-analysis-ocp (push) Waiting to run
Psalm static code analysis / static-code-analysis-ncu (push) Waiting to run

refactor(core): migrate login flow ui from jQuery to Vue
This commit is contained in:
Ferdinand Thiessen 2026-01-14 03:10:07 +01:00 committed by GitHub
commit 891d0fc481
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 813 additions and 395 deletions

View file

@ -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'),

View file

@ -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);

View file

@ -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'
);
}

View file

@ -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')
})

View file

@ -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
})
})

View file

@ -0,0 +1,49 @@
<!--
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import { getRequestToken } from '@nextcloud/auth'
import { t } from '@nextcloud/l10n'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcFormBox from '@nextcloud/vue/components/NcFormBox'
import NcPasswordField from '@nextcloud/vue/components/NcPasswordField'
import NcTextField from '@nextcloud/vue/components/NcTextField'
defineProps<{
appTokenUrl: string
direct: boolean
stateToken: string
}>()
const requestToken = getRequestToken()
</script>
<template>
<form :action="appTokenUrl" :class="$style.loginFlowAuthAppToken" method="post">
<NcFormBox>
<NcTextField name="user" :label="t('core', 'Login')" />
<NcPasswordField name="password" :label="t('core', 'App password')" />
</NcFormBox>
<input type="hidden" name="stateToken" :value="stateToken">
<input type="hidden" name="requesttoken" :value="requestToken">
<input
v-if="direct"
type="hidden"
name="direct"
value="1">
<NcButton type="submit" variant="primary" wide>
{{ t('core', 'Grant access') }}
</NcButton>
</form>
</template>
<style module>
.loginFlowAuthAppToken {
display: flex;
flex-direction: column;
gap: var(--default-grid-baseline);
}
</style>

View file

@ -0,0 +1,26 @@
<!--
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import NcGuestContent from '@nextcloud/vue/components/NcGuestContent'
defineProps<{
heading: string
}>()
</script>
<template>
<NcGuestContent class="picker-window" :class="$style.loginFlowContainer">
<h2>{{ heading }}</h2>
<slot />
</NcGuestContent>
</template>
<style module>
.loginFlowContainer {
display: flex;
flex-direction: column;
}
</style>

22
core/src/login-flow.ts Normal file
View file

@ -0,0 +1,22 @@
/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { getCSPNonce } from '@nextcloud/auth'
import { loadState } from '@nextcloud/initial-state'
import Vue, { defineAsyncComponent } from 'vue'
__webpack_nonce__ = getCSPNonce()
const LoginFlowAuth = defineAsyncComponent(() => import('./views/LoginFlowAuth.vue'))
const LoginFlowGrant = defineAsyncComponent(() => import('./views/LoginFlowGrant.vue'))
const LoginFlowDone = defineAsyncComponent(() => import('./views/LoginFlowDone.vue'))
const state = loadState<'auth' | 'grant' | 'done'>('core', 'loginFlowState')
const app = new Vue({
render: (h) => h(state === 'auth'
? LoginFlowAuth
: (state === 'grant' ? LoginFlowGrant : LoginFlowDone)),
})
app.$mount('#core-loginflow')

View file

@ -0,0 +1,73 @@
<!--
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import { ref } from 'vue'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
import LoginFlowAuthAppToken from '../components/LoginFlow/LoginFlowAuthAppToken.vue'
import LoginFlowContainer from '../components/LoginFlow/LoginFlowContainer.vue'
const {
client,
direct,
instanceName,
loginRedirectUrl,
appTokenUrl,
stateToken,
} = loadState<{
client: string
direct?: boolean
instanceName: string
loginRedirectUrl: string
appTokenUrl: string
stateToken: string
}>('core', 'loginFlowAuth')
const useAppTokenLogin = ref(false)
</script>
<template>
<LoginFlowContainer :heading="t('core', 'Connect to your account')">
<NcNoteCard type="info">
{{ t('core', 'Please log in before granting "{client}" access to your {instanceName} account.', { client, instanceName }) }}
</NcNoteCard>
<NcNoteCard type="warning" :heading="t('core', 'Security warning')">
{{ t('core', '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.') }}
</NcNoteCard>
<NcButton
v-if="!useAppTokenLogin"
:class="$style.loginFlowAuth__button"
:href="loginRedirectUrl"
variant="primary">
{{ t('core', 'Log in') }}
</NcButton>
<LoginFlowAuthAppToken
v-else
:app-token-url="appTokenUrl"
:direct="direct ?? false"
:state-token="stateToken" />
<NcButton
:class="$style.loginFlowAuth__button"
variant="tertiary"
@click="useAppTokenLogin = !useAppTokenLogin">
{{ useAppTokenLogin ? t('core', 'Log in using password') : t('core', 'Alternative log in using app password') }}
</NcButton>
</LoginFlowContainer>
</template>
<style module>
.loginFlowAuth__button {
margin-top: 0.5rem;
margin-inline: auto;
min-width: 50% !important;
}
</style>

View file

@ -0,0 +1,20 @@
<!--
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import { t } from '@nextcloud/l10n'
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
import LoginFlowContainer from '../components/LoginFlow/LoginFlowContainer.vue'
</script>
<template>
<LoginFlowContainer :heading="t('core', 'Account connected')">
<NcNoteCard type="info">
{{ t('core', 'Your client should now be connected!') }}
<br>
{{ t('core', 'You can close this window.') }}
</NcNoteCard>
</LoginFlowContainer>
</template>

View file

@ -0,0 +1,106 @@
<!--
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import { getRequestToken } from '@nextcloud/auth'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import { confirmPassword, isPasswordConfirmationRequired, PwdConfirmationMode } from '@nextcloud/password-confirmation'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
import LoginFlowContainer from '../components/LoginFlow/LoginFlowContainer.vue'
const {
clientIdentifier,
oauthState,
providedRedirectUri,
actionUrl,
client,
direct,
instanceName,
stateToken,
userDisplayName,
userId,
} = loadState<{
clientIdentifier?: string
oauthState?: string
providedRedirectUri?: string
actionUrl: string
client: string
direct: boolean
instanceName: string
stateToken: string
userId: string
userDisplayName: string
}>('core', 'loginFlowGrant')
const requestToken = getRequestToken()
/**
* Handle submit event to confirm password if required
*
* @param event - The submit event
*/
async function onSubmit(event: SubmitEvent) {
if (isPasswordConfirmationRequired(PwdConfirmationMode.Lax)) {
event.preventDefault()
event.stopPropagation()
await confirmPassword()
;(event.target as HTMLFormElement).submit()
return false
}
}
</script>
<template>
<LoginFlowContainer :heading="t('core', 'Account access')">
<NcNoteCard type="info">
{{ t('core', 'Currently logged in as {userDisplayName} ({userId}).', { userDisplayName, userId }) }}
<br>
{{ t('core', 'You are about to grant "{client}" access to your {instanceName} account.', { client, instanceName }) }}
</NcNoteCard>
<form method="POST" :action="actionUrl" @submit="onSubmit">
<input type="hidden" name="requesttoken" :value="requestToken">
<input type="hidden" name="stateToken" :value="stateToken">
<input
v-if="direct"
type="hidden"
name="direct"
value="1">
<input
v-if="clientIdentifier !== undefined"
type="hidden"
name="clientIdentifier"
:value="clientIdentifier">
<input
v-if="oauthState !== undefined"
type="hidden"
name="oauthState"
:value="oauthState">
<input
v-if="providedRedirectUri !== undefined"
type="hidden"
name="providedRedirectUri"
:value="providedRedirectUri">
<NcButton :class="$style.loginFlowGrant__button" type="submit" variant="primary">
{{ t('core', 'Grant access') }}
</NcButton>
</form>
</LoginFlowContainer>
</template>
<style module>
.loginFlowGrant__button {
margin-top: 0.5rem;
margin-inline: auto;
min-width: 50% !important;
}
</style>

View file

@ -0,0 +1,8 @@
<?php
/*!
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
?>
<div id="core-loginflow"></div>

View file

@ -1,59 +0,0 @@
<?php
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
\OCP\Util::addScript('core', 'login/authpicker', 'core');
style('core', 'login/authpicker');
/** @var array $_ */
/** @var \OCP\IURLGenerator $urlGenerator */
$urlGenerator = $_['urlGenerator'];
?>
<div class="picker-window">
<h2><?php p($l->t('Connect to your account')) ?></h2>
<p class="info">
<?php print_unescaped($l->t('Please log in before granting %1$s access to your %2$s account.', [
'<strong>' . \OCP\Util::sanitizeHTML($_['client']) . '</strong>',
\OCP\Util::sanitizeHTML($_['instanceName'])
])) ?>
</p>
<div class="notecard warning">
<h3><?php p($l->t('Security warning')) ?></h3>
<p>
<?php p($l->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.')) ?>
</p>
</div>
<br/>
<p id="redirect-link">
<form id="login-form" action="<?php p($urlGenerator->linkToRoute('core.ClientFlowLogin.grantPage', ['stateToken' => $_['stateToken'], 'clientIdentifier' => $_['clientIdentifier'], 'oauthState' => $_['oauthState'], 'user' => $_['user'], 'direct' => $_['direct'], 'providedRedirectUri' => $_['providedRedirectUri']])) ?>" method="get">
<input type="submit" class="login primary icon-confirm-white" value="<?php p($l->t('Log in')) ?>" disabled>
</form>
</p>
<form action="<?php p($urlGenerator->linkToRouteAbsolute('core.ClientFlowLogin.apptokenRedirect')); ?>" method="post" id="app-token-login-field" class="hidden">
<p class="grouptop">
<input type="text" name="user" id="user" placeholder="<?php p($l->t('Login')) ?>">
<label for="user" class="infield"><?php p($l->t('Login')) ?></label>
</p>
<p class="groupbottom">
<input type="password" name="password" id="password" placeholder="<?php p($l->t('App password')) ?>">
<label for="password" class="infield"><?php p($l->t('Password')) ?></label>
</p>
<input type="hidden" name="stateToken" value="<?php p($_['stateToken']) ?>" />
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>">
<?php if ($_['direct'] !== 0) { ?>
<input type="hidden" name="direct" value="<?php p($_['direct']) ?>">
<?php } ?>
<input id="submit-app-token-login" type="submit" class="login primary icon-confirm-white" value="<?php p($l->t('Grant access')) ?>">
</form>
<?php if (empty($_['oauthState'])): ?>
<a id="app-token-login" class="apptoken-link" href="#"><?php p($l->t('Alternative log in using app password')) ?></a>
<?php endif; ?>
</div>

View file

@ -1,47 +0,0 @@
<?php
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
\OCP\Util::addScript('core', 'login/grant', 'core');
style('core', 'login/authpicker');
/** @var array $_ */
/** @var \OCP\IURLGenerator $urlGenerator */
$urlGenerator = $_['urlGenerator'];
?>
<div class="picker-window small">
<h2><?php p($l->t('Account access')) ?></h2>
<p class="info">
<?php p($l->t('Currently logged in as %1$s (%2$s).', [
$_['userDisplayName'],
$_['userId'],
])) ?>
</p>
<p class="info">
<?php print_unescaped($l->t('You are about to grant %1$s access to your %2$s account.', [
'<strong>' . \OCP\Util::sanitizeHTML($_['client']) . '</strong>',
\OCP\Util::sanitizeHTML($_['instanceName'])
])) ?>
</p>
<br/>
<p id="redirect-link">
<form method="POST" action="<?php p($urlGenerator->linkToRouteAbsolute('core.ClientFlowLogin.generateAppPassword')) ?>">
<input type="hidden" name="clientIdentifier" value="<?php p($_['clientIdentifier']) ?>" />
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
<input type="hidden" name="stateToken" value="<?php p($_['stateToken']) ?>" />
<input type="hidden" name="oauthState" value="<?php p($_['oauthState']) ?>" />
<input type="hidden" name="providedRedirectUri" value="<?php p($_['providedRedirectUri']) ?>">
<?php if ($_['direct']) { ?>
<input type="hidden" name="direct" value="1" />
<?php } ?>
<div id="submit-wrapper">
<input type="submit" class="login primary icon-confirm-white" title="" value="<?php p($l->t('Grant access')); ?>" />
</div>
</form>
</p>
</div>

View file

@ -1,56 +0,0 @@
<?php
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
style('core', 'login/authpicker');
\OCP\Util::addScript('core', 'login/authpicker', 'core');
/** @var array $_ */
/** @var \OCP\IURLGenerator $urlGenerator */
$urlGenerator = $_['urlGenerator'];
?>
<div class="picker-window">
<h2><?php p($l->t('Connect to your account')) ?></h2>
<p class="info">
<?php print_unescaped($l->t('Please log in before granting %1$s access to your %2$s account.', [
'<strong>' . \OCP\Util::sanitizeHTML($_['client']) . '</strong>',
\OCP\Util::sanitizeHTML($_['instanceName'])
])) ?>
</p>
<div class="notecard warning">
<h3><?php p($l->t('Security warning')) ?></h3>
<p>
<?php p($l->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.')) ?>
</p>
</div>
<br/>
<p id="redirect-link">
<form id="login-form" action="<?php p($urlGenerator->linkToRouteAbsolute('core.ClientFlowLoginV2.grantPage', ['stateToken' => $_['stateToken'], 'user' => $_['user'], 'direct' => $_['direct'] ?? 0])) ?>" method="get">
<input type="submit" class="login primary icon-confirm-white" value="<?php p($l->t('Log in')) ?>" disabled>
</form>
</p>
<form action="<?php p($urlGenerator->linkToRouteAbsolute('core.ClientFlowLoginV2.apptokenRedirect')); ?>" method="post" id="app-token-login-field" class="hidden">
<p class="grouptop">
<input type="text" name="user" id="user" placeholder="<?php p($l->t('Login')) ?>">
<label for="user" class="infield"><?php p($l->t('Login')) ?></label>
</p>
<p class="groupbottom">
<input type="password" name="password" id="password" placeholder="<?php p($l->t('App password')) ?>">
<label for="password" class="infield"><?php p($l->t('Password')) ?></label>
</p>
<input type="hidden" name="stateToken" value="<?php p($_['stateToken']) ?>" />
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>">
<input id="submit-app-token-login" type="submit" class="login primary icon-confirm-white" value="<?php p($l->t('Grant access')) ?>">
</form>
<?php if (empty($_['oauthState'])): ?>
<a id="app-token-login" class="apptoken-link" href="#"><?php p($l->t('Alternative log in using app password')) ?></a>
<?php endif; ?>
</div>

View file

@ -1,21 +0,0 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
style('core', 'login/authpicker');
/** @var array $_ */
?>
<div class="picker-window">
<h2><?php p($l->t('Account connected')) ?></h2>
<p class="info">
<?php p($l->t('Your client should now be connected!')) ?><br/>
<?php p($l->t('You can close this window.')) ?>
</p>
<br/>
</div>

View file

@ -1,44 +0,0 @@
<?php
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
\OCP\Util::addScript('core', 'login/grant', 'core');
style('core', 'login/authpicker');
/** @var array $_ */
/** @var \OCP\IURLGenerator $urlGenerator */
$urlGenerator = $_['urlGenerator'];
?>
<div class="picker-window small">
<h2><?php p($l->t('Account access')) ?></h2>
<p class="info">
<?php p($l->t('Currently logged in as %1$s (%2$s).', [
$_['userDisplayName'],
$_['userId'],
])) ?>
</p>
<p class="info">
<?php print_unescaped($l->t('You are about to grant %1$s access to your %2$s account.', [
'<strong>' . \OCP\Util::sanitizeHTML($_['client']) . '</strong>',
\OCP\Util::sanitizeHTML($_['instanceName'])
])) ?>
</p>
<br/>
<p id="redirect-link">
<form method="POST" action="<?php p($urlGenerator->linkToRouteAbsolute('core.ClientFlowLoginV2.generateAppPassword')) ?>">
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
<input type="hidden" name="stateToken" value="<?php p($_['stateToken']) ?>" />
<?php if ($_['direct']) { ?>
<input type="hidden" name="direct" value="1" />
<?php } ?>
<div id="submit-wrapper">
<input type="submit" class="login primary icon-confirm-white" title="" value="<?php p($l->t('Grant access')); ?>" />
</div>
</form>
</p>
</div>

2
dist/2426-2426.js vendored Normal file

File diff suppressed because one or more lines are too long

136
dist/2426-2426.js.license vendored Normal file
View file

@ -0,0 +1,136 @@
SPDX-License-Identifier: MIT
SPDX-License-Identifier: ISC
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-License-Identifier: BSD-3-Clause
SPDX-License-Identifier: AGPL-3.0-or-later
SPDX-License-Identifier: (MPL-2.0 OR Apache-2.0)
SPDX-FileCopyrightText: escape-html developers
SPDX-FileCopyrightText: debounce developers
SPDX-FileCopyrightText: atomiks
SPDX-FileCopyrightText: Tobias Koppers @sokra
SPDX-FileCopyrightText: T. Jameson Little <t.jameson.little@gmail.com>
SPDX-FileCopyrightText: Roman Shtylman <shtylman@gmail.com>
SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
SPDX-FileCopyrightText: Matt Zabriskie
SPDX-FileCopyrightText: Guillaume Chau
SPDX-FileCopyrightText: GitHub Inc.
SPDX-FileCopyrightText: Feross Aboukhadijeh
SPDX-FileCopyrightText: Evan You
SPDX-FileCopyrightText: Eduardo San Martin Morote
SPDX-FileCopyrightText: Dr.-Ing. Mario Heiderich, Cure53 <mario@cure53.de> (https://cure53.de/)
SPDX-FileCopyrightText: David Clark
SPDX-FileCopyrightText: Christoph Wurst
This file is generated from multiple sources. Included packages:
- @floating-ui/core
- version: 1.7.3
- license: MIT
- @floating-ui/utils
- version: 0.2.10
- license: MIT
- @nextcloud/auth
- version: 2.5.3
- license: GPL-3.0-or-later
- @nextcloud/axios
- version: 2.5.2
- license: GPL-3.0-or-later
- @nextcloud/browser-storage
- version: 0.5.0
- license: GPL-3.0-or-later
- @nextcloud/capabilities
- version: 1.2.1
- license: GPL-3.0-or-later
- semver
- version: 7.7.2
- license: ISC
- @nextcloud/event-bus
- version: 3.3.3
- license: GPL-3.0-or-later
- @nextcloud/initial-state
- version: 3.0.0
- license: GPL-3.0-or-later
- @nextcloud/l10n
- version: 3.4.1
- license: GPL-3.0-or-later
- @nextcloud/logger
- version: 3.0.3
- license: GPL-3.0-or-later
- @nextcloud/vue
- version: 9.2.0
- license: AGPL-3.0-or-later
- @vue/reactivity
- version: 3.5.24
- license: MIT
- @vue/runtime-core
- version: 3.5.24
- license: MIT
- @vue/runtime-dom
- version: 3.5.24
- license: MIT
- @vue/shared
- version: 3.5.24
- license: MIT
- vue-router
- version: 4.6.3
- license: MIT
- vue
- version: 3.5.24
- license: MIT
- @nextcloud/password-confirmation
- version: 6.0.2
- license: MIT
- @nextcloud/router
- version: 3.1.0
- license: GPL-3.0-or-later
- @nextcloud/vue
- version: 8.35.0
- license: AGPL-3.0-or-later
- @vue/devtools-api
- version: 6.6.4
- license: MIT
- axios
- version: 1.12.2
- license: MIT
- base64-js
- version: 1.5.1
- license: MIT
- css-loader
- version: 7.1.2
- license: MIT
- debounce
- version: 3.0.0
- license: MIT
- dompurify
- version: 3.3.1
- license: (MPL-2.0 OR Apache-2.0)
- escape-html
- version: 1.0.3
- license: MIT
- focus-trap
- version: 7.6.6
- license: MIT
- ieee754
- version: 1.2.1
- license: BSD-3-Clause
- buffer
- version: 6.0.3
- license: MIT
- process
- version: 0.11.10
- license: MIT
- style-loader
- version: 4.0.0
- license: MIT
- tabbable
- version: 6.3.0
- license: MIT
- vue-loader
- version: 15.11.1
- license: MIT
- vue
- version: 2.7.16
- license: MIT
- nextcloud
- version: 1.0.0
- license: AGPL-3.0-or-later

1
dist/2426-2426.js.map vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/2426-2426.js.map.license vendored Symbolic link
View file

@ -0,0 +1 @@
2426-2426.js.license

2
dist/7867-7867.js vendored Normal file

File diff suppressed because one or more lines are too long

104
dist/7867-7867.js.license vendored Normal file
View file

@ -0,0 +1,104 @@
SPDX-License-Identifier: MIT
SPDX-License-Identifier: ISC
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-License-Identifier: BSD-3-Clause
SPDX-License-Identifier: AGPL-3.0-or-later
SPDX-License-Identifier: (MPL-2.0 OR Apache-2.0)
SPDX-FileCopyrightText: escape-html developers
SPDX-FileCopyrightText: debounce developers
SPDX-FileCopyrightText: Tobias Koppers @sokra
SPDX-FileCopyrightText: T. Jameson Little <t.jameson.little@gmail.com>
SPDX-FileCopyrightText: Roman Shtylman <shtylman@gmail.com>
SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
SPDX-FileCopyrightText: Matt Zabriskie
SPDX-FileCopyrightText: GitHub Inc.
SPDX-FileCopyrightText: Feross Aboukhadijeh
SPDX-FileCopyrightText: Evan You
SPDX-FileCopyrightText: Dr.-Ing. Mario Heiderich, Cure53 <mario@cure53.de> (https://cure53.de/)
SPDX-FileCopyrightText: Christoph Wurst
SPDX-FileCopyrightText: Anthony Fu <https://github.com/antfu>
SPDX-FileCopyrightText: Anthony Fu <anthonyfu117@hotmail.com>
This file is generated from multiple sources. Included packages:
- @nextcloud/auth
- version: 2.5.3
- license: GPL-3.0-or-later
- @nextcloud/axios
- version: 2.5.2
- license: GPL-3.0-or-later
- @nextcloud/browser-storage
- version: 0.5.0
- license: GPL-3.0-or-later
- semver
- version: 7.7.2
- license: ISC
- @nextcloud/event-bus
- version: 3.3.3
- license: GPL-3.0-or-later
- @nextcloud/initial-state
- version: 3.0.0
- license: GPL-3.0-or-later
- @nextcloud/l10n
- version: 3.4.1
- license: GPL-3.0-or-later
- @nextcloud/logger
- version: 3.0.3
- license: GPL-3.0-or-later
- @nextcloud/router
- version: 3.1.0
- license: GPL-3.0-or-later
- @nextcloud/initial-state
- version: 2.2.0
- license: GPL-3.0-or-later
- debounce
- version: 2.2.0
- license: MIT
- @nextcloud/vue
- version: 8.35.0
- license: AGPL-3.0-or-later
- @vueuse/core
- version: 11.3.0
- license: MIT
- @vueuse/shared
- version: 11.3.0
- license: MIT
- axios
- version: 1.12.2
- license: MIT
- base64-js
- version: 1.5.1
- license: MIT
- css-loader
- version: 7.1.2
- license: MIT
- dompurify
- version: 3.3.1
- license: (MPL-2.0 OR Apache-2.0)
- escape-html
- version: 1.0.3
- license: MIT
- ieee754
- version: 1.2.1
- license: BSD-3-Clause
- buffer
- version: 6.0.3
- license: MIT
- process
- version: 0.11.10
- license: MIT
- style-loader
- version: 4.0.0
- license: MIT
- vue-demi
- version: 0.14.10
- license: MIT
- vue-loader
- version: 15.11.1
- license: MIT
- vue
- version: 2.7.16
- license: MIT
- nextcloud
- version: 1.0.0
- license: AGPL-3.0-or-later

1
dist/7867-7867.js.map vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/7867-7867.js.map.license vendored Symbolic link
View file

@ -0,0 +1 @@
7867-7867.js.license

2
dist/9811-9811.js vendored Normal file
View file

@ -0,0 +1,2 @@
"use strict";(globalThis.webpackChunknextcloud_ui_legacy=globalThis.webpackChunknextcloud_ui_legacy||[]).push([[9811],{3357(n,t,e){e.d(t,{A:()=>c});var o=e(71354),l=e.n(o),s=e(76314),i=e.n(s)()(l());i.push([n.id,"\n._loginFlowContainer_OSz1H {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n","",{version:3,sources:["webpack://./core/src/components/LoginFlow/LoginFlowContainer.vue"],names:[],mappings:";AAqBA;CACA,aAAA;CACA,sBAAA;AACA",sourcesContent:['\x3c!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n--\x3e\n\n<script setup lang="ts">\nimport NcGuestContent from \'@nextcloud/vue/components/NcGuestContent\'\n\ndefineProps<{\n\theading: string\n}>()\n<\/script>\n\n<template>\n\t<NcGuestContent class="picker-window" :class="$style.loginFlowContainer">\n\t\t<h2>{{ heading }}</h2>\n\t\t<slot />\n\t</NcGuestContent>\n</template>\n\n<style module>\n.loginFlowContainer {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n</style>\n'],sourceRoot:""}]),i.locals={loginFlowContainer:"_loginFlowContainer_OSz1H"};const c=i},7579(n,t,e){e.d(t,{A:()=>x});var o=e(85471),l=e(66768);const s=(0,o.pM)({__name:"LoginFlowContainer",props:{heading:null},setup:n=>({__sfc:!0,NcGuestContent:l.A})});var i=e(85072),c=e.n(i),r=e(97825),a=e.n(r),u=e(77659),d=e.n(u),p=e(55056),_=e.n(p),A=e(10540),C=e.n(A),g=e(41113),w=e.n(g),h=e(3357),f={};f.styleTagTransform=w(),f.setAttributes=_(),f.insert=d().bind(null,"head"),f.domAPI=a(),f.insertStyleElement=C(),c()(h.A,f);const m=h.A&&h.A.locals?h.A.locals:void 0,x=(0,e(14486).A)(s,function(){var n=this,t=n._self._c;return t(n._self._setupProxy.NcGuestContent,{staticClass:"picker-window",class:n.$style.loginFlowContainer},[t("h2",[n._v(n._s(n.heading))]),n._v(" "),n._t("default")],2)},[],!1,function(n){this.$style=m.locals||m},null,null).exports},59811(n,t,e){e.r(t),e.d(t,{default:()=>r});var o=e(85471),l=e(53334),s=e(371),i=e(7579);const c=(0,o.pM)({__name:"LoginFlowDone",setup:n=>({__sfc:!0,t:l.t,NcNoteCard:s.A,LoginFlowContainer:i.A})}),r=(0,e(14486).A)(c,function(){var n=this,t=n._self._c,e=n._self._setupProxy;return t(e.LoginFlowContainer,{attrs:{heading:e.t("core","Account connected")}},[t(e.NcNoteCard,{attrs:{type:"info"}},[n._v("\n\t\t"+n._s(e.t("core","Your client should now be connected!"))+"\n\t\t"),t("br"),n._v("\n\t\t"+n._s(e.t("core","You can close this window."))+"\n\t")])],1)},[],!1,null,null,null).exports}}]);
//# sourceMappingURL=9811-9811.js.map?v=975f353a252dd0095921

42
dist/9811-9811.js.license vendored Normal file
View file

@ -0,0 +1,42 @@
SPDX-License-Identifier: MIT
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-License-Identifier: AGPL-3.0-or-later
SPDX-License-Identifier: (MPL-2.0 OR Apache-2.0)
SPDX-FileCopyrightText: escape-html developers
SPDX-FileCopyrightText: Tobias Koppers @sokra
SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
SPDX-FileCopyrightText: Evan You
SPDX-FileCopyrightText: Dr.-Ing. Mario Heiderich, Cure53 <mario@cure53.de> (https://cure53.de/)
This file is generated from multiple sources. Included packages:
- @nextcloud/l10n
- version: 3.4.1
- license: GPL-3.0-or-later
- @nextcloud/router
- version: 3.1.0
- license: GPL-3.0-or-later
- @nextcloud/vue
- version: 8.35.0
- license: AGPL-3.0-or-later
- css-loader
- version: 7.1.2
- license: MIT
- dompurify
- version: 3.3.1
- license: (MPL-2.0 OR Apache-2.0)
- escape-html
- version: 1.0.3
- license: MIT
- style-loader
- version: 4.0.0
- license: MIT
- vue-loader
- version: 15.11.1
- license: MIT
- vue
- version: 2.7.16
- license: MIT
- nextcloud
- version: 1.0.0
- license: AGPL-3.0-or-later

1
dist/9811-9811.js.map vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/9811-9811.js.map.license vendored Symbolic link
View file

@ -0,0 +1 @@
9811-9811.js.license

4
dist/core-common.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
dist/core-login_flow.js vendored Normal file
View file

@ -0,0 +1,2 @@
(()=>{"use strict";var e,r,t,o={43925(e,r,t){var o=t(21777),a=t(81222),n=t(85471);t.nc=(0,o.aV)();const l=(0,n.$V)(()=>Promise.all([t.e(4208),t.e(7867)]).then(t.bind(t,50412))),i=(0,n.$V)(()=>Promise.all([t.e(4208),t.e(2426)]).then(t.bind(t,32426))),c=(0,n.$V)(()=>Promise.all([t.e(4208),t.e(9811)]).then(t.bind(t,59811))),d=(0,a.C)("core","loginFlowState");new n.Ay({render:e=>e("auth"===d?l:"grant"===d?i:c)}).$mount("#core-loginflow")}},a={};function n(e){var r=a[e];if(void 0!==r)return r.exports;var t=a[e]={id:e,loaded:!1,exports:{}};return o[e].call(t.exports,t,t.exports,n),t.loaded=!0,t.exports}n.m=o,e=[],n.O=(r,t,o,a)=>{if(!t){var l=1/0;for(u=0;u<e.length;u++){for(var[t,o,a]=e[u],i=!0,c=0;c<t.length;c++)(!1&a||l>=a)&&Object.keys(n.O).every(e=>n.O[e](t[c]))?t.splice(c--,1):(i=!1,a<l&&(l=a));if(i){e.splice(u--,1);var d=o();void 0!==d&&(r=d)}}return r}a=a||0;for(var u=e.length;u>0&&e[u-1][2]>a;u--)e[u]=e[u-1];e[u]=[t,o,a]},n.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return n.d(r,{a:r}),r},n.d=(e,r)=>{for(var t in r)n.o(r,t)&&!n.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce((r,t)=>(n.f[t](e,r),r),[])),n.u=e=>e+"-"+e+".js?v="+{2426:"7593fca92590d7569251",7867:"fe18f7f990988eb27475",9811:"975f353a252dd0095921"}[e],n.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},t="nextcloud-ui-legacy:",n.l=(e,o,a,l)=>{if(r[e])r[e].push(o);else{var i,c;if(void 0!==a)for(var d=document.getElementsByTagName("script"),u=0;u<d.length;u++){var s=d[u];if(s.getAttribute("src")==e||s.getAttribute("data-webpack")==t+a){i=s;break}}i||(c=!0,(i=document.createElement("script")).charset="utf-8",n.nc&&i.setAttribute("nonce",n.nc),i.setAttribute("data-webpack",t+a),i.src=e),r[e]=[o];var p=(t,o)=>{i.onerror=i.onload=null,clearTimeout(f);var a=r[e];if(delete r[e],i.parentNode&&i.parentNode.removeChild(i),a&&a.forEach(e=>e(o)),t)return t(o)},f=setTimeout(p.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),c&&document.head.appendChild(i)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),n.j=3181,(()=>{var e;globalThis.importScripts&&(e=globalThis.location+"");var r=globalThis.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var o=t.length-1;o>-1&&(!e||!/^http(s?):/.test(e));)e=t[o--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),n.p=e})(),(()=>{n.b="undefined"!=typeof document&&document.baseURI||self.location.href;var e={3181:0};n.f.j=(r,t)=>{var o=n.o(e,r)?e[r]:void 0;if(0!==o)if(o)t.push(o[2]);else{var a=new Promise((t,a)=>o=e[r]=[t,a]);t.push(o[2]=a);var l=n.p+n.u(r),i=new Error;n.l(l,t=>{if(n.o(e,r)&&(0!==(o=e[r])&&(e[r]=void 0),o)){var a=t&&("load"===t.type?"missing":t.type),l=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+a+": "+l+")",i.name="ChunkLoadError",i.type=a,i.request=l,o[1](i)}},"chunk-"+r,r)}},n.O.j=r=>0===e[r];var r=(r,t)=>{var o,a,[l,i,c]=t,d=0;if(l.some(r=>0!==e[r])){for(o in i)n.o(i,o)&&(n.m[o]=i[o]);if(c)var u=c(n)}for(r&&r(t);d<l.length;d++)a=l[d],n.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return n.O(u)},t=globalThis.webpackChunknextcloud_ui_legacy=globalThis.webpackChunknextcloud_ui_legacy||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),n.nc=void 0;var l=n.O(void 0,[4208],()=>n(43925));l=n.O(l)})();
//# sourceMappingURL=core-login_flow.js.map?v=96b339a389e0e8f30783

40
dist/core-login_flow.js.license vendored Normal file
View file

@ -0,0 +1,40 @@
SPDX-License-Identifier: MIT
SPDX-License-Identifier: ISC
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-License-Identifier: AGPL-3.0-or-later
SPDX-FileCopyrightText: Tobias Koppers @sokra
SPDX-FileCopyrightText: Roman Shtylman <shtylman@gmail.com>
SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
SPDX-FileCopyrightText: GitHub Inc.
SPDX-FileCopyrightText: Evan You
SPDX-FileCopyrightText: Christoph Wurst
This file is generated from multiple sources. Included packages:
- @nextcloud/auth
- version: 2.5.3
- license: GPL-3.0-or-later
- @nextcloud/browser-storage
- version: 0.5.0
- license: GPL-3.0-or-later
- semver
- version: 7.7.2
- license: ISC
- @nextcloud/event-bus
- version: 3.3.3
- license: GPL-3.0-or-later
- @nextcloud/initial-state
- version: 3.0.0
- license: GPL-3.0-or-later
- process
- version: 0.11.10
- license: MIT
- vue
- version: 2.7.16
- license: MIT
- webpack
- version: 5.104.1
- license: MIT
- nextcloud
- version: 1.0.0
- license: AGPL-3.0-or-later

1
dist/core-login_flow.js.map vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/core-login_flow.js.map.license vendored Symbolic link
View file

@ -0,0 +1 @@
core-login_flow.js.license

4
dist/files-main.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -22,6 +22,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\Defaults;
use OCP\EventDispatcher\IEventDispatcher;
@ -53,6 +54,7 @@ class ClientFlowLoginControllerTest extends TestCase {
private IEventDispatcher&MockObject $eventDispatcher;
private ITimeFactory&MockObject $timeFactory;
private IConfig&MockObject $config;
private IInitialState&MockObject $initialState;
private ClientFlowLoginController $clientFlowLoginController;
@ -79,6 +81,7 @@ class ClientFlowLoginControllerTest extends TestCase {
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
$this->timeFactory = $this->createMock(ITimeFactory::class);
$this->config = $this->createMock(IConfig::class);
$this->initialState = $this->createMock(IInitialState::class);
$this->clientFlowLoginController = new ClientFlowLoginController(
'core',
@ -96,6 +99,7 @@ class ClientFlowLoginControllerTest extends TestCase {
$this->eventDispatcher,
$this->timeFactory,
$this->config,
$this->initialState,
);
}
@ -138,7 +142,7 @@ class ClientFlowLoginControllerTest extends TestCase {
->method('set')
->with('client.flow.state.token', 'StateToken');
$this->session
->expects($this->once())
->expects($this->atLeastOnce())
->method('get')
->with('oauth.state')
->willReturn('OauthStateToken');
@ -154,27 +158,39 @@ class ClientFlowLoginControllerTest extends TestCase {
->method('getServerProtocol')
->willReturn('https');
$initialState = [];
$this->initialState->expects($this->exactly(2))
->method('provideInitialState')
->willReturnCallback(function () use (&$initialState) {
$initialState[] = func_get_args();
});
$expected = new StandaloneTemplateResponse(
'core',
'loginflow/authpicker',
[
'client' => 'Mac OS X Sync Client',
'clientIdentifier' => '',
'instanceName' => 'ExampleCloud',
'urlGenerator' => $this->urlGenerator,
'stateToken' => 'StateToken',
'serverHost' => 'https://example.com',
'oauthState' => 'OauthStateToken',
'user' => '',
'direct' => 0,
'providedRedirectUri' => '',
],
'guest'
'loginflow',
renderAs: 'guest'
);
$csp = new ContentSecurityPolicy();
$csp->addAllowedFormActionDomain('nc://*');
$expected->setContentSecurityPolicy($csp);
$this->assertEquals($expected, $this->clientFlowLoginController->showAuthPickerPage());
self::assertEquals([
['loginFlowState', 'auth'],
[
'loginFlowAuth', [
'client' => 'Mac OS X Sync Client',
'clientIdentifier' => '',
'instanceName' => 'ExampleCloud',
'stateToken' => 'StateToken',
'serverHost' => 'https://example.com',
'oauthState' => 'OauthStateToken',
'direct' => false,
'providedRedirectUri' => '',
'appTokenUrl' => '',
'loginRedirectUrl' => '',
],
],
], $initialState);
}
public function testShowAuthPickerPageWithOauth(): void {
@ -205,7 +221,7 @@ class ClientFlowLoginControllerTest extends TestCase {
->method('set')
->with('client.flow.state.token', 'StateToken');
$this->session
->expects($this->once())
->expects($this->atLeastOnce())
->method('get')
->with('oauth.state')
->willReturn('OauthStateToken');
@ -221,27 +237,39 @@ class ClientFlowLoginControllerTest extends TestCase {
->method('getServerProtocol')
->willReturn('https');
$initialState = [];
$this->initialState->expects($this->exactly(2))
->method('provideInitialState')
->willReturnCallback(function () use (&$initialState) {
$initialState[] = func_get_args();
});
$expected = new StandaloneTemplateResponse(
'core',
'loginflow/authpicker',
[
'client' => 'My external service',
'clientIdentifier' => 'MyClientIdentifier',
'instanceName' => 'ExampleCloud',
'urlGenerator' => $this->urlGenerator,
'stateToken' => 'StateToken',
'serverHost' => 'https://example.com',
'oauthState' => 'OauthStateToken',
'user' => '',
'direct' => 0,
'providedRedirectUri' => '',
],
'guest'
'loginflow',
renderAs: 'guest'
);
$csp = new ContentSecurityPolicy();
$csp->addAllowedFormActionDomain('https://example.com/redirect.php');
$expected->setContentSecurityPolicy($csp);
$this->assertEquals($expected, $this->clientFlowLoginController->showAuthPickerPage('MyClientIdentifier'));
self::assertEquals([
['loginFlowState', 'auth'],
[
'loginFlowAuth', [
'client' => 'My external service',
'clientIdentifier' => 'MyClientIdentifier',
'instanceName' => 'ExampleCloud',
'stateToken' => 'StateToken',
'serverHost' => 'https://example.com',
'oauthState' => 'OauthStateToken',
'direct' => false,
'providedRedirectUri' => '',
'appTokenUrl' => '',
'loginRedirectUrl' => '',
],
],
], $initialState);
}
public function testGenerateAppPasswordWithInvalidToken(): void {

View file

@ -17,6 +17,7 @@ use OC\Core\Service\LoginFlowV2Service;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\StandaloneTemplateResponse;
use OCP\AppFramework\Services\IInitialState;
use OCP\Defaults;
use OCP\IL10N;
use OCP\IRequest;
@ -29,22 +30,15 @@ use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
class ClientFlowLoginV2ControllerTest extends TestCase {
/** @var IRequest|MockObject */
private $request;
/** @var LoginFlowV2Service|MockObject */
private $loginFlowV2Service;
/** @var IURLGenerator|MockObject */
private $urlGenerator;
/** @var ISession|MockObject */
private $session;
/** @var IUserSession|MockObject */
private $userSession;
/** @var ISecureRandom|MockObject */
private $random;
/** @var Defaults|MockObject */
private $defaults;
/** @var IL10N|MockObject */
private $l;
private IRequest&MockObject $request;
private LoginFlowV2Service&MockObject $loginFlowV2Service;
private IURLGenerator&MockObject $urlGenerator;
private ISession&MockObject $session;
private IUserSession&MockObject $userSession;
private ISecureRandom&MockObject $random;
private Defaults&MockObject $defaults;
private IInitialState&MockObject $initialState;
private IL10N&MockObject $l;
/** @var ClientFlowLoginV2Controller */
private $controller;
@ -58,6 +52,7 @@ class ClientFlowLoginV2ControllerTest extends TestCase {
$this->userSession = $this->createMock(IUserSession::class);
$this->random = $this->createMock(ISecureRandom::class);
$this->defaults = $this->createMock(Defaults::class);
$this->initialState = $this->createMock(IInitialState::class);
$this->l = $this->createMock(IL10N::class);
$this->l
->expects($this->any())
@ -75,7 +70,8 @@ class ClientFlowLoginV2ControllerTest extends TestCase {
$this->random,
$this->defaults,
'user',
$this->l
$this->l,
$this->initialState,
);
}