Commit Graph
5370 Commits
Author SHA1 Message Date
wucm667 739c0ff9c5 feat(home): add compact home page preset to avoid abuse classification
- Add compact_home_enabled setting to provide a minimal landing page
- Preserves custom home_content priority over compact mode
- Renders only site identity, navigation, and login/dashboard link
- Avoids marketing copy that triggers anti-fraud systems
- Includes focused backend/frontend tests and i18n support

Fixes #5065
2026-07-30 16:28:19 +08:00
github-actions[bot] 5a6143097d chore: sync VERSION to 0.1.168 [skip ci] 2026-07-29 03:51:01 +00:00
github-actions[bot] b9c7cb8e24 chore: sync VERSION to 0.1.167 [skip ci] 2026-07-29 03:36:59 +00:00
Wesley Liddick 99c8e4bf75 Merge pull request #4973 from yiancode/fix/openai-live-store-resilience
fix(openai-live): Live 会话 finalize 与 observer 对 store 故障的容错,防止用量记录静默丢失
v0.1.168
2026-07-29 09:42:56 +08:00
Wesley Liddick f2d824836f Merge pull request #5008 from hansnow/fix/claude-sonnet-5-status-alias
fix(frontend): 补充 Claude Sonnet 5 模型状态别名
2026-07-29 09:41:54 +08:00
Wesley Liddick 6e1cbed423 Merge pull request #5024 from Wei-Shaw/fix/passkey-disabled-toast
fix(profile): 修复未配置 Passkey 时 /profile 每次访问都弹「加载 Passkey 失败」
2026-07-29 09:41:06 +08:00
shaw acad7f1a09 fix(profile): stop passkey load error toast when feature is disabled
The PASSKEY_DISABLED silence guard compared the string error code
against error.code, but the api client puts the numeric envelope code
there and the string code in error.reason, so the guard never matched
and every /profile visit on deployments without WebAuthn configured
showed a spurious "failed to load passkeys" toast.

Read error.reason instead, and skip the credentials request entirely
when the feature is disabled so the card no longer issues a request
that is guaranteed to fail with 403.
2026-07-28 22:51:58 +08:00
Wesley Liddick 8fd01c2814 Merge pull request #5003 from feeeei/main
feat(模型广场): add model plaza with group-scoped pricing showcase
2026-07-28 20:02:52 +08:00
Wesley Liddick 39903f006e Merge pull request #5005 from Wei-Shaw/refactor/scoped-column-updates
refactor(repository): scope user/api-key updates to explicitly declared columns
2026-07-28 19:43:50 +08:00
hansnow 32618e71e4 fix(frontend): 补充 Claude Sonnet 5 状态别名 2026-07-28 18:17:38 +08:00
shaw 86fb4781f4 refactor(repository): scope user/api-key updates to declared columns
UserRepository.Update and APIKeyRepository.Update rewrote the whole row on
every call, regardless of which fields the caller meant to change. Several
columns on those tables are maintained by dedicated atomic paths (balance
deduction, quota and rate-limit counters, limit adjustments, activity
timestamps), so a caller holding a slightly older snapshot could silently
roll them back - a lost update.

Both methods now take an explicit column mask and persist only the columns
the caller declares; everything else keeps its current database value.

- All user and API-key call sites declare exactly what they mutate, which
  turns admin edits and profile saves into genuine partial updates.
- Email uniqueness locking/lookup and allowed_groups sync only run when
  those fields are part of the update.
- UserUpdateFields deliberately has no balance/total_recharged members, so
  Update cannot touch them. New AdjustBalance/SetBalance apply the change in
  a single statement and return before/after values; admin balance
  adjustment uses them instead of read-modify-write.
- promo_codes.used_count is no longer written by Update; it is only ever
  incremented by the redemption path.
- The billing hot path that marks an API key quota-exhausted writes only
  status.
- Dropped a no-op row write in RevokeAllUserTokens: users has no
  token_version column, so it persisted nothing while still overwriting
  concurrently-updated columns.

