Commit Graph
1641 Commits
Author SHA1 Message Date
superman2003 dd7a2b22f0 fix(grok): align Free probes with health checks 2026-07-18 21:05:50 +08:00
Wesley Liddick a62b821b5f Merge pull request #4478 from yardbirds0/codex/fix-upstream-billing-probe-refresh
fix: 完善上游 Sub2API 倍率探测刷新、展示与账号配置
2026-07-18 20:49:14 +08:00
Wesley Liddick 774ff5d8c8 Merge pull request #4515 from BenjaminAaron196/feat/filter-noise-rejected-requests
(fix) 过滤入口拒绝日志并强化鉴权安全边界
2026-07-18 20:46:50 +08:00
Wesley Liddick d2667393b3 Merge pull request #4522 from wucm667/docs/issue-4518-http-bridge-prerequisite
docs: clarify OpenAI WS mode router prerequisite
2026-07-18 20:43:01 +08:00
Wesley Liddick 5a0492bf88 Merge pull request #4517 from weiness/fix/custom-branding-flash
fix: prevent custom branding flash on initial load
2026-07-18 20:39:00 +08:00
Wesley Liddick fdc9d92fdb Merge pull request #4528 from feitianbubu/fix/plan-validity-label-unit
fix(i18n): 套餐有效期表头与表单标签去掉写死的"天",与动态单位一致
2026-07-18 20:38:47 +08:00
feitianbubu c3f759d13a fix(i18n): 套餐有效期表头与表单标签去掉写死的"天",与动态单位一致 2026-07-18 10:59:11 +08:00
shaw 539bfc8bad feat(security): 敏感操作 step-up 2FA 开关化,安全开关默认关闭
新增系统设置 step_up_enabled(默认关闭),把敏感操作 2FA 门控做成可开关;
同时将会话 IP/UA 绑定默认值从开启改为关闭,避免用户因 IP 变动登录后掉线。

## 新增功能
- 敏感操作 step-up 2FA 总开关 step_up_enabled(默认关闭):关闭时账号/代理导出、
  备份创建/下载、S3 配置修改、提升管理员等操作恢复门控引入前的直接放行行为;
  开启后要求当前会话在 15 分钟内完成过 TOTP step-up 验证。

## 优化改进
- 会话 IP/UA 绑定默认改为关闭(功能保留,可在设置页按需开启)。
- 开启 step-up 开关需操作者本人已启用 TOTP(防自锁);关闭开关本身作为敏感操作,
  需通过 step-up 验证(防止攻击者拿到会话后先关闸再导出/备份)。
- 两个安全开关请求字段改为可空指针(省略=保持现值),避免旧客户端全量保存时
  静默重置安全开关。
- 备份恢复(整库覆盖可回滚安全设置)纳入 step-up 门控。
- 审计摘要 diffSettings 补记 step_up_enabled / session_binding_enabled 变更。

## Bug 修复
- 修复 BackupView 恢复操作 409(恢复进行中)判断未适配 apiClient 扁平化错误对象。
2026-07-18 10:46:42 +08:00
wucm667 8b75dd5576 docs: clarify OpenAI WS mode router prerequisite 2026-07-18 08:37:15 +08:00
weiness 500f241692 fix: prevent custom branding flash on initial load 2026-07-18 00:24:06 +08:00
benjamin b92bbf0299 fix: 过滤入口拒绝日志并强化鉴权边界 2026-07-18 00:11:18 +08:00
Tian Lee d2585097f3 fix: 完善上游 Sub2API 计费倍率探测与账号展示 2026-07-17 20:59:29 +08:00
Wesley Liddick 8bfbc5ca99 Merge pull request #4485 from Sub2API-Devs/dev
feat(security-audit): 新增 OpenAI 兼容提示词审计能力与安全审计控制台
2026-07-17 16:15:26 +08:00
mt21625457 e69e46ba02 feat: allow one-click audit event filter deletion 2026-07-17 15:50:31 +08:00
li 288d3a1cce fix(frontend): saveS3Config 接入 step-up TOTP 门控
Fixes #4445
2026-07-17 14:52:54 +08:00
mt21625457 ac685ccaf5 feat(security-audit): persist full prompts on audit events and polish event review UI
- Add prompt_audit_events.full_prompt (migration 182) so admins can review
  the exact unredacted prompt that triggered a finding; blocking mode writes
  it from the snapshot, async mode reconstructs it from the Redis scan
  payload so jobs rows stay redaction-only
