mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-03-26 07:36:46 +08:00
fix(copilot): unify request fingerprint across all Copilot API calls
- Make header constants in copilot_auth.rs public, add COPILOT_INTEGRATION_ID - Unify User-Agent across 4 internal methods (eliminate "CC-Switch" leakage) and version string - claude.rs add_auth_headers now references shared constants, adds user-agent / api-version / openai-intent - forwarder.rs filters all 6 fixed fingerprint headers for Copilot requests to prevent reqwest append duplication - stream_check.rs health check pipeline aligned with new fingerprint
This commit is contained in:
@@ -856,9 +856,22 @@ impl RequestForwarder {
|
||||
|
||||
// 过滤黑名单 Headers,保护隐私并避免冲突
|
||||
for (key, value) in headers {
|
||||
let key_str = key.as_str();
|
||||
if HEADER_BLACKLIST
|
||||
.iter()
|
||||
.any(|h| key.as_str().eq_ignore_ascii_case(h))
|
||||
.any(|h| key_str.eq_ignore_ascii_case(h))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Copilot 请求:过滤会由 add_auth_headers 注入的固定指纹头,
|
||||
// 防止客户端原始头与注入头重复(reqwest header() 是追加语义)
|
||||
if is_copilot
|
||||
&& (key_str.eq_ignore_ascii_case("user-agent")
|
||||
|| key_str.eq_ignore_ascii_case("editor-version")
|
||||
|| key_str.eq_ignore_ascii_case("editor-plugin-version")
|
||||
|| key_str.eq_ignore_ascii_case("copilot-integration-id")
|
||||
|| key_str.eq_ignore_ascii_case("x-github-api-version")
|
||||
|| key_str.eq_ignore_ascii_case("openai-intent"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -346,12 +346,15 @@ impl ProviderAdapter for ClaudeAdapter {
|
||||
AuthStrategy::Bearer => {
|
||||
request.header("Authorization", format!("Bearer {}", auth.api_key))
|
||||
}
|
||||
// GitHub Copilot: Bearer + 特定的 Editor headers
|
||||
// GitHub Copilot: Bearer + 统一指纹头
|
||||
AuthStrategy::GitHubCopilot => request
|
||||
.header("Authorization", format!("Bearer {}", auth.api_key))
|
||||
.header("Editor-Version", "vscode/1.85.0")
|
||||
.header("Editor-Plugin-Version", "copilot/1.150.0")
|
||||
.header("Copilot-Integration-Id", "vscode-chat"),
|
||||
.header("editor-version", super::copilot_auth::COPILOT_EDITOR_VERSION)
|
||||
.header("editor-plugin-version", super::copilot_auth::COPILOT_PLUGIN_VERSION)
|
||||
.header("copilot-integration-id", super::copilot_auth::COPILOT_INTEGRATION_ID)
|
||||
.header("user-agent", super::copilot_auth::COPILOT_USER_AGENT)
|
||||
.header("x-github-api-version", super::copilot_auth::COPILOT_API_VERSION)
|
||||
.header("openai-intent", "conversation-panel"),
|
||||
_ => request,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,10 +46,11 @@ const TOKEN_REFRESH_BUFFER_SECONDS: i64 = 60;
|
||||
const COPILOT_MODELS_URL: &str = "https://api.githubcopilot.com/models";
|
||||
|
||||
/// Copilot API Header 常量
|
||||
const COPILOT_EDITOR_VERSION: &str = "vscode/1.96.0";
|
||||
const COPILOT_PLUGIN_VERSION: &str = "copilot-chat/0.26.7";
|
||||
const COPILOT_USER_AGENT: &str = "GitHubCopilotChat/0.26.7";
|
||||
const COPILOT_API_VERSION: &str = "2025-04-01";
|
||||
pub const COPILOT_EDITOR_VERSION: &str = "vscode/1.96.0";
|
||||
pub const COPILOT_PLUGIN_VERSION: &str = "copilot-chat/0.26.7";
|
||||
pub const COPILOT_USER_AGENT: &str = "GitHubCopilotChat/0.26.7";
|
||||
pub const COPILOT_API_VERSION: &str = "2025-04-01";
|
||||
pub const COPILOT_INTEGRATION_ID: &str = "vscode-chat";
|
||||
|
||||
/// Copilot 使用量 API URL
|
||||
const COPILOT_USAGE_URL: &str = "https://api.github.com/copilot_internal/user";
|
||||
@@ -465,6 +466,7 @@ impl CopilotAuthManager {
|
||||
.http_client
|
||||
.post(GITHUB_DEVICE_CODE_URL)
|
||||
.header("Accept", "application/json")
|
||||
.header("User-Agent", COPILOT_USER_AGENT)
|
||||
.form(&[("client_id", GITHUB_CLIENT_ID), ("scope", "read:user")])
|
||||
.send()
|
||||
.await?;
|
||||
@@ -502,6 +504,7 @@ impl CopilotAuthManager {
|
||||
.http_client
|
||||
.post(GITHUB_OAUTH_TOKEN_URL)
|
||||
.header("Accept", "application/json")
|
||||
.header("User-Agent", COPILOT_USER_AGENT)
|
||||
.form(&[
|
||||
("client_id", GITHUB_CLIENT_ID),
|
||||
("device_code", device_code),
|
||||
@@ -948,7 +951,9 @@ impl CopilotAuthManager {
|
||||
.http_client
|
||||
.get(GITHUB_USER_URL)
|
||||
.header("Authorization", format!("token {}", github_token))
|
||||
.header("User-Agent", "CC-Switch")
|
||||
.header("User-Agent", COPILOT_USER_AGENT)
|
||||
.header("Editor-Version", COPILOT_EDITOR_VERSION)
|
||||
.header("Editor-Plugin-Version", COPILOT_PLUGIN_VERSION)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
@@ -978,9 +983,9 @@ impl CopilotAuthManager {
|
||||
.http_client
|
||||
.get(COPILOT_TOKEN_URL)
|
||||
.header("Authorization", format!("token {}", github_token))
|
||||
.header("User-Agent", "CC-Switch")
|
||||
.header("Editor-Version", "vscode/1.85.0")
|
||||
.header("Editor-Plugin-Version", "copilot/1.150.0")
|
||||
.header("User-Agent", COPILOT_USER_AGENT)
|
||||
.header("Editor-Version", COPILOT_EDITOR_VERSION)
|
||||
.header("Editor-Plugin-Version", COPILOT_PLUGIN_VERSION)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ use crate::app_config::AppType;
|
||||
use crate::error::AppError;
|
||||
use crate::provider::Provider;
|
||||
use crate::proxy::providers::transform::anthropic_to_openai;
|
||||
use crate::proxy::providers::copilot_auth;
|
||||
use crate::proxy::providers::{get_adapter, AuthInfo, AuthStrategy};
|
||||
|
||||
/// 健康状态枚举
|
||||
@@ -362,9 +363,12 @@ impl StreamCheckService {
|
||||
.header("content-type", "application/json")
|
||||
.header("accept", "text/event-stream")
|
||||
.header("accept-encoding", "identity")
|
||||
.header("editor-version", "vscode/1.85.0")
|
||||
.header("editor-plugin-version", "copilot/1.150.0")
|
||||
.header("copilot-integration-id", "vscode-chat");
|
||||
.header("user-agent", copilot_auth::COPILOT_USER_AGENT)
|
||||
.header("editor-version", copilot_auth::COPILOT_EDITOR_VERSION)
|
||||
.header("editor-plugin-version", copilot_auth::COPILOT_PLUGIN_VERSION)
|
||||
.header("copilot-integration-id", copilot_auth::COPILOT_INTEGRATION_ID)
|
||||
.header("x-github-api-version", copilot_auth::COPILOT_API_VERSION)
|
||||
.header("openai-intent", "conversation-panel");
|
||||
} else if is_openai_chat {
|
||||
// OpenAI-compatible: Bearer auth + standard headers only
|
||||
request_builder = request_builder
|
||||
|
||||
Reference in New Issue
Block a user