diff --git a/backend/internal/service/gemini_session.go b/backend/internal/service/gemini_session.go index 1780d1da..cd291328 100644 --- a/backend/internal/service/gemini_session.go +++ b/backend/internal/service/gemini_session.go @@ -52,10 +52,11 @@ func BuildGeminiDigestChain(req *antigravity.GeminiRequest) string { // 返回 16 字符的 Base64 编码的 SHA256 前缀 func GenerateGeminiPrefixHash(userID, apiKeyID int64, ip, userAgent, platform, model string) string { // 组合所有标识符 + normalizedUserAgent := NormalizeSessionUserAgent(userAgent) combined := strconv.FormatInt(userID, 10) + ":" + strconv.FormatInt(apiKeyID, 10) + ":" + ip + ":" + - userAgent + ":" + + normalizedUserAgent + ":" + platform + ":" + model diff --git a/backend/internal/service/gemini_session_test.go b/backend/internal/service/gemini_session_test.go index a034cddd..27321996 100644 --- a/backend/internal/service/gemini_session_test.go +++ b/backend/internal/service/gemini_session_test.go @@ -152,6 +152,24 @@ func TestGenerateGeminiPrefixHash(t *testing.T) { } } +func TestGenerateGeminiPrefixHash_IgnoresUserAgentVersionNoise(t *testing.T) { + hash1 := GenerateGeminiPrefixHash(1, 100, "192.168.1.1", "Mozilla/5.0 codex_cli_rs/0.1.0", "antigravity", "gemini-2.5-pro") + hash2 := GenerateGeminiPrefixHash(1, 100, "192.168.1.1", "Mozilla/5.0 codex_cli_rs/0.1.1", "antigravity", "gemini-2.5-pro") + + if hash1 != hash2 { + t.Fatalf("version-only User-Agent changes should not perturb Gemini prefix hash: %s vs %s", hash1, hash2) + } +} + +func TestGenerateGeminiPrefixHash_IgnoresFreeformUserAgentVersionNoise(t *testing.T) { + hash1 := GenerateGeminiPrefixHash(1, 100, "192.168.1.1", "Codex CLI 0.1.0", "antigravity", "gemini-2.5-pro") + hash2 := GenerateGeminiPrefixHash(1, 100, "192.168.1.1", "Codex CLI 0.1.1", "antigravity", "gemini-2.5-pro") + + if hash1 != hash2 { + t.Fatalf("free-form version-only User-Agent changes should not perturb Gemini prefix hash: %s vs %s", hash1, hash2) + } +} + func TestParseGeminiSessionValue(t *testing.T) { tests := []struct { name string