- Event detail API returns full_prompt (list endpoint stays lean); text is
  NUL-stripped and capped at 65536 runes
- Detail dialog shows the full prompt in a scrollable pane with fallback to
  the legacy redacted preview; page copy updated to match the new behavior
- Rework filter deletion into a dedicated dialog with time-range presets and
  criteria-change preview invalidation; localize decision/risk/category
  labels across the events workspace
- Fix pre-existing i18n message-compile spec by declaring the
  @intlify/message-compiler dev dependency
2026-07-17 14:38:10 +08:00
mt21625457andCursor 18e698bed6 feat(security-audit): allow admin-managed audit node targets and polish pool UI
Let admins configure private/intranet Guard endpoints without destination-class blocking, and fix prompt-audit switch layout so thumbs and labels no longer overlap.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-17 11:45:14 +08:00
Wesley Liddick 2a75d7d238 Merge pull request #4462 from Wei-Shaw/fix/unify-security-client-ip
fix(security): unify audit log & session binding client IP with API key ACL trust toggle
2026-07-17 09:42:43 +08:00
Wesley Liddick 1c3f2810af Merge pull request #4461 from yardbirds0/feat/account-homepage-link
feat: 支持从 API Key 账号名称跳转上游站点主页
2026-07-17 09:34:50 +08:00
shawandClaude 7c48f9a85f fix(security): unify audit log & session binding client IP with API key ACL trust toggle
Behind a reverse proxy (e.g. nginx with X-Real-IP), admin audit logs and
session IP/UA binding always recorded 127.0.0.1 because they hardcoded
the gin trusted_proxies chain, while API key IP restriction already
honored the "trust forwarded client IP" system setting.

- add ip.GetSecurityClientIP(c, trustForwarded) as the single source of
  truth for security-sensitive client IP selection; API key auth
  middlewares (main + google) refactored onto it with zero behavior change
- SessionBindingContext(cfg) now resolves the client IP via the same
  toggle and injects it into the request context; token issuance,
  binding enforcement and its mismatch audit record all read the
  injected value, so issue/verify can never diverge
- audit log middleware and audit-log clear trace record the same
  security client IP (middleware.SecurityClientIP), falling back to the
  trusted proxy chain when the injection is absent
- settings UI hint (zh/en) documents the broadened toggle scope and the
  one-time re-login after toggling while session binding is enabled

With the toggle off (default) behavior is byte-for-byte unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 09:33:18 +08:00
shawandClaude 980a46ffb0 fix(i18n): add missing OpenAI account entry labels
- admin.accounts.oauth.openai.mobileRefreshTokenAuth was referenced by
  OAuthAuthorizationFlow.vue since 9f8cffe88 (Mobile RT entry) but never
  added to zh/en locales, rendering the raw key in the add-account wizard
