mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-12 22:14:22 +00:00
fix(web-server): add comprehensive reserved name validation
- Import isReservedName from centralized reserved-names module - Add validation to POST /api/profiles endpoint - Add validation to POST /api/cliproxy/openai-compat endpoint - Refactor hardcoded arrays to use centralized isReservedName() - Fixes DRY violation and ensures consistent validation across all endpoints
This commit is contained in:
1 parent
7ea64bdb43
commit
2373100c17
1 file changed
+23
-6
@@ -66,6 +66,7 @@ import { getWebSearchConfig } from '../config/unified-config-loader';
|
|||||||
import type { WebSearchConfig } from '../config/unified-config-types';
|
import type { WebSearchConfig } from '../config/unified-config-types';
|
||||||
import { isUnifiedConfig } from '../config/unified-config-types';
|
import { isUnifiedConfig } from '../config/unified-config-types';
|
||||||
import { isSensitiveKey, maskSensitiveValue } from '../utils/sensitive-keys';
|
import { isSensitiveKey, maskSensitiveValue } from '../utils/sensitive-keys';
|
||||||
|
import { isReservedName, RESERVED_PROFILE_NAMES } from '../config/reserved-names';
|
||||||
import {
|
import {
|
||||||
getWebSearchReadiness,
|
getWebSearchReadiness,
|
||||||
getGeminiCliStatus,
|
getGeminiCliStatus,
|
||||||
@@ -275,6 +276,15 @@ apiRoutes.post('/profiles', (req: Request, res: Response): void => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate reserved names
|
||||||
|
if (isReservedName(name)) {
|
||||||
|
res.status(400).json({
|
||||||
|
error: `Profile name '${name}' is reserved`,
|
||||||
|
reserved: RESERVED_PROFILE_NAMES,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const config = readConfigSafe();
|
const config = readConfigSafe();
|
||||||
|
|
||||||
if (config.profiles[name]) {
|
if (config.profiles[name]) {
|
||||||
@@ -378,11 +388,11 @@ apiRoutes.post('/cliproxy', (req: Request, res: Response): void => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject reserved provider names as variant names
|
// Reject reserved names as variant names (prevents collision with built-in providers)
|
||||||
const reservedNames = ['gemini', 'codex', 'agy', 'qwen', 'iflow'];
|
if (isReservedName(name)) {
|
||||||
if (reservedNames.includes(name.toLowerCase())) {
|
|
||||||
res.status(400).json({
|
res.status(400).json({
|
||||||
error: `Cannot use reserved provider name '${name}' as variant name`,
|
error: `Cannot use reserved name '${name}' as variant name`,
|
||||||
|
reserved: RESERVED_PROFILE_NAMES,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -482,8 +492,7 @@ apiRoutes.delete('/cliproxy/:name', (req: Request, res: Response): void => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Never delete settings files for reserved provider names (safety guard)
|
// Never delete settings files for reserved provider names (safety guard)
|
||||||
const reservedNames = ['gemini', 'codex', 'agy', 'qwen', 'iflow'];
|
if (!isReservedName(name)) {
|
||||||
if (!reservedNames.includes(name.toLowerCase())) {
|
|
||||||
// Only delete settings file for non-reserved variant names
|
// Only delete settings file for non-reserved variant names
|
||||||
const settingsPath = path.join(getCcsDir(), `${name}.settings.json`);
|
const settingsPath = path.join(getCcsDir(), `${name}.settings.json`);
|
||||||
if (fs.existsSync(settingsPath)) {
|
if (fs.existsSync(settingsPath)) {
|
||||||
@@ -1614,6 +1623,14 @@ apiRoutes.post('/cliproxy/openai-compat', (req: Request, res: Response): void =>
|
|||||||
res.status(400).json({ error: 'name is required' });
|
res.status(400).json({ error: 'name is required' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Validate reserved names
|
||||||
|
if (isReservedName(name)) {
|
||||||
|
res.status(400).json({
|
||||||
|
error: `Provider name '${name}' is reserved`,
|
||||||
|
reserved: RESERVED_PROFILE_NAMES,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!baseUrl || typeof baseUrl !== 'string') {
|
if (!baseUrl || typeof baseUrl !== 'string') {
|
||||||
res.status(400).json({ error: 'baseUrl is required' });
|
res.status(400).json({ error: 'baseUrl is required' });
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in new issue
Block a user