mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-04-08 15:10:34 +08:00
fix(proxy): respect existing token field when syncing Claude config
- Add support for ANTHROPIC_API_KEY in Claude auth extraction - Only update existing token fields during sync, avoid adding fields that weren't originally configured by the user - Add tests for both scenarios
This commit is contained in:
@@ -87,6 +87,14 @@ impl ClaudeAdapter {
|
|||||||
log::debug!("[Claude] 使用 ANTHROPIC_AUTH_TOKEN");
|
log::debug!("[Claude] 使用 ANTHROPIC_AUTH_TOKEN");
|
||||||
return Some(key.to_string());
|
return Some(key.to_string());
|
||||||
}
|
}
|
||||||
|
if let Some(key) = env
|
||||||
|
.get("ANTHROPIC_API_KEY")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
{
|
||||||
|
log::debug!("[Claude] 使用 ANTHROPIC_API_KEY");
|
||||||
|
return Some(key.to_string());
|
||||||
|
}
|
||||||
// OpenRouter key
|
// OpenRouter key
|
||||||
if let Some(key) = env
|
if let Some(key) = env
|
||||||
.get("OPENROUTER_API_KEY")
|
.get("OPENROUTER_API_KEY")
|
||||||
@@ -284,6 +292,21 @@ mod tests {
|
|||||||
assert_eq!(auth.strategy, AuthStrategy::Anthropic);
|
assert_eq!(auth.strategy, AuthStrategy::Anthropic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_extract_auth_anthropic_api_key() {
|
||||||
|
let adapter = ClaudeAdapter::new();
|
||||||
|
let provider = create_provider(json!({
|
||||||
|
"env": {
|
||||||
|
"ANTHROPIC_BASE_URL": "https://api.anthropic.com",
|
||||||
|
"ANTHROPIC_API_KEY": "sk-ant-test-key"
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
let auth = adapter.extract_auth(&provider).unwrap();
|
||||||
|
assert_eq!(auth.api_key, "sk-ant-test-key");
|
||||||
|
assert_eq!(auth.strategy, AuthStrategy::Anthropic);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_auth_openrouter() {
|
fn test_extract_auth_openrouter() {
|
||||||
let adapter = ClaudeAdapter::new();
|
let adapter = ClaudeAdapter::new();
|
||||||
|
|||||||
@@ -312,34 +312,35 @@ impl ProxyService {
|
|||||||
|
|
||||||
match env_obj {
|
match env_obj {
|
||||||
Some(obj) => {
|
Some(obj) => {
|
||||||
obj.insert(token_key.to_string(), json!(token));
|
|
||||||
// ANTHROPIC_AUTH_TOKEN 与 ANTHROPIC_API_KEY 视为同义字段,保持一致
|
|
||||||
if token_key == "ANTHROPIC_AUTH_TOKEN"
|
if token_key == "ANTHROPIC_AUTH_TOKEN"
|
||||||
|| token_key == "ANTHROPIC_API_KEY"
|
|| token_key == "ANTHROPIC_API_KEY"
|
||||||
{
|
{
|
||||||
obj.insert(
|
let mut updated = false;
|
||||||
"ANTHROPIC_AUTH_TOKEN".to_string(),
|
if obj.contains_key("ANTHROPIC_AUTH_TOKEN") {
|
||||||
json!(token),
|
obj.insert(
|
||||||
);
|
"ANTHROPIC_AUTH_TOKEN".to_string(),
|
||||||
obj.insert(
|
json!(token),
|
||||||
"ANTHROPIC_API_KEY".to_string(),
|
);
|
||||||
json!(token),
|
updated = true;
|
||||||
);
|
}
|
||||||
|
if obj.contains_key("ANTHROPIC_API_KEY") {
|
||||||
|
obj.insert(
|
||||||
|
"ANTHROPIC_API_KEY".to_string(),
|
||||||
|
json!(token),
|
||||||
|
);
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
if !updated {
|
||||||
|
obj.insert(token_key.to_string(), json!(token));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
obj.insert(token_key.to_string(), json!(token));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// 至少写入一份可用的 Token
|
// 至少写入一份可用的 Token
|
||||||
provider.settings_config["env"] = json!({
|
provider.settings_config["env"] =
|
||||||
token_key: token
|
json!({ token_key: token });
|
||||||
});
|
|
||||||
if token_key == "ANTHROPIC_AUTH_TOKEN"
|
|
||||||
|| token_key == "ANTHROPIC_API_KEY"
|
|
||||||
{
|
|
||||||
provider.settings_config["env"]
|
|
||||||
["ANTHROPIC_AUTH_TOKEN"] = json!(token);
|
|
||||||
provider.settings_config["env"]["ANTHROPIC_API_KEY"] =
|
|
||||||
json!(token);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1575,6 +1576,47 @@ impl ProxyService {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use serial_test::serial;
|
||||||
|
use std::env;
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
struct TempHome {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
dir: TempDir,
|
||||||
|
original_home: Option<String>,
|
||||||
|
original_userprofile: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TempHome {
|
||||||
|
fn new() -> Self {
|
||||||
|
let dir = TempDir::new().expect("failed to create temp home");
|
||||||
|
let original_home = env::var("HOME").ok();
|
||||||
|
let original_userprofile = env::var("USERPROFILE").ok();
|
||||||
|
|
||||||
|
env::set_var("HOME", dir.path());
|
||||||
|
env::set_var("USERPROFILE", dir.path());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
dir,
|
||||||
|
original_home,
|
||||||
|
original_userprofile,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TempHome {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
match &self.original_home {
|
||||||
|
Some(value) => env::set_var("HOME", value),
|
||||||
|
None => env::remove_var("HOME"),
|
||||||
|
}
|
||||||
|
|
||||||
|
match &self.original_userprofile {
|
||||||
|
Some(value) => env::set_var("USERPROFILE", value),
|
||||||
|
None => env::remove_var("USERPROFILE"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn update_toml_base_url_updates_active_model_provider_base_url() {
|
fn update_toml_base_url_updates_active_model_provider_base_url() {
|
||||||
@@ -1637,4 +1679,116 @@ model = "gpt-5.1-codex"
|
|||||||
|
|
||||||
assert_eq!(base_url, new_url);
|
assert_eq!(base_url, new_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
|
async fn sync_claude_token_does_not_add_anthropic_api_key() {
|
||||||
|
let _home = TempHome::new();
|
||||||
|
crate::settings::reload_settings().expect("reload settings");
|
||||||
|
|
||||||
|
let db = Arc::new(Database::memory().expect("init db"));
|
||||||
|
let service = ProxyService::new(db.clone());
|
||||||
|
|
||||||
|
let provider = Provider::with_id(
|
||||||
|
"p1".to_string(),
|
||||||
|
"P1".to_string(),
|
||||||
|
json!({
|
||||||
|
"env": {
|
||||||
|
"ANTHROPIC_BASE_URL": "https://api.anthropic.com",
|
||||||
|
"ANTHROPIC_AUTH_TOKEN": "stale"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
db.save_provider("claude", &provider)
|
||||||
|
.expect("save provider");
|
||||||
|
db.set_current_provider("claude", "p1")
|
||||||
|
.expect("set current provider");
|
||||||
|
|
||||||
|
let live_config = json!({
|
||||||
|
"env": {
|
||||||
|
"ANTHROPIC_AUTH_TOKEN": "fresh"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
service
|
||||||
|
.sync_live_config_to_provider(&AppType::Claude, &live_config)
|
||||||
|
.await
|
||||||
|
.expect("sync");
|
||||||
|
|
||||||
|
let updated = db
|
||||||
|
.get_provider_by_id("p1", "claude")
|
||||||
|
.expect("get provider")
|
||||||
|
.expect("provider exists");
|
||||||
|
let env = updated
|
||||||
|
.settings_config
|
||||||
|
.get("env")
|
||||||
|
.and_then(|v| v.as_object())
|
||||||
|
.expect("env object");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
env.get("ANTHROPIC_AUTH_TOKEN").and_then(|v| v.as_str()),
|
||||||
|
Some("fresh")
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!env.contains_key("ANTHROPIC_API_KEY"),
|
||||||
|
"should not add ANTHROPIC_API_KEY when absent"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
|
async fn sync_claude_token_respects_existing_api_key_field() {
|
||||||
|
let _home = TempHome::new();
|
||||||
|
crate::settings::reload_settings().expect("reload settings");
|
||||||
|
|
||||||
|
let db = Arc::new(Database::memory().expect("init db"));
|
||||||
|
let service = ProxyService::new(db.clone());
|
||||||
|
|
||||||
|
let provider = Provider::with_id(
|
||||||
|
"p1".to_string(),
|
||||||
|
"P1".to_string(),
|
||||||
|
json!({
|
||||||
|
"env": {
|
||||||
|
"ANTHROPIC_BASE_URL": "https://api.anthropic.com",
|
||||||
|
"ANTHROPIC_API_KEY": "stale"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
db.save_provider("claude", &provider)
|
||||||
|
.expect("save provider");
|
||||||
|
db.set_current_provider("claude", "p1")
|
||||||
|
.expect("set current provider");
|
||||||
|
|
||||||
|
let live_config = json!({
|
||||||
|
"env": {
|
||||||
|
"ANTHROPIC_AUTH_TOKEN": "fresh"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
service
|
||||||
|
.sync_live_config_to_provider(&AppType::Claude, &live_config)
|
||||||
|
.await
|
||||||
|
.expect("sync");
|
||||||
|
|
||||||
|
let updated = db
|
||||||
|
.get_provider_by_id("p1", "claude")
|
||||||
|
.expect("get provider")
|
||||||
|
.expect("provider exists");
|
||||||
|
let env = updated
|
||||||
|
.settings_config
|
||||||
|
.get("env")
|
||||||
|
.and_then(|v| v.as_object())
|
||||||
|
.expect("env object");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
env.get("ANTHROPIC_API_KEY").and_then(|v| v.as_str()),
|
||||||
|
Some("fresh")
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!env.contains_key("ANTHROPIC_AUTH_TOKEN"),
|
||||||
|
"should not add ANTHROPIC_AUTH_TOKEN when absent"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user