mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 12:44:18 +08:00
fix(proxy): 修复 Copilot/Codex OAuth 模块绕过全局代理导致 Claude 模型 400 错误 (#4583)
* fix(copilot): 修复 GitHub Copilot 出站请求不走全局代理导致 model not supported * fix(proxy): 修复全局代理客户端配置未被应用到 Copilot/Codex OAuth 模块 两个关键问题: 1. CopilotAuthManager 在构造时写死 Client::new(),使得拉取 /models 列表、 换取 token 等认证流程无视全局代理配置(global_proxy_url),直连目标服务。 结果:直连时 /models 返回 0 个 Claude 模型 → live resolution 失效 → 模型 ID 无法正确归一化/匹配 → Copilot 上游返回 400 model_not_supported。 2. CodexOAuthManager 也有完全相同的问题,导致 Codex OAuth 认证请求绕过代理。 改动:删除两个模块的自持 http_client 字段,改为每次请求时从全局客户端现取 (crate::proxy::http_client::get())。这样: - 遵循全局代理 URL 配置 - 支持运行时热更新代理设置 - 符合代码库设计意图(http_client.rs 注释明确说"所有 HTTP 请求应使用此模块") 修复覆盖范围: - copilot_auth.rs: 7 处调用(token 获取、/models 拉取、model vendor 判断) - codex_oauth_auth.rs: 4 处调用(device code、OAuth token 刷新) Fixes #2016 #2931
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
//! - 通过 JWT id_token 提取 chatgpt_account_id 作为账号唯一标识
|
||||
|
||||
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
|
||||
use reqwest::Client;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
@@ -230,7 +230,6 @@ pub struct CodexOAuthManager {
|
||||
/// 进行中的 Device Code 流程:device_auth_id -> {user_code, expires_at_ms}
|
||||
/// 过期条目会在 start_device_flow 时被清理,防止放弃的登录流程导致无界增长
|
||||
pending_device_codes: Arc<RwLock<HashMap<String, PendingDeviceCode>>>,
|
||||
http_client: Client,
|
||||
storage_path: PathBuf,
|
||||
}
|
||||
|
||||
@@ -244,7 +243,6 @@ impl CodexOAuthManager {
|
||||
access_tokens: Arc::new(RwLock::new(HashMap::new())),
|
||||
refresh_locks: Arc::new(RwLock::new(HashMap::new())),
|
||||
pending_device_codes: Arc::new(RwLock::new(HashMap::new())),
|
||||
http_client: Client::new(),
|
||||
storage_path,
|
||||
};
|
||||
|
||||
@@ -266,8 +264,7 @@ impl CodexOAuthManager {
|
||||
pub async fn start_device_flow(&self) -> Result<GitHubDeviceCodeResponse, CodexOAuthError> {
|
||||
log::info!("[CodexOAuth] 启动 Device Code 流程");
|
||||
|
||||
let response = self
|
||||
.http_client
|
||||
let response = crate::proxy::http_client::get()
|
||||
.post(DEVICE_AUTH_USERCODE_URL)
|
||||
.header("Content-Type", "application/json")
|
||||
.header("User-Agent", CODEX_USER_AGENT)
|
||||
@@ -349,8 +346,7 @@ impl CodexOAuthManager {
|
||||
|
||||
log::debug!("[CodexOAuth] 轮询 Device Code");
|
||||
|
||||
let poll_response = self
|
||||
.http_client
|
||||
let poll_response = crate::proxy::http_client::get()
|
||||
.post(DEVICE_AUTH_TOKEN_URL)
|
||||
.header("Content-Type", "application/json")
|
||||
.header("User-Agent", CODEX_USER_AGENT)
|
||||
@@ -431,8 +427,7 @@ impl CodexOAuthManager {
|
||||
code: &str,
|
||||
code_verifier: &str,
|
||||
) -> Result<OAuthTokenResponse, CodexOAuthError> {
|
||||
let response = self
|
||||
.http_client
|
||||
let response = crate::proxy::http_client::get()
|
||||
.post(OAUTH_TOKEN_URL)
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.header("User-Agent", CODEX_USER_AGENT)
|
||||
@@ -465,8 +460,7 @@ impl CodexOAuthManager {
|
||||
&self,
|
||||
refresh_token: &str,
|
||||
) -> Result<OAuthTokenResponse, CodexOAuthError> {
|
||||
let response = self
|
||||
.http_client
|
||||
let response = crate::proxy::http_client::get()
|
||||
.post(OAUTH_TOKEN_URL)
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.header("User-Agent", CODEX_USER_AGENT)
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
//! - Provider 通过 meta.authBinding 关联账号
|
||||
//! - 自动迁移 v1 单账号格式到 v3 多账号 + 默认账号格式
|
||||
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
@@ -424,8 +423,6 @@ pub struct CopilotAuthManager {
|
||||
api_endpoints: Arc<RwLock<HashMap<String, String>>>,
|
||||
/// 每个账号的端点拉取锁,避免并发拉取重复打 GitHub API
|
||||
endpoint_locks: Arc<RwLock<HashMap<String, Arc<Mutex<()>>>>>,
|
||||
/// HTTP 客户端
|
||||
http_client: Client,
|
||||
/// 存储路径
|
||||
storage_path: PathBuf,
|
||||
/// 待迁移的旧格式 token
|
||||
@@ -447,7 +444,6 @@ impl CopilotAuthManager {
|
||||
copilot_models: Arc::new(RwLock::new(HashMap::new())),
|
||||
api_endpoints: Arc::new(RwLock::new(HashMap::new())),
|
||||
endpoint_locks: Arc::new(RwLock::new(HashMap::new())),
|
||||
http_client: Client::new(),
|
||||
storage_path,
|
||||
pending_migration: Arc::new(RwLock::new(None)),
|
||||
migration_error: Arc::new(RwLock::new(None)),
|
||||
@@ -602,8 +598,7 @@ impl CopilotAuthManager {
|
||||
};
|
||||
log::info!("[CopilotAuth] 启动设备码流程 (domain: {domain})");
|
||||
|
||||
let response = self
|
||||
.http_client
|
||||
let response = crate::proxy::http_client::get()
|
||||
.post(github_device_code_url(&domain))
|
||||
.header("Accept", "application/json")
|
||||
.header("User-Agent", COPILOT_USER_AGENT)
|
||||
@@ -647,8 +642,7 @@ impl CopilotAuthManager {
|
||||
};
|
||||
log::debug!("[CopilotAuth] 轮询 OAuth Token (domain: {domain})");
|
||||
|
||||
let response = self
|
||||
.http_client
|
||||
let response = crate::proxy::http_client::get()
|
||||
.post(github_oauth_token_url(&domain))
|
||||
.header("Accept", "application/json")
|
||||
.header("User-Agent", COPILOT_USER_AGENT)
|
||||
@@ -831,8 +825,7 @@ impl CopilotAuthManager {
|
||||
|
||||
log::info!("[CopilotAuth] 获取账号 {account_id} 的 Copilot 可用模型");
|
||||
|
||||
let response = self
|
||||
.http_client
|
||||
let response = crate::proxy::http_client::get()
|
||||
.get(&models_url)
|
||||
.header("Authorization", format!("Bearer {copilot_token}"))
|
||||
.header("Content-Type", "application/json")
|
||||
@@ -919,8 +912,7 @@ impl CopilotAuthManager {
|
||||
|
||||
log::info!("[CopilotAuth] 获取账号 {account_id} 的 Copilot 使用量");
|
||||
|
||||
let response = self
|
||||
.http_client
|
||||
let response = crate::proxy::http_client::get()
|
||||
.get(copilot_usage_url(&domain))
|
||||
.header("Authorization", format!("token {github_token}"))
|
||||
.header("Content-Type", "application/json")
|
||||
@@ -1034,8 +1026,7 @@ impl CopilotAuthManager {
|
||||
|
||||
log::debug!("[CopilotAuth] 为账号 {account_id} 惰性拉取动态 API 端点");
|
||||
|
||||
let response = self
|
||||
.http_client
|
||||
let response = crate::proxy::http_client::get()
|
||||
.get(copilot_usage_url(&domain))
|
||||
.header("Authorization", format!("token {github_token}"))
|
||||
.header("Content-Type", "application/json")
|
||||
@@ -1312,8 +1303,7 @@ impl CopilotAuthManager {
|
||||
github_token: &str,
|
||||
domain: &str,
|
||||
) -> Result<GitHubUser, CopilotAuthError> {
|
||||
let response = self
|
||||
.http_client
|
||||
let response = crate::proxy::http_client::get()
|
||||
.get(github_user_url(domain))
|
||||
.header("Authorization", format!("token {github_token}"))
|
||||
.header("User-Agent", COPILOT_USER_AGENT)
|
||||
@@ -1345,8 +1335,7 @@ impl CopilotAuthManager {
|
||||
) -> Result<(), CopilotAuthError> {
|
||||
log::debug!("[CopilotAuth] 获取账号 {account_id} 的 Copilot Token (domain: {domain})");
|
||||
|
||||
let response = self
|
||||
.http_client
|
||||
let response = crate::proxy::http_client::get()
|
||||
.get(copilot_token_url(domain))
|
||||
.header("Authorization", format!("token {github_token}"))
|
||||
.header("User-Agent", COPILOT_USER_AGENT)
|
||||
|
||||
Reference in New Issue
Block a user