- admin.accounts.oauth.openai.accessTokenAuth has the same latent issue
  since 26060e702 (Sora AT import); currently hidden but fixed alongside

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 09:32:48 +08:00
yardbirds0 824f763a77 feat: 支持从 API Key 账号名称跳转上游站点 2026-07-17 09:15:32 +08:00
mt21625457andCursor 0f7f8a317e fix(security-audit): close prompt-audit bypass and privacy gaps
Stop WebSocket follow-up turns from reusing a request-wide audit cache, scan
client-controlled instruction fields, fail closed on stale weaker configs, and
tighten preview/SSRF controls including persisted request stage.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-17 08:46:57 +08:00
mt21625457 d11bdb13f5 feat(security-audit): add OpenAI-compatible prompt auditing 2026-07-17 00:39:39 +08:00
wucm667 08e994ad86 fix(frontend): lazy-load Stripe payment dependency 2026-07-16 23:21:58 +08:00
Wesley Liddick 7e13b6d039 Merge pull request #4425 from AdrianZhaoDev/agent/admin-users-batch-limits
feat(admin): batch update user concurrency and RPM
2026-07-16 19:33:32 +08:00
Wesley Liddick c993490a82 Merge pull request #4434 from yan9651688/feat/group-one-click-copy
feat(group): add safe one-click duplication
2026-07-16 19:33:18 +08:00
Wesley Liddick 4d91f39474 Merge pull request #4431 from linyqh/codex/fix-codex-image-handoff
fix(openai): 修复 Codex 生图网关侧交接问题
2026-07-16 19:32:33 +08:00
Wesley Liddick af6bd44d2a Merge pull request #4435 from superman2003/fix/grok-codex-wsv2-template
fix(grok): enable Codex Responses WebSocket v2 in setup template
2026-07-16 19:32:14 +08:00
Wesley Liddick 541ca3bc27 Merge pull request #4430 from feitianbubu/fix/proxy-fallback-label
fix(i18n): 代理"失败回退"改名"到期回退",与实际行为一致
2026-07-16 19:32:04 +08:00
shaw 7f5d067af2 feat(grok): 支持上游端点手动切换与快捷端点,修复 SSO 建号自定义地址被覆盖
官方端点(api.x.ai / cli-chat-proxy.grok.com)偶发不可用,运营方需要在
端点间手动切换。旧语义把 OAuth 账号存储的官方 host 一律视同"未定制"并
回落默认 CLI 网关:填了官方地址保存成功却不生效、重新编辑开关回到关闭、
再次保存直接删值,形成"修改不生效"的静默循环。

后端:
- GetGrokBaseURL OAuth 分支改为"存了什么用什么":官方 API / 区域 API /
  第三方转发地址一律按填写值转发与探测,仅空值或无法解析的脏数据回落
  默认 CLI 网关;删除官方变体运行时迁移逻辑
- *.api.x.ai 区域端点(us-east-1/us-west-2/eu-west-1 等)纳入可信 host,
  OAuth 使用时不受运营方 URL 白名单限制,官方 host 仍强制 /v1 path
- 修复 SSO 批量建号 MergeCredentials 方向缺陷:BuildAccountCredentials
  恒写官方 base_url,会覆盖导入请求指定的自定义转发地址;抽出
  grokSSOImportCredentials 显式保留请求值(与 RefreshAccountToken 对齐)

前端:
- isCustomGrokBaseUrl 仅默认 CLI 网关 host 视同未定制:api.x.ai 与区域
  端点保存后正常回显(开关开启 + 显示地址),不再被静默吞掉
- 新增 GrokBaseUrlPresets 快捷端点组件(Grok Build CLI / 官方 API /
  us-east-1 / us-west-2 / eu-west-1),接入编辑(OAuth 自定义区 + apikey
  Base URL)、新增(同前)与批量编辑(所选平台全为 grok 时显示,点击
  自动勾选 base_url);仅快速填充,输入框仍可自由填写任意第三方地址
2026-07-16 19:10:21 +08:00
superman2003 174ea22eeb fix(grok): enable Codex Responses WebSocket v2 2026-07-16 18:30:59 +08:00
yan9651688 9fc006546c Make repeated group setup safer
Admins often recreate groups with the same pricing, routing, and account membership. A server-side duplicate creates an inactive copy for review, preserves eligible account priorities, and recovers ambiguous retries without creating extra groups.