Adds integration coverage that a stale snapshot cannot revert concurrent
atomic writes, and unit coverage pinning the column set each entry point
declares.
2026-07-28 17:21:32 +08:00
feeeei 720c405e35 feat: add model plaza with group-scoped pricing showcase
- public /model-plaza page (standalone + admin-embedded) listing groups
  with discounted effective prices alongside LiteLLM official reference
- faceted platform/group/rate filters: cross-dimension options gray out
  instead of disappearing, platform-tinted chips via accent color-mix
- paid-price columns highlighted with per-platform tint band
- OptionalJWT middleware so anonymous and signed-in users share one route
- admin settings: enable switch, require-auth switch, markdown description
2026-07-28 16:19:41 +08:00
Wesley Liddick 2e432173f7 Merge pull request #4920 from alexj11324/feat/passkey-auth
feat: add passkey authentication
2026-07-28 14:58:37 +08:00
shaw 38ef8dc069 feat: require account password for passkey enrollment and revocation
A hijacked session must not be able to silently add a passkey as a
persistent backdoor or remove the victim's credentials. Registration
(begin) and deletion now verify the account password server-side,
reusing the existing PASSWORD_REQUIRED / PASSWORD_INCORRECT errors.

The password is used instead of TOTP step-up so the guard also protects
deployments that never configured a TOTP encryption key. The password
key in both request bodies is covered by the audit middleware's
key-substring redaction, so no credential material reaches audit_logs.

Frontend: the add-passkey form gains a current-password field, and the
delete confirmation is now a dialog with a password input (replacing
window.confirm), mirroring the TOTP disable dialog. Backend error
messages (e.g. wrong password) are surfaced instead of the generic
failure toast. Rename remains password-free as it is cosmetic.
2026-07-28 14:12:46 +08:00
shaw 97f44b21bb fix: keep passkey switch coupled to WebAuthn config and fix CI issues
- parseSettings now reports passkey_enabled=false whenever the WebAuthn
  deployment config is absent: a stale "true" row left behind after the
  config is removed previously made the admin update gate reject every
  settings save while the UI toggle was disabled, leaving no recovery
  path from the admin panel. Added a regression test.
- update the admin settings API contract goldens with the new
  passkey_enabled/passkey_configured/passkey_rp_id/passkey_rp_origins
  fields.
- errcheck: check rows.Close in passkey repository (repo convention).
- staticcheck QF1001: apply De Morgan's law in WebAuthn origin scheme
  validation.
