diff --git a/public/script.js b/public/script.js index f0e223519..f3c51e9db 100644 --- a/public/script.js +++ b/public/script.js @@ -7957,6 +7957,11 @@ export async function getSettings(initLoaderHandle = null) { Object.assign(extension_settings, (settings.extension_settings ?? {})); $('#third_party_extension_button').addClass('disabled'); $('#extensions_details').addClass('disabled'); + $('#extensions_connect').addClass('disabled'); + $('#extensions_notify_updates').attr('disabled', 'disabled'); + $('#extensions_autoconnect').attr('disabled', 'disabled'); + $('#extensions_url').attr('disabled', 'disabled'); + $('#extensions_api_key').attr('disabled', 'disabled'); } firstRun = !!settings.firstRun; diff --git a/src/endpoints/extensions.js b/src/endpoints/extensions.js index fe4cbc1f6..df8dd58c2 100644 --- a/src/endpoints/extensions.js +++ b/src/endpoints/extensions.js @@ -65,14 +65,20 @@ async function checkIfRepoIsUpToDate(extensionPath) { export const router = express.Router(); -// Feature flag guard: don't allow calling any of the endpoints if extensions are disabled -router.use((_, response, next) => { +/** + * Feature flag guard: don't allow calling any of the endpoints if extensions are disabled + * @type {import('express').RequestHandler} + */ +export const extensionsEnabledFeatureGuard = (_, response, next) => { const enabled = !!getConfigValue('extensions.enabled', true, 'boolean'); if (!enabled) { - return response.status(400).send('Bad Request: Extensions are disabled.'); + response.sendStatus(404); + return; } next(); -}); +}; + +router.use(extensionsEnabledFeatureGuard); /** * HTTP POST handler function to clone a git repository from a provided URL, read the extension manifest, @@ -119,6 +125,7 @@ router.post('/install', async (request, response) => { } const extensionPath = path.join(basePath, extensionNameSanitized); + const folderName = path.basename(extensionPath); if (fs.existsSync(extensionPath)) { return response.status(409).send(`Directory already exists at ${extensionPath}`); @@ -131,10 +138,17 @@ router.post('/install', async (request, response) => { await git.clone(parsedUrl.href, extensionPath, cloneOptions); console.info(`Extension has been cloned to ${extensionPath} from ${parsedUrl.href} at ${branch || '(default)'} branch`); - const { version, author, display_name } = await getManifest(extensionPath); - const folderName = path.basename(extensionPath); - - return response.send({ version, author, display_name, extensionPath, folderName }); + try { + const manifest = await getManifest(extensionPath); + if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) { + throw new Error('Manifest is not a valid JSON object.'); + } + const { version, author, display_name } = manifest; + return response.send({ version, author, display_name, extensionPath, folderName }); + } catch (manifestError) { + await fs.promises.rm(extensionPath, { recursive: true, force: true }); + throw manifestError; + } } catch (error) { console.error('Importing extension failed', error); return response.status(500).send('Internal Server Error. Check the server logs for more details.'); diff --git a/src/users.js b/src/users.js index cac44f724..3ef054eb7 100644 --- a/src/users.js +++ b/src/users.js @@ -22,6 +22,7 @@ import { allowKeysExposure, readSecret, writeSecret, SECRETS_FILE } from './endp import { getContentOfType } from './endpoints/content-manager.js'; import { serverDirectory } from './server-directory.js'; import { filterValidIpPatterns, getIpFromRequest } from './express-common.js'; +import { extensionsEnabledFeatureGuard } from './endpoints/extensions.js'; export const KEY_PREFIX = 'user:'; const AVATAR_PREFIX = 'avatar:'; @@ -1215,4 +1216,4 @@ router.use('/User%20Avatars/*', createRouteHandler(req => req.user.directories.a router.use('/assets/*', createRouteHandler(req => req.user.directories.assets)); router.use('/user/images/*', createRouteHandler(req => req.user.directories.userImages)); router.use('/user/files/*', createRouteHandler(req => req.user.directories.files)); -router.use('/scripts/extensions/third-party/*', createExtensionsRouteHandler(req => req.user.directories.extensions)); +router.use('/scripts/extensions/third-party/*', extensionsEnabledFeatureGuard, createExtensionsRouteHandler(req => req.user.directories.extensions));