diff options
author | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2024-09-13 13:57:30 +0200 |
---|---|---|
committer | backportbot[bot] <backportbot[bot]@users.noreply.github.com> | 2024-09-13 15:21:45 +0000 |
commit | 89bf1287086f79b252cf64d787034b9c8c72f130 (patch) | |
tree | 41a9e7165fd483bfbbe3c3145b934deb7659667e /apps | |
parent | 91533fb6f7ac0d61f8016aafe5e06bed75fb7498 (diff) | |
download | nextcloud-server-89bf1287086f79b252cf64d787034b9c8c72f130.tar.gz nextcloud-server-89bf1287086f79b252cf64d787034b9c8c72f130.zip |
fix(files_external): broken credentials dialog
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
Diffstat (limited to 'apps')
-rw-r--r-- | apps/files_external/appinfo/routes.php | 5 | ||||
-rw-r--r-- | apps/files_external/lib/Controller/ApiController.php | 28 | ||||
-rw-r--r-- | apps/files_external/src/actions/enterCredentialsAction.ts | 70 | ||||
-rw-r--r-- | apps/files_external/src/views/CredentialsDialog.vue | 86 |
4 files changed, 119 insertions, 70 deletions
diff --git a/apps/files_external/appinfo/routes.php b/apps/files_external/appinfo/routes.php index b3f82cbad74..18418cc19c3 100644 --- a/apps/files_external/appinfo/routes.php +++ b/apps/files_external/appinfo/routes.php @@ -40,10 +40,5 @@ return [ 'url' => '/api/v1/mounts', 'verb' => 'GET', ], - [ - 'name' => 'Api#askNativeAuth', - 'url' => '/api/v1/auth', - 'verb' => 'GET', - ], ], ]; diff --git a/apps/files_external/lib/Controller/ApiController.php b/apps/files_external/lib/Controller/ApiController.php index 56242938593..10fd120c3d9 100644 --- a/apps/files_external/lib/Controller/ApiController.php +++ b/apps/files_external/lib/Controller/ApiController.php @@ -15,7 +15,6 @@ use OCA\Files_External\Service\UserGlobalStoragesService; use OCA\Files_External\Service\UserStoragesService; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\NoAdminRequired; -use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCSController; use OCP\IRequest; @@ -103,31 +102,4 @@ class ApiController extends OCSController { return new DataResponse($entries); } - - /** - * Ask for credentials using a browser's native basic auth prompt - * Then returns it if provided - */ - #[NoAdminRequired] - #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)] - public function askNativeAuth(): DataResponse { - if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) { - $response = new DataResponse([], Http::STATUS_UNAUTHORIZED); - $response->addHeader('WWW-Authenticate', 'Basic realm="Storage authentification needed"'); - return $response; - } - - $user = $_SERVER['PHP_AUTH_USER']; - $password = $_SERVER['PHP_AUTH_PW']; - - // Reset auth - unset($_SERVER['PHP_AUTH_USER']); - unset($_SERVER['PHP_AUTH_PW']); - - // Using 401 again to ensure we clear any cached Authorization - return new DataResponse([ - 'user' => $user, - 'password' => $password, - ], Http::STATUS_UNAUTHORIZED); - } } diff --git a/apps/files_external/src/actions/enterCredentialsAction.ts b/apps/files_external/src/actions/enterCredentialsAction.ts index 78377dc557c..29d660315b4 100644 --- a/apps/files_external/src/actions/enterCredentialsAction.ts +++ b/apps/files_external/src/actions/enterCredentialsAction.ts @@ -7,29 +7,39 @@ import type { AxiosResponse } from '@nextcloud/axios' import type { Node } from '@nextcloud/files' import type { StorageConfig } from '../services/externalStorage' -import { generateOcsUrl, generateUrl } from '@nextcloud/router' -import { showError, showSuccess } from '@nextcloud/dialogs' +import { generateUrl } from '@nextcloud/router' +import { showError, showSuccess, spawnDialog } from '@nextcloud/dialogs' import { translate as t } from '@nextcloud/l10n' import axios from '@nextcloud/axios' import LoginSvg from '@mdi/svg/svg/login.svg?raw' -import Vue from 'vue' +import Vue, { defineAsyncComponent } from 'vue' import { FileAction, DefaultType } from '@nextcloud/files' import { STORAGE_STATUS, isMissingAuthConfig } from '../utils/credentialsUtils' import { isNodeExternalStorage } from '../utils/externalStorageUtils' -type OCSAuthResponse = { - ocs: { - meta: { - status: string - statuscode: number - message: string - }, - data: { - user?: string, - password?: string, - } +type CredentialResponse = { + login?: string, + password?: string, +} + +async function setCredentials(node: Node, login: string, password: string): Promise<null|true> { + const configResponse = await axios.put(generateUrl('apps/files_external/userglobalstorages/{id}', node.attributes), { + backendOptions: { user: login, password }, + }) as AxiosResponse<StorageConfig> + + const config = configResponse.data + if (config.status !== STORAGE_STATUS.SUCCESS) { + showError(t('files_external', 'Unable to update this external storage config. {statusMessage}', { + statusMessage: config?.statusMessage || '', + })) + return null } + + // Success update config attribute + showSuccess(t('files_external', 'New configuration successfully saved')) + Vue.set(node.attributes, 'config', config) + return true } export const action = new FileAction({ @@ -57,30 +67,16 @@ export const action = new FileAction({ }, async exec(node: Node) { - // always resolve auth request, we'll process the data afterwards - // Using fetch as axios have integrated auth handling and X-Requested-With header - const response = await fetch(generateOcsUrl('/apps/files_external/api/v1/auth'), { - headers: new Headers({ Accept: 'application/json' }), - credentials: 'include', - }) - - const data = (await response?.json() || {}) as OCSAuthResponse - if (data.ocs.data.user && data.ocs.data.password) { - const configResponse = await axios.put(generateUrl('apps/files_external/userglobalstorages/{id}', node.attributes), { - backendOptions: data.ocs.data, - }) as AxiosResponse<StorageConfig> - - const config = configResponse.data - if (config.status !== STORAGE_STATUS.SUCCESS) { - showError(t('files_external', 'Unable to update this external storage config. {statusMessage}', { - statusMessage: config?.statusMessage || '', - })) - return null - } + const { login, password } = await new Promise<CredentialResponse>(resolve => spawnDialog( + defineAsyncComponent(() => import('../views/CredentialsDialog.vue')), + {}, + (args) => { + resolve(args as CredentialResponse) + }, + )) - // Success update config attribute - showSuccess(t('files_external', 'New configuration successfully saved')) - Vue.set(node.attributes, 'config', config) + if (login && password) { + return await setCredentials(node, login, password) } return null diff --git a/apps/files_external/src/views/CredentialsDialog.vue b/apps/files_external/src/views/CredentialsDialog.vue new file mode 100644 index 00000000000..c9a9539f061 --- /dev/null +++ b/apps/files_external/src/views/CredentialsDialog.vue @@ -0,0 +1,86 @@ +<!-- + - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> + +<template> + <NcDialog :buttons="dialogButtons" + class="external-storage-auth" + close-on-click-outside + data-cy-external-storage-auth + is-form + :name="t('files_external', 'Storage credentials')" + out-transition + @submit="$emit('close', {login, password})" + @update:open="$emit('close')"> + <!-- Header --> + <NcNoteCard class="external-storage-auth__header" + :text="t('files_external', 'To access the storage, you need to provide the authentification informations.')" + type="info" /> + + <!-- Login --> + <NcTextField ref="login" + class="external-storage-auth__login" + data-cy-external-storage-auth-dialog-login + :label="t('files_external', 'Login')" + :placeholder="t('files_external', 'Enter the storage login')" + minlength="2" + name="login" + required + :value.sync="login" /> + + <!-- Password --> + <NcPasswordField ref="password" + class="external-storage-auth__password" + data-cy-external-storage-auth-dialog-password + :label="t('files_external', 'Password')" + :placeholder="t('files_external', 'Enter the storage password')" + name="password" + required + :value.sync="password" /> + </NcDialog> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue' +import { t } from '@nextcloud/l10n' + +import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js' +import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js' +import NcPasswordField from '@nextcloud/vue/dist/Components/NcPasswordField.js' +import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' + +export default defineComponent({ + name: 'CredentialsDialog', + + components: { + NcDialog, + NcNoteCard, + NcTextField, + NcPasswordField, + }, + + setup() { + return { + t, + } + }, + + data() { + return { + login: '', + password: '', + } + }, + + computed: { + dialogButtons() { + return [{ + label: t('files_external', 'Submit'), + type: 'primary', + nativeType: 'submit', + }] + }, + }, +}) +</script> |