2026-07-28 11:45:18 +08:00
Wesley Liddick 0ef2228ce9 Merge pull request #4906 from alfadb/feature/kimi-k3-support
feat: 支持 Kimi K3 与 Kimi Code 模型 ID
2026-07-28 11:23:53 +08:00
Wesley Liddick 1cf6972e73 Merge pull request #4950 from bestony/worktree/rapid-cloud-510e
feat(setup): add explicit setup bypass
2026-07-28 11:08:34 +08:00
Wesley Liddick 20893dc4fd Merge pull request #4945 from Jopqior/fix/gpt56-anthropic-max-effort
fix(openai): preserve GPT-5.6 max effort in messages bridges
2026-07-28 11:08:20 +08:00
Wesley Liddick a12d88ed4b Merge pull request #4957 from wucm667/fix/issue-4948-codex-web-search-manifest
fix(openai): preserve web search for API-key Codex clients
2026-07-28 11:07:16 +08:00
Wesley Liddick 6c04e41952 Merge pull request #4968 from jeshica/fix/claude-oauth-system-cache-breakpoint
fix: 保留 Claude OAuth system 迁移后的缓存断点
2026-07-28 11:07:03 +08:00
Wesley Liddick f71332ff85 Merge pull request #4980 from yan9651688/feat/model-id-copy
feat(accounts): add one-click model ID copy
2026-07-28 11:06:48 +08:00
Wesley Liddick c342a885b5 Merge pull request #4942 from HuntercodeT/fix/openai-passthrough-model-mapping-4936
fix(openai): honor passthrough over non-empty model_mapping in account selection (#4936)
2026-07-28 11:06:33 +08:00
alfadb 1b966dbea1 fix: treat Kimi 1M suffix as client syntax 2026-07-28 10:08:39 +08:00
alfadb 7e65eafbe4 feat: add Kimi K3 support 2026-07-28 10:08:39 +08:00
Wesley Liddick 1aeacf4d41 Merge pull request #4983 from Wei-Shaw/fix/issue-4887-prompt-audit-recovery
fix(security-audit): 解密失败不再吞掉整份配置,修复升级后配置消失且无法保存的死锁
2026-07-28 09:49:40 +08:00
Wesley Liddick d95f6b98ce Merge pull request #4975 from Vibeone/fix/msg-id-format-authentic
fix(gateway): 修复模拟响应 message ID 格式,改为正宗 Anthropic msg_01 格式
2026-07-28 09:49:31 +08:00
shaw bfbe113f5e fix(security-audit): 解密失败不再吞掉整份配置,修复升级后配置消失且无法保存的死锁 (#4887)
根因:prompt audit 是共享 TOTP_ENCRYPTION_KEY 加密器的功能中唯一不校验
EncryptionKeyConfigured 的落点。未配置固定密钥的部署每次重启自动生成新
密钥,v162 保存的节点 Token 密文在升级重启后永久无法解密,Reload 中
ActiveFromStorage 整体失败导致快照永远装不上:管理端 GET 回退默认 v1
(v166 起为 503),而保存路径直读数据库做 CAS 版本对比,必然冲突——
配置既看不见也改不掉。PR #4893 仅改变了报错形态,未修复根因。

修复:
- ActiveFromStorage 对单节点解密失败降级容忍:该节点运行时禁用并标记
  TokenInvalid,配置整体照常激活;管理端恢复显示真实版本号,重新输入
  Token 即可自愈(密文保留,密钥恢复后自动复原)
- blocking 意图下零可用节点时 evaluator 仍返回 unavailable,请求照旧
  被拒,fail-closed 语义不回归;async 意图下 enqueue 直接 drop 并告警
- Save 在未配置固定加密密钥时拒绝保存新 Token(与 TOTP/Ollama/备份
  一致的门控),错误码 prompt_audit_encryption_key_required
- token_status 新增 invalid 状态,前端凭据列与编辑框提示重新输入
- 新增 config_token_invalid 告警日志(集合变化时记录一次,不随 5s
  刷新刷屏)
2026-07-28 09:31:36 +08:00
yan9651688 d8ae153ae9 feat(accounts): make model IDs easy to copy
Administrators often need exact model identifiers while editing account whitelists. Add a dedicated copy action without changing model selection or upstream sync behavior.

Constraint: Keep the contribution frontend-only and avoid model routing or persistence changes
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep copy and selection as separate actions
Tested: focused Vitest, account component regression tests, frontend typecheck, lint, and production build
Not-tested: Authenticated browser screenshot
Related: Wei-Shaw/sub2api#2151
2026-07-28 09:23:52 +08:00
eyre 248236ce6d fix(gateway): 修复模拟响应使用 Bedrock msg_bdrk_ 格式,改为正宗 Anthropic msg_01 格式
问题:
探针拦截(suggestion mode / warmup / max_tokens=1 haiku)的模拟响应以及
Gemini/Antigravity 兼容层生成的 message ID 不符合 Anthropic 官方 API 格式,
容易被客户端识别为非正宗响应。

修复:
1. generateRealisticMsgID():msg_bdrk_ + 24字符 → msg_01 + 22位 Base62
   (与官方 API 返回的 msg_011CdS6b8gAhoKWdW9jE87Zs 格式一致)
2. 去掉固定的 msg_mock_suggestion / msg_mock_warmup,统一使用随机 ID
3. 流式响应格式对齐官方:
   - message_start 增加 stop_details/cache token 字段
   - content_block_start 字段顺序修正
   - message_delta.usage 只含 output_tokens
4. 非流式响应:增加 stop_details:null,移除非标准 total_tokens
5. Gemini Messages/ChatCompletions 兼容层:msg_ + hex → msg_01 + Base62
6. Antigravity response/stream transformer:msg_ + 12位 → msg_01 + 22位 Base62

验证方式:对照 Anthropic 官方 API 实际响应格式确认。
2026-07-27 15:20:03 +00:00
yian 1c26dc7ad8 fix(openai-live): Live 会话 finalize 与 observer 对 store 故障的容错
- finalizeLiveCall 写 usage log 改走 writeUsageLogBestEffort(日志 + 同步
  兜底重试)。MarkLiveCallClosed 已在 Redis 标记 first,这是该会话唯一一次
  落库机会,失败不能再被 `_, _ =` 静默丢弃
- observeLiveCall / waitForLiveObserverRetry 把 store 报错与「控制权被他人
  接管」拆开:store 抖动时有限次重试(liveObserverStoreRetryLimit),仍失败
  则按 record.ExpiresAt 兜底 finalize,保证 usage log 与租约释放不因 Redis
  故障而丢失;记录确实不存在(ErrLiveCallNotFound)才停止重试
- Live 会话 TotalCost/ActualCost 恒 0 的零计费行为保持不变,加 TODO 注明
  需产品决策(免费 or 按时长接入计费管道)
2026-07-27 22:22:46 +08:00
jy.liu 1631b19f84 fix: preserve system cache breakpoint in OAuth mimic 2026-07-27 19:28:45 +08:00
wucm667 3c62b5ca85 fix(openai): preserve web search for API-key Codex clients 2026-07-27 18:42:34 +08:00
Bestony@Homelab a6fc2d10b3 feat(setup): add explicit setup bypass 2026-07-27 17:08:41 +08:00
github-actions[bot] 59ce11c780 chore: sync VERSION to 0.1.166 [skip ci] 2026-07-27 08:57:42 +00:00
shaw dc893dd0b8 chore: update sponsors v0.1.166 2026-07-27 15:49:14 +08:00
Wesley Liddick f18f3143e2 Merge pull request #4946 from Wei-Shaw/feat/panel-api-rate-limit
feat(security): 面板 API 限流保护——防止高频刷接口打爆数据库
2026-07-27 15:44:06 +08:00
shaw fead4c7ec3 feat(security): add panel API rate limiting to protect DB from high-frequency requests
用户可高频刷面板接口(usage/dashboard 等重聚合查询)直接打爆数据库:
现有限流器只覆盖登录/注册等公开认证入口,登录后的全部面板端点无任何限流。

三层防护(阈值均可在后台可视化配置,panel_rate_limit_settings):

1. 认证面板接口按「用户 ID」限流,与来源 IP 无关——反向代理/NAT 共享出口
   (所有请求源地址坍缩为 127.0.0.1 等)不会互相误伤:
   - Global 档(默认 240 rpm/账号):user/auth/payment/admin 全部登录后路由
   - Heavy 档(默认 60 rpm/账号):/usage、/usage/dashboard/*、
     /user/api-keys/:id/usage/daily 等重 SQL 聚合端点叠加计数
   - 管理员默认豁免(可关闭)

2. 无认证公开接口(/api/v1/settings/*,每次请求都查 DB)按安全客户端 IP
   限流(默认 300 rpm/IP);回环/私网/链路本地地址(反代内部转发地址)
   一律跳过计数,杜绝把整条反代链路合并进同一个桶造成大面积误拦截。

3. 修复既有隐患:auth 入口限流的 IP 取值从 c.ClientIP() 切换到与审计日志/
   会话绑定/API Key ACL 同源的安全客户端 IP 解析(尊重后台「信任反代转发
   IP」开关快照)。原实现下默认反代部署(未配置 server.trusted_proxies)
   所有用户共享同一个登录限流桶,既会全员误拦也可被单人恶意占满形成登录
   DoS;开关关闭时行为与原来完全一致。

工程约束:
- 配置热路径走进程内缓存(atomic.Value + singleflight,60s TTL),
  限流中间件零 DB 访问;保存后当前节点立即生效
- 面板限流 Redis 故障 fail-open(auth 入口保持原有 fail-close)
- 429 响应携带 Retry-After;错误码 RATE_LIMITED
- 支付 webhook / 公开支付回调有意不挂限流
- 新增 GET/PUT /api/v1/admin/settings/panel-rate-limit;设置页安全 tab
  新增「面板接口限流」卡片(zh/en i18n 全量)

测试:rate_limiter/panel_rate_limit/setting_panel_rate_limit 单测全绿;
routes、handler/admin、-tags unit 契约测试通过;前端 vue-tsc/ESLint/
SettingsView spec(26/26,含新增交互用例)/i18n 守卫全部通过。
2026-07-27 15:12:51 +08:00
JopqiorandClaude 46dba19397 fix(openai): preserve GPT-5.6 max effort in messages bridges
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-27 14:54:01 +08:00
HuntercodeT 83b368553d fix(openai): honor passthrough over model_mapping in IsModelSupported (#4936)
An OpenAI account with auto-passthrough enabled (extra.openai_passthrough=true,
"replace auth only, allow all models") was still filtered out during account
selection when it had a non-empty credentials.model_mapping that did not list the
requested model. isOpenAICompatibleAccountEligibleForRequest calls
Account.IsModelSupported directly, and IsModelSupported only bypassed the mapping
whitelist for passthrough accounts when the mapping was empty. A leftover mapping
(common after switching an account from whitelist mode to passthrough) therefore
excluded the account -> zero candidates -> ErrNoAvailableAccounts, and the client
saw 404 "Model ... is not supported by any configured account in this group" even
though a direct account test with the same model succeeded (that path already
honored passthrough via isModelSupportedByAccount).

Fix: short-circuit passthrough at the top of Account.IsModelSupported, before the
model_mapping check, so it is consistent with isModelSupportedByAccount. Add a
regression test covering passthrough + non-empty leftover mapping.
2026-07-27 14:20:12 +08:00
Wesley Liddick d96b6a31ff Merge pull request #4908 from chinnsenn/fix/antigravity-openai-compat
fix(antigravity): route OpenAI-compatible requests through native gateway
2026-07-27 13:59:47 +08:00
Wesley Liddick ab73bc0c77 Merge pull request #4924 from Cynicismcart/fix/group-description-wrapping
修复分组描述换行与下拉框溢出
2026-07-27 13:52:44 +08:00
Senn Chinn 3ce8efc125 Merge branch 'Wei-Shaw:main' into fix/antigravity-openai-compat 2026-07-27 13:40:05 +09:00
chinnsenn cc84cd8b4c test(gemini): check function declaration assertions 2026-07-27 13:19:00 +09:00
Wesley Liddick 95590b5530 Merge pull request #4932 from Ricardo-binZzz/codex-responses-compat
Fix Codex (Responses API) <-> Anthropic tool compatibility
2026-07-27 11:47:13 +08:00
Wesley Liddick b765a7f9f6 Merge pull request #4890 from SemonCat/fix/openai-cross-mode-reasoning-failover
fix(openai): strip foreign reasoning on account failover
2026-07-27 11:46:49 +08:00
Wesley Liddick b72d487b85 Merge pull request #4878 from StarryKira/codex/fix-payment-dashboard-currencies
fix(payment): group dashboard stats by currency
2026-07-27 11:46:23 +08:00
Wesley Liddick ad34f89152 Merge pull request #4933 from visa2/fix/usage-model-mapping-statistics
fix(usage): report channel-mapped requests under their real upstream model
2026-07-27 11:45:58 +08:00
Wesley Liddick de6b189a6b Merge pull request #4879 from wey-gu/fix/security-deps-20260726
fix(deps): update image and telemetry packages
2026-07-27 11:45:06 +08:00
Wesley Liddick a74e11c26a Merge pull request #4868 from visa2/fix/settings-partial-update-clobber
fix(settings): keep fields a settings PUT never sent at their stored value
2026-07-27 11:44:40 +08:00
Wesley Liddick 131d42d25d Merge pull request #4839 from visa2/fix/composite-route-prefix-passthrough
fix(composite): pass the requested model through when a prefix route leaves upstream_model empty
2026-07-27 11:44:15 +08:00