Repository: Mintplex-Labs/anything-llm
File: server/models/systemSettings.js (JavaScript)

Code before:
      // CometAPI LLM Keys
      CometApiLLMApiKey: !!process.env.COMETAPI_LLM_API_KEY,
      CometApiLLMModelPref: process.env.COMETAPI_LLM_MODEL_PREF,
      CometApiLLMTimeout: process.env.COMETAPI_LLM_TIMEOUT_MS,

      // Z.AI Keys
      ZAiApiKey: !!process.env.ZAI_API_KEY,
      ZAiModelPref: process.env.ZAI_MODEL_PREF,

      // GiteeAI API Keys
      GiteeAIApiKey: !!process.env.GITEE_AI_API_KEY,
      GiteeAIModelPref: process.env.GITEE_AI_MODEL_PREF,
      GiteeAITokenLimit: process.env.GITEE_AI_MODEL_TOKEN_LIMIT || 8192,

      // Docker Model Runner Keys
      DockerModelRunnerBasePath: process.env.DOCKER_MODEL_RUNNER_BASE_PATH,
      DockerModelRunnerModelPref:
        process.env.DOCKER_MODEL_RUNNER_LLM_MODEL_PREF,
      DockerModelRunnerModelTokenLimit:
        process.env.DOCKER_MODEL_RUNNER_LLM_MODEL_TOKEN_LIMIT || 8192,
    };
  },

  agent_sql_connections: async function () {
    const setting = await SystemSettings.get({
      label: "agent_sql_connections",
    });
    if (!setting) return [];

    const connections = safeJsonParse(setting.value, []).map((conn) => {
      let scheme = conn.engine;
      if (scheme === "sql-server") scheme = "mssql";
      if (scheme === "postgresql") scheme = "postgres";
      const parser = new ConnectionStringParser({ scheme });

      const parsed = parser.parse(conn.connectionString);
      return {
        ...conn,
        username: parsed.username,
        password: parsed.password,
        host: parsed.hosts?.[0]?.host,
        port: parsed.hosts?.[0]?.port,
        database: parsed.endpoint,
        scheme: parsed.scheme,
      };
    });

    return connections;
  },
  getFeatureFlags: async function () {
    return {

Review comment (security):
Ah, I see, brief was to prevent sending the raw credentials back to the frontend since it is the direct SQL connection information - even if read-only.

I suppose all this did prior was send back all information in JSON form with the exception of `connectionString` - which at the time would just be
```json
[
    {
        "database_id": "myuniquedb",
        "engine": "postgresql"
    }
]
```

Thus, not expose any information to the UI via this call. I did go ahead and check and non-admins cannot even hit this endpoint to get the information. However, now we are passing back basically the entire credentials in plaintext back to the UI.

That being said, since this is only for admins, I believe doing this is okay as otherwise there is no way to verify or validate the values for a DB connection, which can be very tedious for those not used to using connection strings or DB's in general.

Take some time to review this carefully to ensure there is no accidental leakage of this information to the frontend (non-admins) and even in logging/tools or anything like that.


Code after:
      // CometAPI LLM Keys
      CometApiLLMApiKey: !!process.env.COMETAPI_LLM_API_KEY,
      CometApiLLMModelPref: process.env.COMETAPI_LLM_MODEL_PREF,
      CometApiLLMTimeout: process.env.COMETAPI_LLM_TIMEOUT_MS,

      // Z.AI Keys
      ZAiApiKey: !!process.env.ZAI_API_KEY,
      ZAiModelPref: process.env.ZAI_MODEL_PREF,

      // GiteeAI API Keys
      GiteeAIApiKey: !!process.env.GITEE_AI_API_KEY,
      GiteeAIModelPref: process.env.GITEE_AI_MODEL_PREF,
      GiteeAITokenLimit: process.env.GITEE_AI_MODEL_TOKEN_LIMIT || 8192,

      // Docker Model Runner Keys
      DockerModelRunnerBasePath: process.env.DOCKER_MODEL_RUNNER_BASE_PATH,
      DockerModelRunnerModelPref:
        process.env.DOCKER_MODEL_RUNNER_LLM_MODEL_PREF,
      DockerModelRunnerModelTokenLimit:
        process.env.DOCKER_MODEL_RUNNER_LLM_MODEL_TOKEN_LIMIT || 8192,

      // Privatemode Keys
      PrivateModeBasePath: process.env.PRIVATEMODE_LLM_BASE_PATH,
      PrivateModeModelPref: process.env.PRIVATEMODE_LLM_MODEL_PREF,
    };
  },

  agent_sql_connections: async function () {
    const setting = await SystemSettings.get({
      label: "agent_sql_connections",
    });
    if (!setting) return [];

    const connections = safeJsonParse(setting.value, []).map((conn) => {
      let scheme = conn.engine;
      if (scheme === "sql-server") scheme = "mssql";
      if (scheme === "postgresql") scheme = "postgres";
      const parser = new ConnectionStringParser({ scheme });

      const parsed = parser.parse(conn.connectionString);
      return {
        ...conn,
        username: parsed.username,
        password: parsed.password,
        host: parsed.hosts?.[0]?.host,
        port: parsed.hosts?.[0]?.port,
        database: parsed.endpoint,
        scheme: parsed.scheme,
      };
    });