Constraint: Group has no neutral JSON metadata field for durable operation recovery
Constraint: Model routing references account IDs, so copied configuration requires matching bindings
Rejected: Rebuild from the list response | it omits configuration and account priority details
Rejected: Store operation identity in business configuration | it would pollute real group settings
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep duplicated groups inactive until an administrator reviews the copied configuration
Tested: Go unit and full tests, go vet, integration-tag compile, frontend Vitest, lint, typecheck, production build, and Playwright duplicate flow
Not-tested: PostgreSQL container integration locally because Docker is unavailable; CI will execute the database-backed suite
2026-07-16 18:18:28 +08:00
viccyandOmX 9d1064badd 澄清 Codex 图片桥接与本地执行器边界
配置界面现在区分非 Responses Lite 的 hosted 桥接与客户端本地 image_gen,并准确描述账号 strip 策略。API Key Mode 同时提示完全重启 Codex 后新建 task,以重建客户端工具注册表。

Constraint: 兼容模式继续保持默认,Responses Lite 的本地工具由客户端与账号策略决定
Rejected: 写入 features.image_generation | 当前 Codex 已默认启用且仓库既有配置刻意省略该项
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: 图片桥接文案必须区分 hosted 注入、客户端声明和 image-only 路由
Tested: 前端 lint、typecheck、关键套件 93 项、定向套件 43 项
Not-tested: Codex Desktop 真实工具注册表重建

Co-authored-by: OmX <omx@oh-my-codex.dev>
2026-07-16 17:11:17 +08:00
feitianbubu ca82fd6e98 fix(i18n): rename proxy fallback label to expiry fallback 2026-07-16 17:09:23 +08:00
Wesley Liddick dbef64bb45 Merge pull request #4427 from yan9651688/feat/channel-monitor-one-click-copy
feat(channel-monitor): add safe one-click duplication
2026-07-16 16:54:22 +08:00
shaw 35748d8c51 feat(security): gate admin role promotion behind step-up 2FA and harden admin TOTP verification
- 提升用户为管理员 / 创建管理员账号纳入敏感操作:handler 级 EnforceStepUp 门控
  (admin API key 拒绝、未启用 TOTP 拒绝、无 grant 返回 STEP_UP_REQUIRED),
  目标已是管理员的日常编辑不触发
- 管理员启用/停用 2FA 一律使用密码验证(默认通知邮箱常收不到验证码),
  verification-method 按用户角色返回;普通用户行为不变
- 用户编辑/创建弹窗接入 useStepUp:命中 STEP_UP_REQUIRED 弹 TOTP 验证并自动重试
- 审计日志清理入口与其他敏感操作对齐:未启用 2FA 时直接提示先启用 TOTP,
  不再弹出无法完成的验证码输入框(后端强制现场 TOTP 语义不变)
- 审计日志页重构:DataTable 布局、详情弹窗分区展示、时间范围改为 ops 同款
  下拉(预设窗口 + 自定义起止支持时分)
2026-07-16 16:49:08 +08:00
yan9651688 e2e375d694 Make repeated channel-monitor setup safer
Admins often recreate monitors with the same endpoint, model, and request settings. A server-side duplicate keeps the stored API key out of the browser, creates a disabled copy for review, and uses stable operation identity to recover ambiguous retries without creating extra rows.

Constraint: Stored monitor API keys must never be returned to the browser
Constraint: Applying a request template must preserve internal duplicate recovery metadata
Rejected: Rebuild the monitor from list data | list responses only contain a masked API key
Rejected: Copy runtime state and history | a duplicate should start as an unverified configuration
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep duplicated monitors disabled until an administrator reviews and enables them
Tested: Go unit tests for repository, service, and admin handler; integration-tag compile; go vet; golangci-lint v2.9; frontend Vitest, ESLint, typecheck, production build; Playwright duplicate flow
Not-tested: PostgreSQL container integration locally because Docker is unavailable; CI will execute the database-backed suite
2026-07-16 16:30:19 +08:00
zhaozewu 7947619cc3 feat(admin): batch update user limits 2026-07-16 15:37:35 +08:00
shaw 2d97207d41 fix(settings): 审计日志保留天数清空时回退默认值避免保存 400
audit_log_retention_days 用 v-model.number 绑定数字框,管理员清空输入框时
得到空串,后端 int 字段 ShouldBindJSON 解析空串失败返回 400,导致整次系统
设置保存被拒。payload 构建时对空/非法值回退默认 180(与后端
parseAuditLogRetentionDays("") 语义一致;显式 0 仍表示永久保留)。
2026-07-16 15:19:19 +08:00
shaw 2de6ccb071 fix(security): 补齐审计日志脱敏缺口 + step-up 下载/取消体验修复
审计发现修复:

