@samanhappy/mcphub 1.0.31 → 1.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/README.zh.md +12 -2
- package/dist/betterAuth.js +13 -5
- package/dist/betterAuth.js.map +1 -1
- package/dist/cli/commands/cache.js.map +1 -1
- package/dist/cli/commands/call.js +2 -2
- package/dist/cli/commands/call.js.map +1 -1
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/discover.js.map +1 -1
- package/dist/cli/commands/export.js.map +1 -1
- package/dist/cli/commands/groups.js.map +1 -1
- package/dist/cli/commands/install.js +1 -1
- package/dist/cli/commands/install.js.map +1 -1
- package/dist/cli/commands/keys.js.map +1 -1
- package/dist/cli/commands/login.js.map +1 -1
- package/dist/cli/commands/servers.js.map +1 -1
- package/dist/cli/commands/tools.js +2 -2
- package/dist/cli/commands/tools.js.map +1 -1
- package/dist/cli/context.js +1 -1
- package/dist/cli/context.js.map +1 -1
- package/dist/cli/http.js +3 -1
- package/dist/cli/http.js.map +1 -1
- package/dist/clients/openapi.js +498 -76
- package/dist/clients/openapi.js.map +1 -1
- package/dist/config/DaoConfigService.js +3 -2
- package/dist/config/DaoConfigService.js.map +1 -1
- package/dist/config/configManager.js +9 -8
- package/dist/config/configManager.js.map +1 -1
- package/dist/config/index.js +54 -8
- package/dist/config/index.js.map +1 -1
- package/dist/config/jwt.js +2 -1
- package/dist/config/jwt.js.map +1 -1
- package/dist/config/migrationUtils.js +46 -45
- package/dist/config/migrationUtils.js.map +1 -1
- package/dist/constants/oauthServerDefaults.js +5 -0
- package/dist/constants/oauthServerDefaults.js.map +1 -1
- package/dist/controllers/activityController.js +6 -5
- package/dist/controllers/activityController.js.map +1 -1
- package/dist/controllers/authController.js +5 -4
- package/dist/controllers/authController.js.map +1 -1
- package/dist/controllers/bearerKeyController.js +7 -6
- package/dist/controllers/bearerKeyController.js.map +1 -1
- package/dist/controllers/betterAuthController.js +2 -1
- package/dist/controllers/betterAuthController.js.map +1 -1
- package/dist/controllers/builtinPromptController.js +13 -5
- package/dist/controllers/builtinPromptController.js.map +1 -1
- package/dist/controllers/builtinResourceController.js +14 -6
- package/dist/controllers/builtinResourceController.js.map +1 -1
- package/dist/controllers/changelogController.js +5 -2
- package/dist/controllers/changelogController.js.map +1 -1
- package/dist/controllers/cloudController.js +11 -10
- package/dist/controllers/cloudController.js.map +1 -1
- package/dist/controllers/configController.js +4 -3
- package/dist/controllers/configController.js.map +1 -1
- package/dist/controllers/contextCostController.js +3 -2
- package/dist/controllers/contextCostController.js.map +1 -1
- package/dist/controllers/groupController.js +2 -1
- package/dist/controllers/groupController.js.map +1 -1
- package/dist/controllers/healthController.js +2 -1
- package/dist/controllers/healthController.js.map +1 -1
- package/dist/controllers/hostedInternalController.js +2 -1
- package/dist/controllers/hostedInternalController.js.map +1 -1
- package/dist/controllers/logController.js +5 -4
- package/dist/controllers/logController.js.map +1 -1
- package/dist/controllers/mcpbController.js +23 -20
- package/dist/controllers/mcpbController.js.map +1 -1
- package/dist/controllers/oauthCallbackController.js +54 -27
- package/dist/controllers/oauthCallbackController.js.map +1 -1
- package/dist/controllers/oauthClientController.js +7 -6
- package/dist/controllers/oauthClientController.js.map +1 -1
- package/dist/controllers/oauthDynamicRegistrationController.js +22 -4
- package/dist/controllers/oauthDynamicRegistrationController.js.map +1 -1
- package/dist/controllers/oauthServerController.js +62 -15
- package/dist/controllers/oauthServerController.js.map +1 -1
- package/dist/controllers/openApiController.js +7 -6
- package/dist/controllers/openApiController.js.map +1 -1
- package/dist/controllers/promptController.js +2 -1
- package/dist/controllers/promptController.js.map +1 -1
- package/dist/controllers/registryController.js +4 -3
- package/dist/controllers/registryController.js.map +1 -1
- package/dist/controllers/serverController.js +154 -65
- package/dist/controllers/serverController.js.map +1 -1
- package/dist/controllers/templateController.js +3 -2
- package/dist/controllers/templateController.js.map +1 -1
- package/dist/controllers/toolController.js +2 -1
- package/dist/controllers/toolController.js.map +1 -1
- package/dist/dao/DaoFactory.js +3 -2
- package/dist/dao/DaoFactory.js.map +1 -1
- package/dist/dao/ServerDao.js.map +1 -1
- package/dist/dao/UserConfigDaoDbImpl.js.map +1 -1
- package/dist/dao/UserDao.js.map +1 -1
- package/dist/dao/base/JsonFileBaseDao.js +3 -2
- package/dist/dao/base/JsonFileBaseDao.js.map +1 -1
- package/dist/dao/examples.js +35 -34
- package/dist/dao/examples.js.map +1 -1
- package/dist/db/connection.js +59 -58
- package/dist/db/connection.js.map +1 -1
- package/dist/db/index.js +2 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/repositories/ServerRepository.js +3 -3
- package/dist/db/repositories/ServerRepository.js.map +1 -1
- package/dist/db/repositories/SystemConfigRepository.js +2 -1
- package/dist/db/repositories/SystemConfigRepository.js.map +1 -1
- package/dist/db/repositories/UserConfigRepository.js.map +1 -1
- package/dist/db/repositories/VectorEmbeddingRepository.js +6 -5
- package/dist/db/repositories/VectorEmbeddingRepository.js.map +1 -1
- package/dist/index.js +28 -19
- package/dist/index.js.map +1 -1
- package/dist/middlewares/auth.js +4 -3
- package/dist/middlewares/auth.js.map +1 -1
- package/dist/middlewares/index.js +2 -1
- package/dist/middlewares/index.js.map +1 -1
- package/dist/middlewares/userContext.js +7 -6
- package/dist/middlewares/userContext.js.map +1 -1
- package/dist/models/OAuth.js +7 -6
- package/dist/models/OAuth.js.map +1 -1
- package/dist/models/User.js +13 -12
- package/dist/models/User.js.map +1 -1
- package/dist/routes/index.js +11 -10
- package/dist/routes/index.js.map +1 -1
- package/dist/scripts/dao-demo.js +28 -27
- package/dist/scripts/dao-demo.js.map +1 -1
- package/dist/server.js +36 -30
- package/dist/server.js.map +1 -1
- package/dist/services/activityLoggingService.js +3 -2
- package/dist/services/activityLoggingService.js.map +1 -1
- package/dist/services/authorizationService.js +28 -0
- package/dist/services/authorizationService.js.map +1 -0
- package/dist/services/betterAuthConfig.js +1 -4
- package/dist/services/betterAuthConfig.js.map +1 -1
- package/dist/services/betterAuthSession.js +8 -7
- package/dist/services/betterAuthSession.js.map +1 -1
- package/dist/services/changelogService.js +5 -2
- package/dist/services/changelogService.js.map +1 -1
- package/dist/services/cimdClientService.js +195 -0
- package/dist/services/cimdClientService.js.map +1 -0
- package/dist/services/cloudService.js +10 -9
- package/dist/services/cloudService.js.map +1 -1
- package/dist/services/contextCostService.js +6 -2
- package/dist/services/contextCostService.js.map +1 -1
- package/dist/services/groupService.js +8 -7
- package/dist/services/groupService.js.map +1 -1
- package/dist/services/hostedAuthService.js +3 -2
- package/dist/services/hostedAuthService.js.map +1 -1
- package/dist/services/hostedControlPlaneClient.js.map +1 -1
- package/dist/services/hostedEventSubscriber.js +9 -8
- package/dist/services/hostedEventSubscriber.js.map +1 -1
- package/dist/services/hostedRuntimeCatalogNames.js +1 -3
- package/dist/services/hostedRuntimeCatalogNames.js.map +1 -1
- package/dist/services/keepAliveService.js +7 -6
- package/dist/services/keepAliveService.js.map +1 -1
- package/dist/services/marketService.js +2 -1
- package/dist/services/marketService.js.map +1 -1
- package/dist/services/mcpOAuthProvider.js +22 -21
- package/dist/services/mcpOAuthProvider.js.map +1 -1
- package/dist/services/mcpService.js +239 -130
- package/dist/services/mcpService.js.map +1 -1
- package/dist/services/oauthClientRegistration.js +30 -29
- package/dist/services/oauthClientRegistration.js.map +1 -1
- package/dist/services/oauthServerService.js +39 -18
- package/dist/services/oauthServerService.js.map +1 -1
- package/dist/services/oauthService.js +16 -15
- package/dist/services/oauthService.js.map +1 -1
- package/dist/services/oauthSettingsStore.js +4 -3
- package/dist/services/oauthSettingsStore.js.map +1 -1
- package/dist/services/openApiGeneratorService.js +1 -3
- package/dist/services/openApiGeneratorService.js.map +1 -1
- package/dist/services/openApiToolStatsService.js +37 -0
- package/dist/services/openApiToolStatsService.js.map +1 -0
- package/dist/services/registry.js +2 -1
- package/dist/services/registry.js.map +1 -1
- package/dist/services/requestContextService.js.map +1 -1
- package/dist/services/serverConfigPresenter.js +85 -0
- package/dist/services/serverConfigPresenter.js.map +1 -0
- package/dist/services/smartRoutingService.js +6 -5
- package/dist/services/smartRoutingService.js.map +1 -1
- package/dist/services/sseService.js +52 -51
- package/dist/services/sseService.js.map +1 -1
- package/dist/services/templateService.js +105 -23
- package/dist/services/templateService.js.map +1 -1
- package/dist/services/toolResultCompressionService.js +8 -5
- package/dist/services/toolResultCompressionService.js.map +1 -1
- package/dist/services/upstreamOAuthDisconnectService.js +9 -6
- package/dist/services/upstreamOAuthDisconnectService.js.map +1 -1
- package/dist/services/userService.js +5 -4
- package/dist/services/userService.js.map +1 -1
- package/dist/services/vectorSearchService.js +126 -112
- package/dist/services/vectorSearchService.js.map +1 -1
- package/dist/utils/cacheUtils.js +5 -4
- package/dist/utils/cacheUtils.js.map +1 -1
- package/dist/utils/corsOrigin.js +42 -0
- package/dist/utils/corsOrigin.js.map +1 -0
- package/dist/utils/dbRetry.js +2 -5
- package/dist/utils/dbRetry.js.map +1 -1
- package/dist/utils/frontendShell.js +2 -1
- package/dist/utils/frontendShell.js.map +1 -1
- package/dist/utils/i18n.js.map +1 -1
- package/dist/utils/logger.js +170 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/migration.js +51 -50
- package/dist/utils/migration.js.map +1 -1
- package/dist/utils/oauthIssuer.js +57 -0
- package/dist/utils/oauthIssuer.js.map +1 -0
- package/dist/utils/openApiRequestBody.js +220 -0
- package/dist/utils/openApiRequestBody.js.map +1 -0
- package/dist/utils/parameterConversion.js +2 -1
- package/dist/utils/parameterConversion.js.map +1 -1
- package/dist/utils/path.js +9 -8
- package/dist/utils/path.js.map +1 -1
- package/dist/utils/processTree.js +47 -0
- package/dist/utils/processTree.js.map +1 -0
- package/dist/utils/proxyTrust.js.map +1 -1
- package/dist/utils/rateLimit.js +8 -0
- package/dist/utils/rateLimit.js.map +1 -1
- package/dist/utils/requireAdmin.js +15 -0
- package/dist/utils/requireAdmin.js.map +1 -0
- package/dist/utils/serverConfigPersistence.js +3 -0
- package/dist/utils/serverConfigPersistence.js.map +1 -1
- package/dist/utils/serverConfigValidation.js +13 -0
- package/dist/utils/serverConfigValidation.js.map +1 -0
- package/dist/utils/serverNameValidation.js +56 -0
- package/dist/utils/serverNameValidation.js.map +1 -0
- package/dist/utils/serverShutdown.js +3 -2
- package/dist/utils/serverShutdown.js.map +1 -1
- package/dist/utils/smartRouting.js +4 -3
- package/dist/utils/smartRouting.js.map +1 -1
- package/dist/utils/ssrf.js +23 -10
- package/dist/utils/ssrf.js.map +1 -1
- package/dist/utils/systemConfigCache.js +40 -2
- package/dist/utils/systemConfigCache.js.map +1 -1
- package/dist/utils/tokenCost.js.map +1 -1
- package/dist/utils/tokenTruncation.js +9 -4
- package/dist/utils/tokenTruncation.js.map +1 -1
- package/dist/utils/version.js +3 -2
- package/dist/utils/version.js.map +1 -1
- package/frontend/dist/assets/{ActivityPage-Dx53zxEM.js → ActivityPage-Du9Nh-Jy.js} +2 -2
- package/frontend/dist/assets/{ActivityPage-Dx53zxEM.js.map → ActivityPage-Du9Nh-Jy.js.map} +1 -1
- package/frontend/dist/assets/ConfirmDialog-3APts2Y9.js +2 -0
- package/frontend/dist/assets/ConfirmDialog-3APts2Y9.js.map +1 -0
- package/frontend/dist/assets/Dashboard-J4G-AZkI.js +2 -0
- package/frontend/dist/assets/{Dashboard-ZYVsSvOw.js.map → Dashboard-J4G-AZkI.js.map} +1 -1
- package/frontend/dist/assets/{DeleteDialog-DNe-zTEl.js → DeleteDialog-D9ycSRvn.js} +2 -2
- package/frontend/dist/assets/{DeleteDialog-DNe-zTEl.js.map → DeleteDialog-D9ycSRvn.js.map} +1 -1
- package/frontend/dist/assets/{EndpointCopy-ngxLPeDF.js → EndpointCopy-DFeLcU9A.js} +2 -2
- package/frontend/dist/assets/{EndpointCopy-ngxLPeDF.js.map → EndpointCopy-DFeLcU9A.js.map} +1 -1
- package/frontend/dist/assets/GroupsPage-CGMZBiXd.js +33 -0
- package/frontend/dist/assets/{GroupsPage-JPtupGpI.js.map → GroupsPage-CGMZBiXd.js.map} +1 -1
- package/frontend/dist/assets/{LoginPage-B6rU3Ugr.js → LoginPage-g5pJLBk0.js} +2 -2
- package/frontend/dist/assets/{LoginPage-B6rU3Ugr.js.map → LoginPage-g5pJLBk0.js.map} +1 -1
- package/frontend/dist/assets/{LogsPage-CXq382fb.js → LogsPage-Bkv7xhNf.js} +2 -2
- package/frontend/dist/assets/{LogsPage-CXq382fb.js.map → LogsPage-Bkv7xhNf.js.map} +1 -1
- package/frontend/dist/assets/MarketPage-WkLrckIr.js +3 -0
- package/frontend/dist/assets/MarketPage-WkLrckIr.js.map +1 -0
- package/frontend/dist/assets/{OAuthConsentPage-C-n6tv3-.js → OAuthConsentPage-CA35XoBK.js} +2 -2
- package/frontend/dist/assets/{OAuthConsentPage-C-n6tv3-.js.map → OAuthConsentPage-CA35XoBK.js.map} +1 -1
- package/frontend/dist/assets/{Pagination-DLSuQ8hw.js → Pagination-Dwko3g48.js} +2 -2
- package/frontend/dist/assets/{Pagination-DLSuQ8hw.js.map → Pagination-Dwko3g48.js.map} +1 -1
- package/frontend/dist/assets/{PromptsPage-BLpy76K4.js → PromptsPage-BuDdW69R.js} +2 -2
- package/frontend/dist/assets/{PromptsPage-BLpy76K4.js.map → PromptsPage-BuDdW69R.js.map} +1 -1
- package/frontend/dist/assets/{ResourcesPage-C5nynRqE.js → ResourcesPage-Cu-eD5e2.js} +2 -2
- package/frontend/dist/assets/{ResourcesPage-C5nynRqE.js.map → ResourcesPage-Cu-eD5e2.js.map} +1 -1
- package/frontend/dist/assets/{ServersPage-Ca5W9cPW.js → ServersPage-B1Np5x3N.js} +8 -8
- package/frontend/dist/assets/ServersPage-B1Np5x3N.js.map +1 -0
- package/frontend/dist/assets/{SettingsPage-DgFBjp_O.js → SettingsPage-BQN8-ZQh.js} +4 -4
- package/frontend/dist/assets/SettingsPage-BQN8-ZQh.js.map +1 -0
- package/frontend/dist/assets/{StatusDot-CmSkukx0.js → StatusDot-WyvgqplP.js} +2 -2
- package/frontend/dist/assets/{StatusDot-CmSkukx0.js.map → StatusDot-WyvgqplP.js.map} +1 -1
- package/frontend/dist/assets/{ToggleGroup-sG_2LQom.js → ToggleGroup-CmeedsZU.js} +2 -2
- package/frontend/dist/assets/{ToggleGroup-sG_2LQom.js.map → ToggleGroup-CmeedsZU.js.map} +1 -1
- package/frontend/dist/assets/UsersPage-DqDFrIIW.js +2 -0
- package/frontend/dist/assets/UsersPage-DqDFrIIW.js.map +1 -0
- package/frontend/dist/assets/contextCost-CilWqGWT.js +2 -0
- package/frontend/dist/assets/contextCost-CilWqGWT.js.map +1 -0
- package/frontend/dist/assets/{framework-vendor-I9Y6AgD5.js → framework-vendor-BHAQX05P.js} +3 -3
- package/frontend/dist/assets/{framework-vendor-I9Y6AgD5.js.map → framework-vendor-BHAQX05P.js.map} +1 -1
- package/frontend/dist/assets/{i18n-vendor-y9bLzIeh.js → i18n-vendor-CMcB7XUR.js} +2 -2
- package/frontend/dist/assets/{i18n-vendor-y9bLzIeh.js.map → i18n-vendor-CMcB7XUR.js.map} +1 -1
- package/frontend/dist/assets/{icons-vendor-BFl4A9fq.js → icons-vendor-HZHHWeTa.js} +2 -2
- package/frontend/dist/assets/{icons-vendor-BFl4A9fq.js.map → icons-vendor-HZHHWeTa.js.map} +1 -1
- package/frontend/dist/assets/index-BvU2-VT8.js +3 -0
- package/frontend/dist/assets/{index-CLugsCsy.js.map → index-BvU2-VT8.js.map} +1 -1
- package/frontend/dist/assets/index-DtrCVU1h.css +1 -0
- package/frontend/dist/assets/passwordValidation-DTLWgUy9.js +2 -0
- package/frontend/dist/assets/passwordValidation-DTLWgUy9.js.map +1 -0
- package/frontend/dist/assets/{resourceService-33rS8QGJ.js → resourceService-BFH4w47h.js} +2 -2
- package/frontend/dist/assets/{resourceService-33rS8QGJ.js.map → resourceService-BFH4w47h.js.map} +1 -1
- package/frontend/dist/assets/useCostData-CoM1SxdS.js +2 -0
- package/frontend/dist/assets/useCostData-CoM1SxdS.js.map +1 -0
- package/frontend/dist/assets/useSettingsData-DKrECrG1.js +2 -0
- package/frontend/dist/assets/{useSettingsData-fK2bv9oN.js.map → useSettingsData-DKrECrG1.js.map} +1 -1
- package/frontend/dist/assets/variableDetection-CIrYDjrq.js +16 -0
- package/frontend/dist/assets/variableDetection-CIrYDjrq.js.map +1 -0
- package/frontend/dist/index.html +5 -5
- package/package.json +2 -2
- package/frontend/dist/assets/ConfirmDialog-CYfXEuyU.js +0 -2
- package/frontend/dist/assets/ConfirmDialog-CYfXEuyU.js.map +0 -1
- package/frontend/dist/assets/Dashboard-ZYVsSvOw.js +0 -2
- package/frontend/dist/assets/GroupsPage-JPtupGpI.js +0 -33
- package/frontend/dist/assets/MarketPage-BGnQQyXK.js +0 -3
- package/frontend/dist/assets/MarketPage-BGnQQyXK.js.map +0 -1
- package/frontend/dist/assets/ServersPage-Ca5W9cPW.js.map +0 -1
- package/frontend/dist/assets/SettingsPage-DgFBjp_O.js.map +0 -1
- package/frontend/dist/assets/UsersPage-PHkFXLL8.js +0 -2
- package/frontend/dist/assets/UsersPage-PHkFXLL8.js.map +0 -1
- package/frontend/dist/assets/contextCost-D_iNNbhX.js +0 -2
- package/frontend/dist/assets/contextCost-D_iNNbhX.js.map +0 -1
- package/frontend/dist/assets/index-CGvImZ3F.css +0 -1
- package/frontend/dist/assets/index-CLugsCsy.js +0 -3
- package/frontend/dist/assets/useSettingsData-fK2bv9oN.js +0 -2
- package/frontend/dist/assets/variableDetection-ByJ_cnxa.js +0 -16
- package/frontend/dist/assets/variableDetection-ByJ_cnxa.js.map +0 -1
|
@@ -6,10 +6,16 @@ import { createSafeJSON } from '../utils/serialization.js';
|
|
|
6
6
|
import { cloneDefaultOAuthServerConfig } from '../constants/oauthServerDefaults.js';
|
|
7
7
|
import { getBearerKeyDao, getGroupDao, getOAuthClientDao, getOAuthTokenDao, getServerDao, getSystemConfigDao, getUserConfigDao, getUserDao, } from '../dao/DaoFactory.js';
|
|
8
8
|
import { UserContextService } from '../services/userContextService.js';
|
|
9
|
+
import { authorizationService } from '../services/authorizationService.js';
|
|
10
|
+
import { presentServerForPrincipal, presentServerInfoForPrincipal, } from '../services/serverConfigPresenter.js';
|
|
9
11
|
import { disconnectUpstreamOAuth } from '../services/upstreamOAuthDisconnectService.js';
|
|
10
12
|
import { normalizeServerConfigForPersistence } from '../utils/serverConfigPersistence.js';
|
|
13
|
+
import { isPrivilegedServerConfig } from '../utils/serverConfigValidation.js';
|
|
14
|
+
import { validateServerName } from '../utils/serverNameValidation.js';
|
|
11
15
|
import { setCachedSystemConfig } from '../utils/systemConfigCache.js';
|
|
12
16
|
import { DEFAULT_INSTALL_BASE_URL, withResolvedInstallBaseUrl } from '../utils/installBaseUrl.js';
|
|
17
|
+
import { previewOpenApiToolStats } from '../services/openApiToolStatsService.js';
|
|
18
|
+
import { logger } from '../utils/logger.js';
|
|
13
19
|
const getRequestUser = (req) => {
|
|
14
20
|
return req.user || null;
|
|
15
21
|
};
|
|
@@ -22,12 +28,6 @@ const canAccessServer = (user, server) => {
|
|
|
22
28
|
}
|
|
23
29
|
return server.owner === user.username;
|
|
24
30
|
};
|
|
25
|
-
const isPrivilegedServerConfig = (config) => {
|
|
26
|
-
return Boolean(config.type === 'stdio' ||
|
|
27
|
-
config.command ||
|
|
28
|
-
(Array.isArray(config.args) && config.args.length > 0) ||
|
|
29
|
-
(!config.url && !config.openapi?.url && !config.openapi?.schema));
|
|
30
|
-
};
|
|
31
31
|
const loadAuthorizedServer = async (req, res, serverName) => {
|
|
32
32
|
const serverDao = getServerDao();
|
|
33
33
|
const server = await serverDao.findById(serverName);
|
|
@@ -194,16 +194,21 @@ export const getAllServers = async (req, res) => {
|
|
|
194
194
|
// No pagination, get all servers (will be filtered by mcpService)
|
|
195
195
|
serversInfo = await getServersInfo();
|
|
196
196
|
}
|
|
197
|
+
// #1036 Phase 1: withhold OAuth session-recovery fields from principals
|
|
198
|
+
// who may not read the full server configuration (defense in depth; the
|
|
199
|
+
// config block on list entries is already narrowed to safe metadata).
|
|
200
|
+
const presentedServersInfo = serversInfo.map((info) => presentServerInfoForPrincipal(info, currentUser));
|
|
201
|
+
const presentedAllServers = allServers?.map((info) => presentServerInfoForPrincipal(info, currentUser));
|
|
197
202
|
const response = {
|
|
198
203
|
success: true,
|
|
199
|
-
data: createSafeJSON(
|
|
200
|
-
...(
|
|
204
|
+
data: createSafeJSON(presentedServersInfo),
|
|
205
|
+
...(presentedAllServers && { allServers: createSafeJSON(presentedAllServers) }),
|
|
201
206
|
...(pagination && { pagination }),
|
|
202
207
|
};
|
|
203
208
|
res.json(response);
|
|
204
209
|
}
|
|
205
210
|
catch (error) {
|
|
206
|
-
|
|
211
|
+
logger.error('Failed to get servers information:', error);
|
|
207
212
|
res.status(500).json({
|
|
208
213
|
success: false,
|
|
209
214
|
message: 'Failed to get servers information',
|
|
@@ -228,7 +233,7 @@ export const getServerShareCandidates = async (req, res) => {
|
|
|
228
233
|
res.json({ success: true, data: usernames });
|
|
229
234
|
}
|
|
230
235
|
catch (error) {
|
|
231
|
-
|
|
236
|
+
logger.error('Failed to get server share candidates:', error);
|
|
232
237
|
res.status(500).json({
|
|
233
238
|
success: false,
|
|
234
239
|
message: 'Failed to get server share candidates',
|
|
@@ -308,23 +313,64 @@ export const getAllSettings = async (req, res) => {
|
|
|
308
313
|
res.json(response);
|
|
309
314
|
}
|
|
310
315
|
catch (error) {
|
|
311
|
-
|
|
316
|
+
logger.error('Failed to get server settings:', error);
|
|
312
317
|
res.status(500).json({
|
|
313
318
|
success: false,
|
|
314
319
|
message: 'Failed to get server settings',
|
|
315
320
|
});
|
|
316
321
|
}
|
|
317
322
|
};
|
|
323
|
+
/**
|
|
324
|
+
* Preview the tool list an OpenAPI import would generate, without persisting
|
|
325
|
+
* anything (#1082). Large specs can silently produce a tools/list that does
|
|
326
|
+
* not fit in a model's context window; this endpoint lets the form surface
|
|
327
|
+
* the numbers at the point of confirming the import.
|
|
328
|
+
*/
|
|
329
|
+
export const previewOpenApiToolStatsHandler = async (req, res) => {
|
|
330
|
+
try {
|
|
331
|
+
const { config } = req.body;
|
|
332
|
+
if (!config || typeof config !== 'object') {
|
|
333
|
+
res.status(400).json({
|
|
334
|
+
success: false,
|
|
335
|
+
message: 'Server configuration is required',
|
|
336
|
+
});
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const normalizedConfig = normalizeServerConfigForPersistence(config);
|
|
340
|
+
if (!normalizedConfig.openapi?.url && !normalizedConfig.openapi?.schema) {
|
|
341
|
+
res.status(400).json({
|
|
342
|
+
success: false,
|
|
343
|
+
message: 'OpenAPI specification URL or schema is required',
|
|
344
|
+
});
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
// Assign the requesting user as owner so initialize()'s admin check (and
|
|
348
|
+
// therefore the internal-network SSRF allowance) matches what a real
|
|
349
|
+
// add-server request would produce for the same caller.
|
|
350
|
+
assignServerOwner(req, normalizedConfig);
|
|
351
|
+
const stats = await previewOpenApiToolStats(normalizedConfig);
|
|
352
|
+
res.json({ success: true, data: stats });
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
logger.warn('Failed to preview OpenAPI tool stats:', error);
|
|
356
|
+
res.status(400).json({
|
|
357
|
+
success: false,
|
|
358
|
+
message: error instanceof Error ? error.message : 'Failed to analyze OpenAPI specification',
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
};
|
|
318
362
|
export const createServer = async (req, res) => {
|
|
319
363
|
try {
|
|
320
364
|
const { name, config } = req.body;
|
|
321
|
-
|
|
365
|
+
const nameValidation = validateServerName(name);
|
|
366
|
+
if (!nameValidation.valid) {
|
|
322
367
|
res.status(400).json({
|
|
323
368
|
success: false,
|
|
324
|
-
message:
|
|
369
|
+
message: nameValidation.message,
|
|
325
370
|
});
|
|
326
371
|
return;
|
|
327
372
|
}
|
|
373
|
+
const serverName = nameValidation.normalized;
|
|
328
374
|
if (!config || typeof config !== 'object') {
|
|
329
375
|
res.status(400).json({
|
|
330
376
|
success: false,
|
|
@@ -391,20 +437,19 @@ export const createServer = async (req, res) => {
|
|
|
391
437
|
return;
|
|
392
438
|
}
|
|
393
439
|
// Set default keep-alive interval for SSE servers if not specified
|
|
394
|
-
if ((normalizedConfig.type === 'sse' ||
|
|
395
|
-
(!normalizedConfig.type && normalizedConfig.url)) &&
|
|
440
|
+
if ((normalizedConfig.type === 'sse' || (!normalizedConfig.type && normalizedConfig.url)) &&
|
|
396
441
|
!normalizedConfig.keepAliveInterval) {
|
|
397
442
|
normalizedConfig.keepAliveInterval = 60000; // Default 60 seconds for SSE servers
|
|
398
443
|
}
|
|
399
444
|
assignServerOwner(req, normalizedConfig);
|
|
400
|
-
const result = await addServer(
|
|
445
|
+
const result = await addServer(serverName, normalizedConfig);
|
|
401
446
|
if (result.success) {
|
|
402
447
|
res.json({
|
|
403
448
|
success: true,
|
|
404
449
|
message: 'Server added successfully',
|
|
405
450
|
});
|
|
406
|
-
notifyToolChanged(
|
|
407
|
-
|
|
451
|
+
notifyToolChanged(serverName, { reportEmbeddingProgress: true }).catch((error) => {
|
|
452
|
+
logger.error('Failed to trigger embedding sync for created server:', error);
|
|
408
453
|
});
|
|
409
454
|
}
|
|
410
455
|
else {
|
|
@@ -442,8 +487,9 @@ export const batchCreateServers = async (req, res) => {
|
|
|
442
487
|
}
|
|
443
488
|
// Helper function to validate a single server configuration
|
|
444
489
|
const validateServerConfig = (name, config) => {
|
|
445
|
-
|
|
446
|
-
|
|
490
|
+
const nameValidation = validateServerName(name);
|
|
491
|
+
if (!nameValidation.valid) {
|
|
492
|
+
return { valid: false, message: nameValidation.message };
|
|
447
493
|
}
|
|
448
494
|
if (!config || typeof config !== 'object') {
|
|
449
495
|
return { valid: false, message: 'Server configuration is required and must be an object' };
|
|
@@ -491,7 +537,7 @@ export const batchCreateServers = async (req, res) => {
|
|
|
491
537
|
if (normalizedConfig.headers && normalizedConfig.type === 'stdio') {
|
|
492
538
|
return { valid: false, message: 'Headers are not supported for stdio server type' };
|
|
493
539
|
}
|
|
494
|
-
return { valid: true };
|
|
540
|
+
return { valid: true, normalizedName: nameValidation.normalized };
|
|
495
541
|
};
|
|
496
542
|
// Process each server
|
|
497
543
|
const results = [];
|
|
@@ -513,17 +559,17 @@ export const batchCreateServers = async (req, res) => {
|
|
|
513
559
|
failureCount++;
|
|
514
560
|
continue;
|
|
515
561
|
}
|
|
562
|
+
const serverName = validation.normalizedName ?? name;
|
|
516
563
|
try {
|
|
517
564
|
// Set default keep-alive interval for SSE servers if not specified
|
|
518
565
|
const normalizedConfig = normalizeServerConfigForPersistence(config);
|
|
519
|
-
if ((normalizedConfig.type === 'sse' ||
|
|
520
|
-
(!normalizedConfig.type && normalizedConfig.url)) &&
|
|
566
|
+
if ((normalizedConfig.type === 'sse' || (!normalizedConfig.type && normalizedConfig.url)) &&
|
|
521
567
|
!normalizedConfig.keepAliveInterval) {
|
|
522
568
|
normalizedConfig.keepAliveInterval = 60000; // Default 60 seconds for SSE servers
|
|
523
569
|
}
|
|
524
570
|
if (isPrivilegedServerConfig(normalizedConfig) && currentUser?.isAdmin !== true) {
|
|
525
571
|
results.push({
|
|
526
|
-
name,
|
|
572
|
+
name: serverName,
|
|
527
573
|
success: false,
|
|
528
574
|
message: 'Only admins can create or modify stdio-based servers',
|
|
529
575
|
});
|
|
@@ -531,19 +577,21 @@ export const batchCreateServers = async (req, res) => {
|
|
|
531
577
|
continue;
|
|
532
578
|
}
|
|
533
579
|
// Set owner property if not provided
|
|
534
|
-
normalizedConfig.owner = currentUser?.isAdmin
|
|
580
|
+
normalizedConfig.owner = currentUser?.isAdmin
|
|
581
|
+
? normalizedConfig.owner || defaultOwner
|
|
582
|
+
: defaultOwner;
|
|
535
583
|
// Attempt to add server
|
|
536
|
-
const result = await addServer(
|
|
584
|
+
const result = await addServer(serverName, normalizedConfig);
|
|
537
585
|
if (result.success) {
|
|
538
586
|
results.push({
|
|
539
|
-
name,
|
|
587
|
+
name: serverName,
|
|
540
588
|
success: true,
|
|
541
589
|
});
|
|
542
590
|
successCount++;
|
|
543
591
|
}
|
|
544
592
|
else {
|
|
545
593
|
results.push({
|
|
546
|
-
name,
|
|
594
|
+
name: serverName,
|
|
547
595
|
success: false,
|
|
548
596
|
message: result.message || 'Failed to add server',
|
|
549
597
|
});
|
|
@@ -552,7 +600,7 @@ export const batchCreateServers = async (req, res) => {
|
|
|
552
600
|
}
|
|
553
601
|
catch (error) {
|
|
554
602
|
results.push({
|
|
555
|
-
name,
|
|
603
|
+
name: serverName,
|
|
556
604
|
success: false,
|
|
557
605
|
message: error instanceof Error ? error.message : 'Internal server error',
|
|
558
606
|
});
|
|
@@ -577,12 +625,12 @@ export const batchCreateServers = async (req, res) => {
|
|
|
577
625
|
.filter((result) => result.success)
|
|
578
626
|
.map((result) => result.name);
|
|
579
627
|
Promise.all(successfulServerNames.map((serverName) => notifyToolChanged(serverName, { reportEmbeddingProgress: true }))).catch((error) => {
|
|
580
|
-
|
|
628
|
+
logger.error('Failed to trigger embedding sync for batch-created servers:', error);
|
|
581
629
|
});
|
|
582
630
|
}
|
|
583
631
|
}
|
|
584
632
|
catch (error) {
|
|
585
|
-
|
|
633
|
+
logger.error('Batch create servers error:', error);
|
|
586
634
|
res.status(500).json({
|
|
587
635
|
success: false,
|
|
588
636
|
message: 'Internal server error',
|
|
@@ -706,8 +754,7 @@ export const updateServer = async (req, res) => {
|
|
|
706
754
|
return;
|
|
707
755
|
}
|
|
708
756
|
// Set default keep-alive interval for SSE servers if not specified
|
|
709
|
-
if ((normalizedConfig.type === 'sse' ||
|
|
710
|
-
(!normalizedConfig.type && normalizedConfig.url)) &&
|
|
757
|
+
if ((normalizedConfig.type === 'sse' || (!normalizedConfig.type && normalizedConfig.url)) &&
|
|
711
758
|
!normalizedConfig.keepAliveInterval) {
|
|
712
759
|
normalizedConfig.keepAliveInterval = 60000; // Default 60 seconds for SSE servers
|
|
713
760
|
}
|
|
@@ -715,19 +762,32 @@ export const updateServer = async (req, res) => {
|
|
|
715
762
|
assignServerOwner(req, normalizedConfig, existingServer.owner);
|
|
716
763
|
// Check if server name is being changed
|
|
717
764
|
const isRenaming = newName && newName !== name;
|
|
765
|
+
// Final server name used for the rest of the update flow (the new name when
|
|
766
|
+
// renaming, otherwise the original name).
|
|
767
|
+
let finalName = name;
|
|
718
768
|
// If renaming, validate the new name and update references
|
|
719
769
|
if (isRenaming) {
|
|
720
770
|
const serverDao = getServerDao();
|
|
771
|
+
const nameValidation = validateServerName(newName);
|
|
772
|
+
if (!nameValidation.valid) {
|
|
773
|
+
res.status(400).json({
|
|
774
|
+
success: false,
|
|
775
|
+
message: nameValidation.message,
|
|
776
|
+
});
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
const targetName = nameValidation.normalized;
|
|
780
|
+
finalName = targetName;
|
|
721
781
|
// Check if new name already exists
|
|
722
|
-
if (await serverDao.exists(
|
|
782
|
+
if (await serverDao.exists(targetName)) {
|
|
723
783
|
res.status(400).json({
|
|
724
784
|
success: false,
|
|
725
|
-
message: `Server name '${
|
|
785
|
+
message: `Server name '${targetName}' already exists`,
|
|
726
786
|
});
|
|
727
787
|
return;
|
|
728
788
|
}
|
|
729
789
|
// Rename the server
|
|
730
|
-
const renamed = await serverDao.rename(name,
|
|
790
|
+
const renamed = await serverDao.rename(name, targetName);
|
|
731
791
|
if (!renamed) {
|
|
732
792
|
res.status(404).json({
|
|
733
793
|
success: false,
|
|
@@ -743,10 +803,10 @@ export const updateServer = async (req, res) => {
|
|
|
743
803
|
closeServer(name);
|
|
744
804
|
// Update references in groups
|
|
745
805
|
const groupDao = getGroupDao();
|
|
746
|
-
await groupDao.updateServerName(name,
|
|
806
|
+
await groupDao.updateServerName(name, targetName);
|
|
747
807
|
// Update references in bearer keys
|
|
748
808
|
const bearerKeyDao = getBearerKeyDao();
|
|
749
|
-
await bearerKeyDao.updateServerName(name,
|
|
809
|
+
await bearerKeyDao.updateServerName(name, targetName);
|
|
750
810
|
// Drop embeddings stored under the old name so search_tools does not
|
|
751
811
|
// advertise phantom tools; addOrUpdateServer below regenerates them
|
|
752
812
|
// under the new name. A failure here must not abort the rename.
|
|
@@ -754,14 +814,12 @@ export const updateServer = async (req, res) => {
|
|
|
754
814
|
await removeServerToolEmbeddings(name);
|
|
755
815
|
}
|
|
756
816
|
catch (error) {
|
|
757
|
-
|
|
817
|
+
logger.warn('Failed to remove embeddings for renamed server', {
|
|
758
818
|
serverName: name,
|
|
759
819
|
error,
|
|
760
820
|
});
|
|
761
821
|
}
|
|
762
822
|
}
|
|
763
|
-
// Use the final server name (new name if renaming, otherwise original name)
|
|
764
|
-
const finalName = isRenaming ? newName : name;
|
|
765
823
|
// Fast path: if no connection-relevant field changed, persist and update
|
|
766
824
|
// in-memory access metadata without tearing down the runtime. This covers
|
|
767
825
|
// visibility/sharedWithUsers edits, description-only edits, owner changes,
|
|
@@ -823,15 +881,34 @@ export const updateServer = async (req, res) => {
|
|
|
823
881
|
export const getServerConfig = async (req, res) => {
|
|
824
882
|
try {
|
|
825
883
|
const { name } = req.params;
|
|
826
|
-
const
|
|
827
|
-
|
|
884
|
+
const serverDao = getServerDao();
|
|
885
|
+
const serverRecord = await serverDao.findById(name);
|
|
886
|
+
if (!serverRecord) {
|
|
887
|
+
res.status(404).json({
|
|
888
|
+
success: false,
|
|
889
|
+
message: 'Server not found',
|
|
890
|
+
});
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
// #1036 Phase 1: config read and server use are separate decisions.
|
|
894
|
+
// Owner/admin get the full configuration; visibility-admitted shared users
|
|
895
|
+
// (public / group members) get a safe view without secret-bearing fields;
|
|
896
|
+
// everyone else is rejected exactly as before.
|
|
897
|
+
const principal = getRequestUser(req);
|
|
898
|
+
const canReadFullConfig = authorizationService.can('server.config.read', serverRecord, principal);
|
|
899
|
+
if (!canReadFullConfig && !authorizationService.can('server.invoke', serverRecord, principal)) {
|
|
900
|
+
res.status(403).json({
|
|
901
|
+
success: false,
|
|
902
|
+
message: 'Forbidden',
|
|
903
|
+
});
|
|
828
904
|
return;
|
|
829
905
|
}
|
|
830
906
|
// Get runtime info (status, tools) from getServersInfo
|
|
831
907
|
const allServers = await getServersInfo();
|
|
832
908
|
const serverInfo = allServers.find((s) => s.name === name);
|
|
833
909
|
// Extract config without the name field
|
|
834
|
-
const { name: serverName, ...config } =
|
|
910
|
+
const { name: serverName, ...config } = serverRecord;
|
|
911
|
+
const presented = presentServerForPrincipal(config, principal);
|
|
835
912
|
// OpenAPI tools can carry circular $ref cycles left by SwaggerParser.dereference
|
|
836
913
|
// (recursive schemas), which would make res.json throw. Mirror the list endpoint
|
|
837
914
|
// and sanitize via createSafeJSON. See #959.
|
|
@@ -841,13 +918,13 @@ export const getServerConfig = async (req, res) => {
|
|
|
841
918
|
name: serverName,
|
|
842
919
|
status: serverInfo?.status || 'disconnected',
|
|
843
920
|
tools: serverInfo?.tools || [],
|
|
844
|
-
config,
|
|
921
|
+
config: presented.data,
|
|
845
922
|
}),
|
|
846
923
|
};
|
|
847
924
|
res.json(response);
|
|
848
925
|
}
|
|
849
926
|
catch (error) {
|
|
850
|
-
|
|
927
|
+
logger.error('Failed to get server configuration:', error);
|
|
851
928
|
res.status(500).json({
|
|
852
929
|
success: false,
|
|
853
930
|
message: 'Failed to get server configuration',
|
|
@@ -929,7 +1006,7 @@ export const reloadServer = async (req, res) => {
|
|
|
929
1006
|
});
|
|
930
1007
|
}
|
|
931
1008
|
catch (error) {
|
|
932
|
-
|
|
1009
|
+
logger.error('Failed to reload server:', error);
|
|
933
1010
|
res.status(500).json({
|
|
934
1011
|
success: false,
|
|
935
1012
|
message: 'Failed to reload server',
|
|
@@ -976,7 +1053,7 @@ export const disconnectServerOAuth = async (req, res) => {
|
|
|
976
1053
|
});
|
|
977
1054
|
}
|
|
978
1055
|
catch (error) {
|
|
979
|
-
|
|
1056
|
+
logger.error('Failed to disconnect server OAuth:', error);
|
|
980
1057
|
res.status(500).json({
|
|
981
1058
|
success: false,
|
|
982
1059
|
message: 'Failed to disconnect server OAuth',
|
|
@@ -1005,11 +1082,10 @@ export const reinstallServerHandler = async (req, res) => {
|
|
|
1005
1082
|
});
|
|
1006
1083
|
}
|
|
1007
1084
|
catch (error) {
|
|
1008
|
-
|
|
1085
|
+
logger.error('Failed to reinstall server:', error);
|
|
1009
1086
|
const message = error instanceof Error ? error.message : 'Failed to reinstall server';
|
|
1010
1087
|
// Validation errors (unsupported command, disabled server) → 400
|
|
1011
|
-
if (message.includes('does not support cache refresh') ||
|
|
1012
|
-
message.includes('disabled server')) {
|
|
1088
|
+
if (message.includes('does not support cache refresh') || message.includes('disabled server')) {
|
|
1013
1089
|
res.status(400).json({ success: false, message });
|
|
1014
1090
|
}
|
|
1015
1091
|
else {
|
|
@@ -1036,7 +1112,7 @@ export const clearCache = async (req, res) => {
|
|
|
1036
1112
|
});
|
|
1037
1113
|
}
|
|
1038
1114
|
catch (error) {
|
|
1039
|
-
|
|
1115
|
+
logger.error('Failed to clear cache:', error);
|
|
1040
1116
|
res.status(500).json({
|
|
1041
1117
|
success: false,
|
|
1042
1118
|
message: 'Failed to clear cache',
|
|
@@ -1050,7 +1126,7 @@ export const toggleTool = async (req, res) => {
|
|
|
1050
1126
|
const serverName = decodeURIComponent(req.params.serverName);
|
|
1051
1127
|
const toolName = decodeURIComponent(req.params.toolName);
|
|
1052
1128
|
const { enabled } = req.body;
|
|
1053
|
-
if (!serverName || !toolName) {
|
|
1129
|
+
if (!serverName || !toolName || ['__proto__', 'constructor', 'prototype'].includes(toolName)) {
|
|
1054
1130
|
res.status(400).json({
|
|
1055
1131
|
success: false,
|
|
1056
1132
|
message: 'Server name and tool name are required',
|
|
@@ -1103,7 +1179,7 @@ export const updateToolDescription = async (req, res) => {
|
|
|
1103
1179
|
const serverName = decodeURIComponent(req.params.serverName);
|
|
1104
1180
|
const toolName = decodeURIComponent(req.params.toolName);
|
|
1105
1181
|
const { description } = req.body;
|
|
1106
|
-
if (!serverName || !toolName) {
|
|
1182
|
+
if (!serverName || !toolName || ['__proto__', 'constructor', 'prototype'].includes(toolName)) {
|
|
1107
1183
|
res.status(400).json({
|
|
1108
1184
|
success: false,
|
|
1109
1185
|
message: 'Server name and tool name are required',
|
|
@@ -1158,7 +1234,7 @@ export const resetToolDescription = async (req, res) => {
|
|
|
1158
1234
|
try {
|
|
1159
1235
|
const serverName = decodeURIComponent(req.params.serverName);
|
|
1160
1236
|
const toolName = decodeURIComponent(req.params.toolName);
|
|
1161
|
-
if (!serverName || !toolName) {
|
|
1237
|
+
if (!serverName || !toolName || ['__proto__', 'constructor', 'prototype'].includes(toolName)) {
|
|
1162
1238
|
res.status(400).json({
|
|
1163
1239
|
success: false,
|
|
1164
1240
|
message: 'Server name and tool name are required',
|
|
@@ -1546,7 +1622,8 @@ export const updateSystemConfig = async (req, res) => {
|
|
|
1546
1622
|
systemConfig.smartRouting.azureOpenaiApiKey = smartRouting.azureOpenaiApiKey?.trim();
|
|
1547
1623
|
}
|
|
1548
1624
|
if (typeof smartRouting.azureOpenaiApiVersion === 'string') {
|
|
1549
|
-
systemConfig.smartRouting.azureOpenaiApiVersion =
|
|
1625
|
+
systemConfig.smartRouting.azureOpenaiApiVersion =
|
|
1626
|
+
smartRouting.azureOpenaiApiVersion?.trim();
|
|
1550
1627
|
}
|
|
1551
1628
|
if (typeof smartRouting.azureOpenaiEmbeddingDeployment === 'string') {
|
|
1552
1629
|
systemConfig.smartRouting.azureOpenaiEmbeddingDeployment =
|
|
@@ -1760,15 +1837,15 @@ export const updateSystemConfig = async (req, res) => {
|
|
|
1760
1837
|
});
|
|
1761
1838
|
// If smart routing configuration changed, sync all existing server tools
|
|
1762
1839
|
if (needsSync) {
|
|
1763
|
-
|
|
1840
|
+
logger.log('SmartRouting configuration changed - syncing all existing server tools...');
|
|
1764
1841
|
// Run sync asynchronously to avoid blocking the response
|
|
1765
1842
|
syncAllServerToolsEmbeddings().catch((error) => {
|
|
1766
|
-
|
|
1843
|
+
logger.error('Failed to sync server tools embeddings:', error);
|
|
1767
1844
|
});
|
|
1768
1845
|
}
|
|
1769
1846
|
}
|
|
1770
1847
|
catch (saveError) {
|
|
1771
|
-
|
|
1848
|
+
logger.error('Failed to save system configuration:', saveError);
|
|
1772
1849
|
res.status(500).json({
|
|
1773
1850
|
success: false,
|
|
1774
1851
|
message: 'Failed to save system configuration',
|
|
@@ -1789,7 +1866,9 @@ export const togglePrompt = async (req, res) => {
|
|
|
1789
1866
|
const serverName = decodeURIComponent(req.params.serverName);
|
|
1790
1867
|
const promptName = decodeURIComponent(req.params.promptName);
|
|
1791
1868
|
const { enabled } = req.body;
|
|
1792
|
-
if (!serverName ||
|
|
1869
|
+
if (!serverName ||
|
|
1870
|
+
!promptName ||
|
|
1871
|
+
['__proto__', 'constructor', 'prototype'].includes(promptName)) {
|
|
1793
1872
|
res.status(400).json({
|
|
1794
1873
|
success: false,
|
|
1795
1874
|
message: 'Server name and prompt name are required',
|
|
@@ -1842,7 +1921,9 @@ export const updatePromptDescription = async (req, res) => {
|
|
|
1842
1921
|
const serverName = decodeURIComponent(req.params.serverName);
|
|
1843
1922
|
const promptName = decodeURIComponent(req.params.promptName);
|
|
1844
1923
|
const { description } = req.body;
|
|
1845
|
-
if (!serverName ||
|
|
1924
|
+
if (!serverName ||
|
|
1925
|
+
!promptName ||
|
|
1926
|
+
['__proto__', 'constructor', 'prototype'].includes(promptName)) {
|
|
1846
1927
|
res.status(400).json({
|
|
1847
1928
|
success: false,
|
|
1848
1929
|
message: 'Server name and prompt name are required',
|
|
@@ -1895,7 +1976,9 @@ export const resetPromptDescription = async (req, res) => {
|
|
|
1895
1976
|
try {
|
|
1896
1977
|
const serverName = decodeURIComponent(req.params.serverName);
|
|
1897
1978
|
const promptName = decodeURIComponent(req.params.promptName);
|
|
1898
|
-
if (!serverName ||
|
|
1979
|
+
if (!serverName ||
|
|
1980
|
+
!promptName ||
|
|
1981
|
+
['__proto__', 'constructor', 'prototype'].includes(promptName)) {
|
|
1899
1982
|
res.status(400).json({
|
|
1900
1983
|
success: false,
|
|
1901
1984
|
message: 'Server name and prompt name are required',
|
|
@@ -1941,7 +2024,9 @@ export const toggleResource = async (req, res) => {
|
|
|
1941
2024
|
const serverName = decodeURIComponent(req.params.serverName);
|
|
1942
2025
|
const resourceUri = decodeURIComponent(req.params.resourceUri);
|
|
1943
2026
|
const { enabled } = req.body;
|
|
1944
|
-
if (!serverName ||
|
|
2027
|
+
if (!serverName ||
|
|
2028
|
+
!resourceUri ||
|
|
2029
|
+
['__proto__', 'constructor', 'prototype'].includes(resourceUri)) {
|
|
1945
2030
|
res.status(400).json({
|
|
1946
2031
|
success: false,
|
|
1947
2032
|
message: 'Server name and resource URI are required',
|
|
@@ -1994,7 +2079,9 @@ export const updateResourceDescription = async (req, res) => {
|
|
|
1994
2079
|
const serverName = decodeURIComponent(req.params.serverName);
|
|
1995
2080
|
const resourceUri = decodeURIComponent(req.params.resourceUri);
|
|
1996
2081
|
const { description } = req.body;
|
|
1997
|
-
if (!serverName ||
|
|
2082
|
+
if (!serverName ||
|
|
2083
|
+
!resourceUri ||
|
|
2084
|
+
['__proto__', 'constructor', 'prototype'].includes(resourceUri)) {
|
|
1998
2085
|
res.status(400).json({
|
|
1999
2086
|
success: false,
|
|
2000
2087
|
message: 'Server name and resource URI are required',
|
|
@@ -2047,7 +2134,9 @@ export const resetResourceDescription = async (req, res) => {
|
|
|
2047
2134
|
try {
|
|
2048
2135
|
const serverName = decodeURIComponent(req.params.serverName);
|
|
2049
2136
|
const resourceUri = decodeURIComponent(req.params.resourceUri);
|
|
2050
|
-
if (!serverName ||
|
|
2137
|
+
if (!serverName ||
|
|
2138
|
+
!resourceUri ||
|
|
2139
|
+
['__proto__', 'constructor', 'prototype'].includes(resourceUri)) {
|
|
2051
2140
|
res.status(400).json({
|
|
2052
2141
|
success: false,
|
|
2053
2142
|
message: 'Server name and resource URI are required',
|