From 3713f40d5ba84767891ab9bfcf0b97c6814e2d7d Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 9 Jan 2026 17:59:01 +0100 Subject: [PATCH] fix(app-password): Require strict password confirmation Signed-off-by: Joas Schilling --- .../lib/Controller/AuthSettingsController.php | 2 +- apps/settings/src/store/authtoken.ts | 6 +++--- .../AccountMenu/AccountMenuProfileEntry.vue | 12 ++++++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/settings/lib/Controller/AuthSettingsController.php b/apps/settings/lib/Controller/AuthSettingsController.php index 54c15fd14f6..251f1f6ea53 100644 --- a/apps/settings/lib/Controller/AuthSettingsController.php +++ b/apps/settings/lib/Controller/AuthSettingsController.php @@ -59,7 +59,7 @@ class AuthSettingsController extends Controller { * @param bool $qrcodeLogin If set to true, the returned token could be (depending on server settings) a onetime password, that can only be used to get the actual app password a single time */ #[NoAdminRequired] - #[PasswordConfirmationRequired] + #[PasswordConfirmationRequired(strict: true)] public function create(string $name = '', bool $qrcodeLogin = false): JSONResponse { if ($this->checkAppToken()) { return $this->getServiceNotAvailableResponse(); diff --git a/apps/settings/src/store/authtoken.ts b/apps/settings/src/store/authtoken.ts index 542a6f73547..9ea81e69e52 100644 --- a/apps/settings/src/store/authtoken.ts +++ b/apps/settings/src/store/authtoken.ts @@ -6,12 +6,13 @@ import axios from '@nextcloud/axios' import { showError } from '@nextcloud/dialogs' import { loadState } from '@nextcloud/initial-state' import { translate as t } from '@nextcloud/l10n' -import { confirmPassword } from '@nextcloud/password-confirmation' +import { addPasswordConfirmationInterceptors, confirmPassword, PwdConfirmationMode } from '@nextcloud/password-confirmation' import { generateUrl } from '@nextcloud/router' import { defineStore } from 'pinia' import logger from '../logger.ts' const BASE_URL = generateUrl('/settings/personal/authtokens') +addPasswordConfirmationInterceptors(axios) /** * @@ -89,9 +90,8 @@ export const useAuthTokenStore = defineStore('auth-token', { logger.debug('Creating a new app token') try { - await confirmPassword() + const { data } = await axios.post(BASE_URL, { name, oneTime: true }, { confirmPassword: PwdConfirmationMode.Strict }) - const { data } = await axios.post(BASE_URL, { name, oneTime: true }) this.tokens.push(data.deviceToken) logger.debug('App token created') return data diff --git a/core/src/components/AccountMenu/AccountMenuProfileEntry.vue b/core/src/components/AccountMenu/AccountMenuProfileEntry.vue index 04db713d67b..d6411f03729 100644 --- a/core/src/components/AccountMenu/AccountMenuProfileEntry.vue +++ b/core/src/components/AccountMenu/AccountMenuProfileEntry.vue @@ -36,7 +36,7 @@ import axios from '@nextcloud/axios' import { getCapabilities } from '@nextcloud/capabilities' import { subscribe, unsubscribe } from '@nextcloud/event-bus' import { loadState } from '@nextcloud/initial-state' -import { confirmPassword } from '@nextcloud/password-confirmation' +import { addPasswordConfirmationInterceptors, PwdConfirmationMode } from '@nextcloud/password-confirmation' import { generateUrl } from '@nextcloud/router' import { spawnDialog } from '@nextcloud/vue/functions/dialog' import { defineComponent } from 'vue' @@ -46,6 +46,8 @@ import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon' import IconQrcodeScan from 'vue-material-design-icons/QrcodeScan.vue' import AccountQrLoginDialog from './AccountQRLoginDialog.vue' +addPasswordConfirmationInterceptors(axios) + const { profileEnabled } = loadState('user_status', 'profileEnabled', { profileEnabled: false }) // @ts-expect-error capabilities is missing the capability to type it... @@ -115,9 +117,11 @@ export default defineComponent({ }, async handleQrCodeClick() { - await confirmPassword() - - const { data } = await axios.post(generateUrl('/settings/personal/authtokens'), { qrcodeLogin: true }) + const { data } = await axios.post( + generateUrl('/settings/personal/authtokens'), + { qrcodeLogin: true }, + { confirmPassword: PwdConfirmationMode.Strict }, + ) await spawnDialog(AccountQrLoginDialog, { data }) },