高危——审计日志请求体脱敏不全(audit_logs 沦为明文凭证聚合点):
- 键名归一化比对(小写+去分隔符),覆盖 privateKey/apiv3key 等无分隔符与 camelCase 写法
- 程序化并入 SensitiveCredentialKeys 与 providerSensitiveConfigFields 两份权威敏感表,防清单漂移
- 补齐 proxy_key(内嵌代理密码)、custom_key(自设 API Key 明文)精确键
- Codex session 导入路由 body 整体由粘贴的 auth JSON 构成,键级脱敏无法覆盖,整体不入库
- 新增守卫测试:两份权威表的每个键必须被审计脱敏命中;provider_key 等渠道标识保留以便追责

中危——step-up 前端体验:
- 备份下载改同页 anchor 导航(预签名 URL 后端强制 attachment disposition),
  避免 step-up 弹窗 await 耗尽瞬态激活后 window.open 被浏览器拦截
- useStepUp.run 用户取消时抛 StepUpCancelledError sentinel,
  三个调用点静默处理,不再把取消误报为红色错误 toast

低危:
- 修正审计中间件挂载位置的陈旧注释(实际挂在认证之后)
- 审计 body 捕获改 LimitReader 按 256KB 上限截断读取,超出部分拼接回填,
  避免大体积导入请求被完整复制进内存两次
- TOTP step-up 弹窗验证成功后即时清空验证码输入
2026-07-16 14:38:16 +08:00
shaw 0ddd58aaf9 feat(security): 操作审计日志 + 会话IP/UA绑定 + 敏感操作 step-up 2FA
应对管理员访问凭证失守导致的数据外泄风险,新增三层防护:

审计日志(admin-only 可见,用户不可见)
- 新增 append-only audit_logs 表(migration 180)+ 异步批量写入 + 保留期清理
- 审计中间件挂在 admin/user/auth/admin-payment 组认证之后:记录所有变更类
  请求 + 白名单敏感读取(账号/代理导出、备份下载、admin/user API key 读取)
- 请求头凭证首尾掩码;请求体 JSON 递归脱敏(api_key/password 等擦除,base_url
  保留以便追责);非 JSON body 不入库
- 无单条删除;全量清空需现场 TOTP 校验、拒绝 admin API key、未启用 2FA 不允许,
  清空后同步写入留痕记录

会话 IP/UA 绑定(默认开启,可在系统设置关闭)
- JWT 携带 session id + IP/UA 指纹哈希;IP 或 UA 任一变化即撤销会话家族并要求
  重新登录;旧 token 无指纹时放行以平滑升级

敏感操作 step-up 2FA(sudo 窗口 15 分钟)
- 账号/代理导出、DB 备份创建/下载、S3 目标修改要求近期 TOTP 二次验证;admin API
  key 一律拒绝;前端 useStepUp 组合式 + TotpStepUpDialog 弹码后自动重试
- API key 查看按需求暂不加强管控

