feat: add environment variable interpolation for API keys
- Add interpolateEnvVars function to support $VAR_NAME and ${VAR_NAME} syntax
- Apply interpolation to config after JSON5 parsing in readConfigFile()
- Enables secure API key management without hardcoding in config.json
- Supports nested objects and arrays for comprehensive interpolation
- Maintains backward compatibility with existing configurations
Example usage in config.json:
{
"OPENAI_API_KEY": "$OPENAI_API_KEY",
"Providers": [
{
"name": "openai",
"api_key": "$OPENAI_API_KEY"
}
]
}
This commit is contained in:
@@ -11,6 +11,26 @@ import {
|
|||||||
import { getSystemUUID, generateTempAPIKey, getTempAPIKey } from "./systemUUID";
|
import { getSystemUUID, generateTempAPIKey, getTempAPIKey } from "./systemUUID";
|
||||||
import { cleanupLogFiles } from "./logCleanup";
|
import { cleanupLogFiles } from "./logCleanup";
|
||||||
|
|
||||||
|
// Function to interpolate environment variables in config values
|
||||||
|
const interpolateEnvVars = (obj: any): any => {
|
||||||
|
if (typeof obj === "string") {
|
||||||
|
// Replace $VAR_NAME or ${VAR_NAME} with environment variable values
|
||||||
|
return obj.replace(/\$\{([^}]+)\}|\$([A-Z_][A-Z0-9_]*)/g, (match, braced, unbraced) => {
|
||||||
|
const varName = braced || unbraced;
|
||||||
|
return process.env[varName] || match; // Keep original if env var doesn't exist
|
||||||
|
});
|
||||||
|
} else if (Array.isArray(obj)) {
|
||||||
|
return obj.map(interpolateEnvVars);
|
||||||
|
} else if (obj !== null && typeof obj === "object") {
|
||||||
|
const result: any = {};
|
||||||
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
|
result[key] = interpolateEnvVars(value);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
const ensureDir = async (dir_path: string) => {
|
const ensureDir = async (dir_path: string) => {
|
||||||
try {
|
try {
|
||||||
await fs.access(dir_path);
|
await fs.access(dir_path);
|
||||||
@@ -52,7 +72,9 @@ export const readConfigFile = async () => {
|
|||||||
const config = await fs.readFile(CONFIG_FILE, "utf-8");
|
const config = await fs.readFile(CONFIG_FILE, "utf-8");
|
||||||
try {
|
try {
|
||||||
// Try to parse with JSON5 first (which also supports standard JSON)
|
// Try to parse with JSON5 first (which also supports standard JSON)
|
||||||
return JSON5.parse(config);
|
const parsedConfig = JSON5.parse(config);
|
||||||
|
// Interpolate environment variables in the parsed config
|
||||||
|
return interpolateEnvVars(parsedConfig);
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
console.error(`Failed to parse config file at ${CONFIG_FILE}`);
|
console.error(`Failed to parse config file at ${CONFIG_FILE}`);
|
||||||
console.error("Error details:", (parseError as Error).message);
|
console.error("Error details:", (parseError as Error).message);
|
||||||
|
|||||||
Reference in New Issue
Block a user