huangzhenpc
2d77047287
Merge upstream/main: v0.1.61 updates with TOTP & password reset
...
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
Major features:
- feat(auth): add TOTP (2FA) support for enhanced security
- feat(auth): add password reset functionality
- feat(openai): improve rate limit handling with reset time tracking
- feat(subscription): add expiry notification service
- fix(urlvalidator): remove trailing slash from validated URLs
- docs: update demo site domain
Resolved conflicts:
- deploy/docker-compose.yml: added TOTP_ENCRYPTION_KEY config
- setting_service.go: keep TianShuAPI site name while adding new features
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2026-01-26 10:35:33 +08:00
Wesley Liddick
e32c5f534f
Merge pull request #386 from IanShaw027/fix/openai-usage-limit-reset-time
...
fix(ratelimit): 修复 OpenAI usage_limit_reached 错误的重置时间解析
2026-01-26 10:22:42 +08:00
ianshaw
a55cfebd09
fix(ratelimit): 修复 OpenAI usage_limit_reached 错误的重置时间解析
...
- 问题:OpenAI 的 usage_limit_reached 错误(需 37 小时重置)被错误地设置为 5 分钟
- 原因:handle429 只检查 Anthropic 响应头,没有解析 OpenAI 响应体中的 resets_in_seconds
- 修复:新增 parseOpenAIRateLimitResetTime 函数解析 OpenAI 响应体
- 影响:避免调度器不断尝试已达配额上限的账户
2026-01-26 09:57:44 +08:00
Wesley Liddick
34cc02f8c7
Merge pull request #393 from IanShaw027/fix/gemini-thought-signature-preserve
...
fix(gemini): 修复 thoughtSignature 跨账号验证错误
2026-01-26 09:23:46 +08:00
Wesley Liddick
624d9fddb7
Merge pull request #391 from geminiwen/main
...
fix(subscription): 修复订阅调整逻辑,已过期订阅从当前时间计算
2026-01-26 09:23:29 +08:00
Wesley Liddick
47fbe43324
Merge pull request #385 from DDZS987/fix/oauth-token-refresh-missing-project-id-retry
...
fix(oauth): 修复 OAuth 令牌刷新时 missing_project_id 误报问题
2026-01-26 09:22:48 +08:00
shaw
1245f07a2d
feat(auth): 实现 TOTP 双因素认证功能
...
新增功能:
- 支持 Google Authenticator 等应用进行 TOTP 二次验证
- 用户可在个人设置中启用/禁用 2FA
- 登录时支持 TOTP 验证流程
- 管理后台可全局开关 TOTP 功能
安全增强:
- TOTP 密钥使用 AES-256-GCM 加密存储
- 添加 TOTP_ENCRYPTION_KEY 配置项,必须手动配置才能启用功能
- 防止服务重启导致加密密钥变更使用户无法登录
- 验证失败次数限制,防止暴力破解
配置说明:
- Docker 部署:在 .env 中设置 TOTP_ENCRYPTION_KEY
- 非 Docker 部署:在 config.yaml 中设置 totp.encryption_key
- 生成密钥命令:openssl rand -hex 32
2026-01-26 09:19:53 +08:00
ianshaw
839975b0cf
feat(gemini): 支持 Gemini CLI 粘性会话与跨账号 thoughtSignature 清理
...
## 问题背景
1. Gemini CLI 没有明确的会话标识(如 Claude Code 的 metadata.user_id)
2. thoughtSignature 与具体上游账号强绑定,跨账号使用会导致 400 错误
3. 粘性会话切换账号或 cache 丢失时,旧签名会导致请求失败
## 解决方案
### 1. Gemini CLI 会话标识提取
- 从 `x-gemini-api-privileged-user-id` header 和请求体中的 tmp 目录哈希生成会话标识
- 组合策略:SHA256(privileged-user-id + ":" + tmp_dir_hash)
- 正则提取:`/\.gemini/tmp/([A-Fa-f0-9]{64})`
### 2. 跨账号 thoughtSignature 清理
实现三种场景的智能清理:
1. **Cache 命中 + 账号切换**
- 粘性会话绑定的账号与当前选择的账号不同时清理
2. **同一请求内 failover 切换**
- 通过 sessionBoundAccountID 跟踪,检测重试时的账号切换
3. **Gemini CLI + Cache 未命中 + 含签名**
- 预防性清理,避免 cache 丢失后首次转发就 400
- 仅对 Gemini CLI 请求且请求体包含 thoughtSignature 时触发
## 修改内容
### backend/internal/handler/gemini_v1beta_handler.go
- 添加 `extractGeminiCLISessionHash` 函数提取 Gemini CLI 会话标识
- 添加 `isGeminiCLIRequest` 函数识别 Gemini CLI 请求
- 实现账号切换检测与 thoughtSignature 清理逻辑
- 添加 `geminiCLITmpDirRegex` 正则表达式
### backend/internal/service/gateway_service.go
- 添加 `GetCachedSessionAccountID` 方法查询粘性会话绑定的账号 ID
### backend/internal/service/gemini_native_signature_cleaner.go (新增)
- 实现 `CleanGeminiNativeThoughtSignatures` 函数
- 递归清理 JSON 中的所有 thoughtSignature 字段
- 支持任意 JSON 顶层类型(object/array)
### backend/internal/handler/gemini_cli_session_test.go (新增)
- 测试 Gemini CLI 会话哈希提取逻辑
- 测试 tmp 目录正则匹配
- 覆盖有/无 privileged-user-id 的场景
## 影响范围
- 修复 Gemini CLI 多轮对话时账号切换导致的 400 错误
- 提高粘性会话的稳定性和容错能力
- 不影响其他客户端(Claude Code 等)的会话标识生成
## 测试
- 单元测试:go test -tags=unit ./internal/handler -run TestExtractGeminiCLISessionHash
- 单元测试:go test -tags=unit ./internal/handler -run TestGeminiCLITmpDirRegex
- 编译验证:go build ./cmd/server
2026-01-26 04:40:38 +08:00
Gemini Wen
9cdb0568cc
fix(subscription): 修复订阅调整逻辑,已过期订阅从当前时间计算
...
- 已过期订阅延长时,从当前时间开始增加天数
- 已过期订阅不允许负向调整(缩短)
- 未过期订阅保持原逻辑,从原过期时间增减
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2026-01-25 18:12:15 +08:00
shaw
74e05b83ea
fix(ratelimit): 修复 OpenAI 账号限流倒计时计算错误
...
- 解析 x-codex-* 响应头获取正确的重置时间
- 7d 限制用尽时使用 codex_7d_reset_after_seconds
- 提取 Normalize() 方法统一窗口规范化逻辑
2026-01-25 13:32:08 +08:00
Ubuntu
4ded9e7d49
fix(oauth): 为初始 OAuth 授权添加 LoadCodeAssist 重试机制
...
问题:
- 初始授权时 LoadCodeAssist 没有重试机制,失败后直接跳过
- 导致账号创建时就可能缺失 project_id
- 之后每次刷新都因为 missing_project_id 报错
修复:
- 统一使用 loadProjectIDWithRetry 方法(最多4次尝试)
- 初始授权和token刷新使用相同的重试策略
- 保留原注释说明部分账户可能没有 project_id
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2026-01-24 23:41:36 +08:00
Ubuntu
716272a1e2
fix(oauth): 彻底修复 project_id 丢失问题
...
根本原因:
- BuildAccountCredentials 只在 project_id 非空时才添加该字段
- LoadCodeAssist 失败时返回空字符串 → 新 credentials 不包含 project_id 键
- 普通合并逻辑只保留新 credentials 中不存在的键,无法覆盖空值
解决方案:
1. 在合并后特殊处理 project_id:如果新值为空但旧值非空,保留旧值
2. LoadCodeAssist 失败不再返回错误,只记录警告
3. Token 刷新成功(access_token 已更新)就不应标记账户为 error
改进效果:
- 即使 LoadCodeAssist 连续失败,已有的 project_id 也不会丢失
- 避免因临时网络问题将账户误标记为不可用
- 允许在下次刷新时自动重试获取 project_id
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2026-01-24 23:04:48 +08:00
shaw
9cc8352593
feat(auth): 密码重置邮件队列化与限流优化
...
- 邮件发送改为异步队列处理,避免并发导致发送失败
- 新增 Email 维度限流(30秒冷却期),防止邮件轰炸
- Token 验证使用常量时间比较,防止时序攻击
- 重构代码消除冗余,提取公共验证逻辑
2026-01-24 22:55:28 +08:00
Wesley Liddick
a5547b2f30
Merge pull request #380 from DDZS987/fix/oauth-token-refresh-missing-project-id-retry
...
fix(oauth): 修复 OAuth 令牌刷新时 missing_project_id 误报问题
2026-01-24 20:29:43 +08:00
shaw
b0aa23540b
feat(subscription): 订阅过期状态自动更新与服务端排序
...
- 新增 SubscriptionExpiryService 定时任务,每分钟更新过期订阅状态
- 订阅列表支持服务端排序(按过期时间、状态、创建时间)
- 实时显示正确的过期状态,无需等待定时任务
- 允许对已过期订阅进行续期操作
- DataTable 组件支持 serverSideSort 模式
2026-01-24 20:26:01 +08:00
Ubuntu
ffaa6c4a17
fix(oauth): 修复 OAuth 令牌刷新时 missing_project_id 误报问题
...
问题描述:
在网络波动环境下,LoadCodeAssist 临时失败会被错误地标记为
"missing_project_id" 不可重试错误,导致账户被禁用。但实际上
账户配置正确,手动刷新后即可恢复。
解决方案:
1. 为 LoadCodeAssist 增加重试机制(最多4次,指数退避)
2. 区分真正的配置缺失和临时网络故障:
- 如果之前有 project_id,本次获取失败只保留旧值,不报错
- 只有从未获取过 project_id 且本次也失败时,才标记为缺失
3. 优化错误判断逻辑,避免误报
改进效果:
- 提高在复杂网络环境(如家宽代理)下的鲁棒性
- 减少因临时网络波动导致的服务中断
- 保持真正配置错误的检测能力
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2026-01-24 17:44:56 +08:00
huangzhenpc
dc031ec3d0
Merge upstream/main: sync latest updates
...
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
- feat(gateway): aggregate all text chunks in non-streaming Gemini responses
- feat(gateway): add SUGGESTION MODE request interception
- feat(oauth): support Anthropic Team accounts with sk authorization
- fix(oauth): update Anthropic OAuth parameters to sync with latest client
- feat: add PromoCodeEnabled setting (default: true)
- resolved conflict: keep TianShuAPI site name while adding PromoCode feature
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2026-01-24 10:21:16 +08:00
lynoot
909b8a8f9c
fix(gateway): aggregate all text chunks in non-streaming Gemini responses
...
Previously, collectGeminiSSE() only returned the last chunk received
from the upstream streaming response when converting to non-streaming.
This caused incomplete responses where only the final text fragment
was returned to clients.
For example, a request asking to "count from 1 to 10" would only
return "\n" (the last chunk) instead of "1\n2\n3\n...\n10\n".
This was especially problematic for JSON structured output where
the opening brace "{" from the first chunk was lost, resulting
in invalid JSON like: colors": ["red", "blue"]}
The fix:
- Collect all text parts from each SSE chunk into a slice
- Merge all collected text parts into the final response
- Reuse the same pattern as handleGeminiStreamToNonStreaming
in antigravity_gateway_service.go
Fixes: non-streaming responses returning incomplete text
Fixes: structured output (JSON schema) returning invalid JSON
2026-01-23 13:54:09 +00:00
shaw
f9ab1daa3c
feat: 保存并显示OAuth账号邮箱地址
2026-01-23 15:17:47 +08:00
shaw
d27b847442
fix(test): 修复测试中引用不存在的函数名
...
测试文件引用了 IsTokenVersionStale 函数,但实际函数名为 CheckTokenVersion,导致 CI 构建失败
2026-01-23 10:58:30 +08:00
shaw
dac6bc2228
fix(token-cache): 版本过时时使用最新token而非旧token
...
上次修复(2665230 )只阻止了写入缓存,但仍返回旧token导致403。
现在版本过时时直接使用DB中的最新token返回。
- 重构 IsTokenVersionStale 为 CheckTokenVersion,返回最新account
- 消除重复DB查询,复用版本检查时已获取的account
2026-01-23 10:29:52 +08:00
Wesley Liddick
226df1c23a
Merge pull request #358 from 0xff26b9a8/main
...
fix(antigravity): 修复非流式 Claude To Antigravity 响应内容为空的问题
2026-01-22 21:16:54 +08:00
shaw
2665230a09
fix(token-cache): 修复异步刷新与请求线程的缓存竞态条件
...
- 新增 _token_version 版本号机制,防止过期 token 污染缓存
- TokenRefreshService 刷新成功后写入版本号并清除缓存
- TokenProvider 写入缓存前检查版本,过时则跳过
- ClearError 时同步清除 token 缓存
2026-01-22 21:09:28 +08:00
0xff26b9a8
4f0c2b794c
style: gofmt antigravity_gateway_service.go
2026-01-22 14:38:55 +08:00
0xff26b9a8
e756064c19
fix(antigravity): 修复非流式 Claude To Antigravity 响应内容为空的问题
...
- 修复 TransformGeminiToClaude 的 JSON 解析逻辑,当 V1InternalResponse
解析成功但 candidates 为空时,尝试直接解析为 GeminiResponse 格式
- 修复 handleClaudeStreamToNonStreaming 收集流式响应的逻辑,累积所有
chunks 的内容而不是只保留最后一个(最后一个 chunk 通常 text 为空)
- 新增 mergeCollectedPartsToResponse 函数,合并所有类型的 parts
(text、thinking、functionCall、inlineData),保持原始顺序
- 连续的普通 text parts 合并为一个,thinking/functionCall/inlineData 保持原样
2026-01-22 14:17:59 +08:00
0xff26b9a8
da48df06d2
refactor(antigravity): 提取并同步 Schema 清理逻辑至 schema_cleaner.go
...
主要变更:
1. 重构代码结构:
- 将 CleanJSONSchema 及其相关辅助函数从 request_transformer.go 提取到独立的 schema_cleaner.go 文件中,实现逻辑解耦。
2. 逻辑优化与修正:
- 参考 Antigravity-Manager (json_schema.rs) 的实现逻辑,修正了 Schema 清洗策略。
2026-01-20 23:41:53 +08:00
Wesley Liddick
5602d02b1b
Merge pull request #343 from mt21625457/main
...
fix(调度): 完善粘性会话清理与账号调度刷新 和 启用 OpenAI OAuth HTTP/2 并修复清理任务 lint
2026-01-20 16:05:53 +08:00
shaw
192efb84a0
feat(promo-code): complete promo code feature implementation
...
- Add promo_code_enabled field to SystemSettings and PublicSettings DTOs
- Add promo code validation in registration flow
- Add admin settings UI for promo code configuration
- Add i18n translations for promo code feature
2026-01-20 15:56:26 +08:00
huangzhenpc
6989e3420e
Merge remote-tracking branch 'upstream/main'
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
2026-01-20 14:39:03 +08:00
yangjianbo
2a16735495
fix(测试): 修复 SelectAccountWithLoadAwareness 调用缺少参数
...
为 gateway_multiplatform_test.go 中的 SelectAccountWithLoadAwareness
调用添加缺少的第6个参数 metadataUserID,修复 CI 测试编译错误。
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2026-01-20 14:16:46 +08:00
yangjianbo
292f25f9ca
Merge branch 'main' of https://github.com/mt21625457/aicodex2api
2026-01-20 14:02:08 +08:00
yangjianbo
f6ed3d1456
Merge branch 'test' into dev
2026-01-20 11:59:13 +08:00
yangjianbo
91f01309da
fix(调度): 完善粘性会话清理与账号调度刷新
...
- Update/BulkUpdate 按不可调度字段触发缓存刷新
- GatewayCache 支持多前缀会话键清理
- 模型路由与混合调度优化粘性会话处理
- 补充调度与缓存相关测试覆盖
2026-01-20 11:40:55 +08:00
Gemini Wen
cc07a0e295
feat(subscription): 支持调整订阅时长(延长/缩短)
...
- 将"延长订阅"功能改为"调整订阅",支持正数延长、负数缩短
- 后端验证:调整天数范围 -36500 到 36500,缩短后剩余天数必须 > 0
- 前端同步更新界面文案和验证逻辑
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2026-01-20 00:11:30 +08:00
yangjianbo
73e6b160f8
feat(认证): 启用 OpenAI OAuth HTTP/2 并修复清理任务 lint
...
为共享 req 客户端增加 HTTP/2 选项与缓存隔离
OpenAI OAuth 超时提升到 120s,并按协议控制强制
新增客户端池与 OAuth 客户端单测覆盖
修复 usage cleanup 相关 errcheck/ineffassign/staticcheck 并统一格式
测试: make test
2026-01-19 19:50:57 +08:00
shaw
b1a980f344
feat: 添加隐藏CCS导入按钮的设置选项
...
在管理后台设置页面新增开关,允许管理员隐藏API Keys页面的"导入CCS"按钮
2026-01-19 19:25:16 +08:00
shaw
3dab71729d
feat: usage接口支持TLS指纹和缓存User-Agent
2026-01-19 17:06:16 +08:00
shaw
090c8981dd
fix: 更新Claude OAuth授权配置以匹配最新规范
...
- 更新TokenURL和RedirectURI为platform.claude.com
- 更新scope定义,区分浏览器URL和内部API调用
- 修正state/code_verifier生成算法使用base64url编码
- 修正授权URL参数顺序并添加code=true
- 更新token交换请求头匹配官方实现
- 清理未使用的类型和函数
2026-01-19 16:40:06 +08:00
shaw
fbb572948d
fix: 修复会话数量查询使用错误的超时配置
2026-01-19 11:45:04 +08:00
shaw
a652b513d3
fix: handle 400 error for disabled organization
2026-01-19 10:54:40 +08:00
shaw
ccfeaeb22d
feat: 新增会话ID伪装功能,优化日志系统
...
- 新增 session_id_masking_enabled 配置,启用后将在15分钟内固定
metadata.user_id 中的 session ID
- TLS fingerprint 模块日志从自定义 debugLog 迁移到 slog
- main.go 添加 slog 初始化,根据 gin mode 设置日志级别
- 前端创建/编辑账号模态框添加会话ID伪装开关
- 多语言支持(中英文)
2026-01-19 10:22:13 +08:00
shaw
4c12799a95
fix: 补充测试桩缺失的接口方法
2026-01-19 09:28:11 +08:00
Wesley Liddick
0f8d42c577
Merge pull request #327 from mt21625457/main
...
feat(usage): 添加清理任务与统计过滤
2026-01-19 09:18:00 +08:00
Wesley Liddick
03c7578713
Merge pull request #325 from slovx2/main
...
fix(antigravity): 修复Antigravity 频繁429的问题,以及一系列优化,配置增强
2026-01-19 09:17:15 +08:00
shaw
de6797c560
fix: 修复5小时窗口费用不重置的问题
...
- 新增 GetCurrentWindowStartTime() 方法,当窗口过期时自动使用新的预测窗口开始时间
- UpdateSessionWindow 更新窗口时间后触发 outbox 事件同步调度器缓存
- 统一所有窗口费用查询入口使用新方法
2026-01-19 09:13:15 +08:00
huangzhenpc
c4cc56eb10
Merge remote-tracking branch 'upstream/main'
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
2026-01-18 23:46:19 +08:00
shaw
46ae08ecb7
fix: 补充测试桩缺失的接口方法
2026-01-18 22:23:03 +08:00
shaw
2028cc29b7
fix: 修复多个管理后台问题
...
- 分页接口 page_size 最大限制从 100 改为 1000
- 通过 Redis Pub/Sub 实现跨实例认证缓存失效
- 允许订阅类型分组编辑计费倍率
- 账号计费倍率支持 3 位小数
2026-01-18 22:13:47 +08:00
shaw
f6360e0bf3
fix: 移除未使用的 extractSessionUUID 函数
...
修复 golangci-lint unused 检查报错
2026-01-18 20:15:02 +08:00
shaw
9abda1bc59
feat(tls): 新增 TLS 指纹模拟功能
2026-01-18 20:08:40 +08:00