前端:新增 /admin/audit-logs 操作日志页面(筛选/详情/2FA 清空)、侧边栏入口、
step-up 弹窗接入导出与备份流程、安全设置项(绑定开关 + 日志保留天数)、zh/en i18n
2026-07-16 13:47:50 +08:00
shaw 0408bdb34f Merge remote-tracking branch 'origin/main' into feat/upstream-rate-scheduling
# Conflicts:
#	backend/internal/handler/openai_gateway_handler.go
2026-07-16 10:31:21 +08:00
Wesley Liddick ab978e615e Merge pull request #4385 from yardbirds0/feat/upstream-billing-probe
feat: 增加上游 Sub2API 计费倍率探测与账号展示
2026-07-16 10:27:45 +08:00
Wesley Liddick e4329a04e8 Merge pull request #4393 from superman2003/fix/grok-codex-compatibility
fix(grok): improve Codex compatibility and key setup
2026-07-16 09:33:20 +08:00
Wesley Liddick 807850769f Merge pull request #4396 from StarryKira/fix/4386-image-input-pricing
fix(billing): 图像输入 token 按独立单价计费(gpt-image-2 图片编辑)
2026-07-16 09:32:29 +08:00
Wesley Liddick ba01199812 Merge pull request #4376 from drgnchan/hotfix/find-n6-table-scroll
fix(frontend): preserve horizontal table scrolling on tablets
2026-07-16 09:31:16 +08:00
harukaandClaude Opus 4.8 62d57c02d8 feat(billing): usage_logs 单独记录图片输入 token 与费用
图片编辑/图生图请求的图片输入 token 此前并入 input_tokens/input_cost,
无法对账。拆分上报口径,total_cost 保持不变。

后端:
- CostBreakdown 新增 ImageInputCost;computeTokenBreakdown 将图片输入费用
  从 InputCost 拆出(InputCost 从此仅含文本输入),并纳入 tier 倍率与总额;
  长上下文合并路径同步携带 ImageInputCost
- 迁移 179:usage_logs 新增 image_input_tokens / image_input_cost 列
- UsageLog、insert/query 仓储(含定位参数数组、CTE 列表、扫描顺序)、
  DTO 与 mapper 补齐两列
- openai_gateway_usage 从 usage 与 cost 落库图片输入 token/费用

前端:
- UsageLog 类型、imageUsage 工具(hasImageInputTokens/Cost、textInputTokens)
- 用量表 token 徽标、Token/费用 tooltip 与单价行按图/文输入拆分展示
- zh/en usage.* i18n

测试:
- 新增 gpt-image-2 图片编辑复现用例(复现 #4386 的 $0.016081 期望值)
- 新增 usage 提取器图片输入 token 解析用例(input_tokens_details.image_tokens)
- 更新 doubao 图文分价用例与仓储/契约测试以匹配新的 input/image 拆分口径

相关 #4386。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015wcJTKDddxXSQrepSs3wrU
2026-07-15 10:03:38 -07:00
Tian Lee 90ee85f3ef feat: 按上游计费倍率调度 OpenAI 账号 2026-07-16 00:40:46 +08:00
harukaandClaude Opus 4.8 06e03f467a feat(billing): 渠道自定义定价支持图片输入 token 单价 image_input_price
渠道 token 计费模式此前无法为图片输入 token 单独定价,gpt-image-2
图片编辑等请求的图像输入被按文本 input_price 计费。新增
channel_model_pricing.image_input_price 列及全链路支持。

后端:
- 迁移 178:channel_model_pricing 新增 image_input_price 列
- ChannelModelPricing 新增 ImageInputPrice 字段,repo 读写、校验补齐
- model_pricing_resolver / GetModelPricingWithChannel 映射到
  ImageInputPricePerToken;未配置时归零,由 computeTokenBreakdown
  回退文本输入价(向后兼容,与 image_output_price 的渠道权威规则一致)
- admin / 用户侧定价 DTO 与 model-pricing 自动填充接口补充该字段

前端:
- 渠道定价表单新增「图片输入」价格输入(token 模式)
- API 类型、表单模型、form↔API 换算、自动填充、用户侧模型定价卡展示
- zh/en i18n 标签

相关 #4386。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015wcJTKDddxXSQrepSs3wrU
2026-07-15 09:35:34 -07:00