From 82fb2e1bb327f70067cce88ce046ec7d84b3de84 Mon Sep 17 00:00:00 2001 From: Peter Ringelmann Date: Tue, 5 May 2026 14:30:01 +0200 Subject: [PATCH] fix(core): prompt for password once when installing recommended apps Wire the password-confirmation interceptors into the recommendedapps entry point and switch the installer to a single bulk enable call so the strict password confirmation on enableApps is satisfied. Fixes #60068 -e Signed-off-by: Peter Ringelmann --- core/src/components/setup/RecommendedApps.vue | 60 ++++++++++--------- core/src/recommendedapps.js | 4 ++ 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/core/src/components/setup/RecommendedApps.vue b/core/src/components/setup/RecommendedApps.vue index 9021fb89fa3..1abb6ffba16 100644 --- a/core/src/components/setup/RecommendedApps.vue +++ b/core/src/components/setup/RecommendedApps.vue @@ -62,8 +62,8 @@ import axios from '@nextcloud/axios' import { loadState } from '@nextcloud/initial-state' import { t } from '@nextcloud/l10n' +import { PwdConfirmationMode } from '@nextcloud/password-confirmation' import { generateUrl, imagePath } from '@nextcloud/router' -import pLimit from 'p-limit' import NcButton from '@nextcloud/vue/components/NcButton' import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch' import logger from '../../logger.js' @@ -147,35 +147,41 @@ export default { }, methods: { - installApps() { - this.installingApps = true - - const limit = pLimit(1) - const installing = this.recommendedApps + async installApps() { + const apps = this.recommendedApps .filter((app) => !app.active && app.isCompatible && app.canInstall && app.isSelected) - .map((app) => limit(async () => { - logger.info(`installing ${app.id}`) - app.loading = true - return axios.post(generateUrl('settings/apps/enable'), { appIds: [app.id], groups: [] }) - .catch((error) => { - logger.error(`could not install ${app.id}`, { error }) - app.isSelected = false - app.installationError = true - }) - .then(() => { - logger.info(`installed ${app.id}`) - app.loading = false - app.active = true - }) - })) - logger.debug(`installing ${installing.length} recommended apps`) - Promise.all(installing) - .then(() => { - logger.info('all recommended apps installed, redirecting …') + if (apps.length === 0) { + return + } - window.location = this.defaultPageUrl + this.installingApps = true + apps.forEach((app) => { + app.loading = true + }) + const appIds = apps.map((app) => app.id) + logger.debug(`installing ${apps.length} recommended apps`, { appIds }) + + try { + await axios.post( + generateUrl('settings/apps/enable'), + { appIds, groups: [] }, + { confirmPassword: PwdConfirmationMode.Strict }, + ) + apps.forEach((app) => { + app.loading = false + app.active = true }) - .catch((error) => logger.error('could not install recommended apps', { error })) + logger.info('all recommended apps installed, redirecting …') + window.location = this.defaultPageUrl + } catch (error) { + logger.error('could not install recommended apps', { error }) + apps.forEach((app) => { + app.loading = false + app.isSelected = false + app.installationError = true + }) + this.installingApps = false + } }, customIcon(appId) { diff --git a/core/src/recommendedapps.js b/core/src/recommendedapps.js index 5c2ea255eb7..693dbae8dd4 100644 --- a/core/src/recommendedapps.js +++ b/core/src/recommendedapps.js @@ -4,11 +4,15 @@ */ import { getCSPNonce } from '@nextcloud/auth' +import axios from '@nextcloud/axios' import { translate as t } from '@nextcloud/l10n' +import { addPasswordConfirmationInterceptors } from '@nextcloud/password-confirmation' import Vue from 'vue' import RecommendedApps from './components/setup/RecommendedApps.vue' import logger from './logger.js' +addPasswordConfirmationInterceptors(axios) + __webpack_nonce__ = getCSPNonce() Vue.mixin({