Files
CST-agent/src/creds.c
T
WHCandCursor 1f1fcba7ad Initial CST-Agent: portable Linux/Termux/Windows coding agent.
Vendored sashidown, OpenAI-compatible env (OPENAI_*), and bootstrap scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-07 22:42:32 +08:00

141 lines
3.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#define _DEFAULT_SOURCE
#include "cst_agent.h"
#include "os_compat.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
/* Config dir via os_compat: ~/.config/cst-agent or %APPDATA%\cst-agent */
static int credentials_path(char *out, size_t n) {
char dir[OS_PATH_MAX];
if (os_config_dir(dir, sizeof(dir)) != 0)
return -1;
return os_path_join(out, n, dir, "credentials");
}
int cst_creds_load_api_key(char *out, size_t out_sz) {
if (!out || out_sz < 2)
return -1;
out[0] = 0;
char path[OS_PATH_MAX];
if (credentials_path(path, sizeof(path)) != 0)
return -1;
FILE *fp = fopen(path, "r");
if (!fp)
return -1;
char line[1024];
while (fgets(line, sizeof(line), fp)) {
if (strncmp(line, "api_key=", 8) != 0)
continue;
char *v = line + 8;
size_t len = strlen(v);
while (len > 0 && (v[len - 1] == '\n' || v[len - 1] == '\r'))
v[--len] = 0;
if (len == 0 || len + 1 > out_sz) {
fclose(fp);
return -1;
}
memcpy(out, v, len + 1);
fclose(fp);
return 0;
}
fclose(fp);
return -1;
}
int cst_creds_save_api_key(const char *key) {
if (!key || !key[0])
return -1;
char dir[OS_PATH_MAX], path[OS_PATH_MAX];
if (os_config_dir(dir, sizeof(dir)) != 0)
return -1;
if (os_mkdir(dir, 0700) != 0)
return -1;
if (credentials_path(path, sizeof(path)) != 0)
return -1;
FILE *fp = fopen(path, "w");
if (!fp)
return -1;
fprintf(fp, "api_key=%s\n", key);
fprintf(fp, "api_base=https://api.minimax.cn/v1\n");
fprintf(fp, "model=MiniMax-M2.7\n");
fclose(fp);
(void)os_chmod_private(path);
return 0;
}
/* Zenity on Unix; stdin prompt elsewhere / when zenity missing. */
int cst_creds_prompt_api_key(char *out, size_t out_sz) {
if (!out || out_sz < 2)
return -1;
out[0] = 0;
#ifndef _WIN32
FILE *fp = popen(
"zenity --password --title='CST-Agent / MiniMax' "
"--text='请输入 MiniMax API Key(将保存到配置目录 credentials)' "
"2>/dev/null",
"r");
if (fp) {
if (fgets(out, (int)out_sz, fp)) {
int st = pclose(fp);
size_t len = strlen(out);
while (len > 0 && (out[len - 1] == '\n' || out[len - 1] == '\r'))
out[--len] = 0;
if (st == 0 && len > 0)
return 0;
} else {
pclose(fp);
}
out[0] = 0;
}
#endif
/* Fallback: console prompt (headless / Windows / no zenity). */
fprintf(stderr, "CST-Agent: enter MiniMax API Key (saved to config dir): ");
fflush(stderr);
if (!fgets(out, (int)out_sz, stdin)) {
out[0] = 0;
return -1;
}
size_t len = strlen(out);
while (len > 0 && (out[len - 1] == '\n' || out[len - 1] == '\r'))
out[--len] = 0;
if (len == 0) {
out[0] = 0;
return -1;
}
return 0;
}
int cst_creds_ensure_api_key(char *out, size_t out_sz) {
const char *env = getenv("CST_API_KEY");
if (!env || !env[0])
env = getenv("MINIMAX_API_KEY");
if (!env || !env[0])
env = getenv("OPENAI_API_KEY");
if (env && env[0]) {
snprintf(out, out_sz, "%s", env);
return 0;
}
if (cst_creds_load_api_key(out, out_sz) == 0 && out[0])
return 0;
if (cst_creds_prompt_api_key(out, out_sz) != 0)
return -1;
if (cst_creds_save_api_key(out) != 0)
fprintf(stderr, "warning: failed to save credentials file\n");
else
fprintf(stderr, "saved API key to config directory\n");
return 0;
}