From 577eee2f6a69022a799380bf570feef30856e8a7 Mon Sep 17 00:00:00 2001 From: Shlomo <78599753+ShlomoCode@users.noreply.github.com> Date: Fri, 21 Feb 2025 16:38:45 +0200 Subject: [PATCH] feat(config): add `acpPluginInstallDisabled` option (#13189) --- public/language/en-GB/error.json | 1 + public/openapi/read/admin/development/info.yaml | 2 ++ src/controllers/admin/info.js | 1 + src/prestart.js | 3 ++- src/socket.io/admin/plugins.js | 4 ++++ test/mocks/databasemock.js | 1 + 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/public/language/en-GB/error.json b/public/language/en-GB/error.json index caa23964b4..d511ef8300 100644 --- a/public/language/en-GB/error.json +++ b/public/language/en-GB/error.json @@ -268,6 +268,7 @@ "invalid-plugin-id": "Invalid plugin ID", "plugin-not-whitelisted": "Unable to install plugin – only plugins whitelisted by the NodeBB Package Manager can be installed via the ACP", + "plugin-installation-via-acp-disabled": "Plugin installation via ACP is disabled", "plugins-set-in-configuration": "You are not allowed to change plugin state as they are defined at runtime (config.json, environmental variables or terminal arguments), please modify the configuration instead.", "theme-not-set-in-configuration": "When defining active plugins in configuration, changing themes requires adding the new theme to the list of active plugins before updating it in the ACP", diff --git a/public/openapi/read/admin/development/info.yaml b/public/openapi/read/admin/development/info.yaml index 81b9e3f49e..1eeb77c1b3 100644 --- a/public/openapi/read/admin/development/info.yaml +++ b/public/openapi/read/admin/development/info.yaml @@ -98,6 +98,8 @@ get: type: boolean jobsDisabled: type: boolean + acpPluginInstallDisabled: + type: boolean git: type: object properties: diff --git a/src/controllers/admin/info.js b/src/controllers/admin/info.js index 45ffe078b7..d581780b11 100644 --- a/src/controllers/admin/info.js +++ b/src/controllers/admin/info.js @@ -88,6 +88,7 @@ async function getNodeInfo() { isPrimary: nconf.get('isPrimary'), runJobs: nconf.get('runJobs'), jobsDisabled: nconf.get('jobsDisabled'), + acpPluginInstallDisabled: nconf.get('acpPluginInstallDisabled') }, }; diff --git a/src/prestart.js b/src/prestart.js index b09ef5d9bc..57b5f0590e 100644 --- a/src/prestart.js +++ b/src/prestart.js @@ -58,6 +58,7 @@ function loadConfig(configFile) { isCluster: false, isPrimary: true, jobsDisabled: false, + acpPluginInstallDisabled: false, fontawesome: { pro: false, styles: '*', @@ -65,7 +66,7 @@ function loadConfig(configFile) { }); // Explicitly cast as Bool, loader.js passes in isCluster as string 'true'/'false' - const castAsBool = ['isCluster', 'isPrimary', 'jobsDisabled']; + const castAsBool = ['isCluster', 'isPrimary', 'jobsDisabled', 'acpPluginInstallDisabled']; nconf.stores.env.readOnly = false; castAsBool.forEach((prop) => { const value = nconf.get(prop); diff --git a/src/socket.io/admin/plugins.js b/src/socket.io/admin/plugins.js index 2d6f705be9..d926dfa0cf 100644 --- a/src/socket.io/admin/plugins.js +++ b/src/socket.io/admin/plugins.js @@ -22,6 +22,10 @@ Plugins.toggleActive = async function (socket, plugin_id) { }; Plugins.toggleInstall = async function (socket, data) { + const isInstalled = await plugins.isInstalled(data.id); + if (nconf.get('acpPluginInstallDisabled') && !isInstalled) { + throw new Error('[[error:plugin-installation-via-acp-disabled]]'); + } postsCache.reset(); await plugins.checkWhitelist(data.id, data.version); const pluginData = await plugins.toggleInstall(data.id, data.version); diff --git a/test/mocks/databasemock.js b/test/mocks/databasemock.js index 587dd65dcc..6a568109b7 100644 --- a/test/mocks/databasemock.js +++ b/test/mocks/databasemock.js @@ -144,6 +144,7 @@ before(async function () { nconf.set('version', packageInfo.version); nconf.set('runJobs', false); nconf.set('jobsDisabled', false); + nconf.set('acpPluginInstallDisabled', false); await db.init();