v0.0.8
·
1221 commits
to master
since this release
v0.0.8 — 安全加固与登录页改版
修复 3 个可导致提权 / 凭据泄露的安全问题(指定渠道越权、用户列表暴露 access_token),并全面改版登录注册页:新增《服务条款》《隐私政策》页面、注册需同意条款、补充无障碍支持;同时把 README 国际化扩展至 8 种语言,并加入"启动时校验内嵌主题"的防御性检查,避免升级后因数据库残留旧主题字段导致后台空白页。
中文
🔒 安全
- 修复指定渠道越权漏洞(one-api#2410):此前任意已登录用户均可通过
/v1/oneapi/proxy/:channelid/*target指定任意上游渠道,绕过分组隔离与模型白名单并触发上游凭据转发。现在该 URL 参数路径与 token 后缀路径一样,仅管理员可用。 - 指定渠道时重新校验分组 / 模型白名单(one-api#2410):即使管理员使用指定渠道功能,转发前也会再次确认该渠道确实服务于当前用户分组与所请求模型,作为纵深防御。
- 修复用户列表接口泄露 access_token(one-api#2425):管理员批量用户接口(
GET /api/user/、GET /api/user/search)不再返回用户的 access_token,避免被重放后提权为 root(现有单用户读取路径的保护保持一致)。 - 为上述修复补充模型层辅助方法
Channel.ContainsGroup/Channel.ContainsModel及相应回归测试。
✨ 新增功能
- 登录 / 注册 / 找回密码 / 重置密码四个鉴权页全面改版:抽出新的
AuthLayout(带装饰性渐变光晕背景与品牌位 Logo),统一语义化标题(h1+ 副标题)与表单无障碍aria-label;forgot-link/form-alert等局部样式整理后视觉与交互更一致。 - 新增 《服务条款》页面(
/terms) 与 《隐私政策》页面(/privacy),使用新的LegalLayout(顶部导航 + 法律文件版式)排版;路由免登录即可访问,并已在router/index.js的白名单中放行,避免跳转登录页。 - 注册流程新增「我同意《服务条款》和《隐私政策》」勾选(带
aria-label),未勾选不可提交注册,并在条款文案上提供/terms、/privacy直达链接。 - 套餐页新增空状态:未配置任何套餐时展示友好的插画 + 提示文案("暂无可用套餐 / 请联系管理员配置套餐后再来查看"),替代空白网格。
- 新增
Channel.ContainsGroup/Channel.ContainsModel白名单辅助方法(按,拆分、精确匹配,空配置视为全部放行),为下游的鉴权与重校验逻辑提供复用基础。 - 启动时校验前端主题:新增
common.ValidateEmbeddedTheme(buildFS, themesRoot, theme)与common.ListEmbeddedThemes(buildFS, themesRoot)辅助函数;main.go在using theme <name>日志之后调用校验器,如果当前主题未被打入二进制,会输出[ERROR]日志并指出web/build/<theme>/index.html缺失、列出实际已内嵌的全部主题,并给出三种修复建议(修改options.theme/ 调整THEME环境变量 / 重新打包时把期望主题加入web/THEMES)。该检查非致命,服务器仍会启动以便运维修复,但能立刻把"后台空白"问题暴露在日志里。
🐛 问题修复
- 修复订单页多了一层
page-container内边距导致与其它页面边距不一致的问题。 - 修复普通用户可绕过分组隔离 / 模型白名单指定上游渠道的安全问题(详见「安全」)。
- 修复管理员用户列表 / 搜索接口可能暴露 access_token 的安全问题(详见「安全」)。
router/web.go不再静默吞掉web/build/<theme>/index.html读取失败的错误,改为通过logger.SysError打印明确错误("theme %q is not embedded ...")作为兜底,确保即使绕过启动检查也能在路由层看到失败原因。
📚 文档
- README 国际化扩展至 8 种语言:新增德语、阿拉伯语、韩语、俄语、日语、繁体中文 README,主 README 与英文 README 的语言导航同步更新。
🔧 工程 / CI
- 补充三组回归测试:中间件指定渠道鉴权(
middleware/auth_test.go)、用户列表access_token脱敏(controller/user_test.go)、模型白名单辅助方法(model/channel_contains_test.go)。 - 为内嵌主题校验辅助函数补充 5 个单元测试(
common/embed_theme_test.go,含embed_theme_testdata/测试资源),覆盖:列出主题、主题存在、主题缺失、空主题、根路径带尾斜杠容错。
⚠️ 升级注意事项
- 本次为代码与前端改动,无数据库迁移,可直接升级。
- 登录 / 注册 / 找回密码页面已改版,建议升级后清除浏览器缓存或以无痕模式验证。
- 若你在开放注册场景下依赖「匿名指定渠道代理」能力,请注意该能力现已被移除:仅管理员可通过 URL 参数或 token 后缀指定渠道。
- 数据库残留的旧
options.theme会被新校验器捕获:如果你从较早版本(例如内置default主题的旧 one-api / one-api-pro)升级,启动日志中若出现theme "default" is not embedded in this binary ...的[ERROR],说明 MySQLoptions表里仍保留着旧的theme=default记录。请执行UPDATE options SET value='default-pro' WHERE \key`='theme';`(或直接删除该行)后重启即可。
English
🔒 Security
- Fixed privilege escalation via URL-parameter channel pinning (one-api#2410): any authenticated user could previously call
/v1/oneapi/proxy/:channelid/*targetto pin an arbitrary upstream channel, bypassing group isolation and per-channel model allowlists while triggering upstream-credential forwarding. The URL-parameter path now requires an admin, matching the token-suffix path. - Re-validate group / model allowlist on pinned channels (one-api#2410): even when an admin pins a channel, the distributor now re-checks that the channel actually serves the caller's user group and requested model before forwarding — defense in depth.
- Stopped leaking
access_tokenin admin user APIs (one-api#2425): the admin batch endpoints (GET /api/user/,GET /api/user/search) no longer return users' access_tokens, preventing token replay that could escalate to root (consistent with the existing single-user read path). - Added
Channel.ContainsGroup/Channel.ContainsModelmodel helpers and regression tests covering all of the above.
✨ New Features
- Reworked all four auth pages — Login, Register, Password Reset, and Password Reset Confirm — around a new
AuthLayout(decorative gradient-orb background + branded logo slot), unified semantic headings (h1+ subtitle) and formaria-labels; tidied upforgot-link/form-alertstyles so all four pages look and behave consistently. - Added Terms of Service (
/terms) and Privacy Policy (/privacy) pages rendered via a newLegalLayout(top nav + legal document layout). Both routes are whitelisted in the router so visitors can reach them without first logging in. - Registration now requires checking "I agree to the Terms of Service and Privacy Policy" (with
aria-label) before submitting, and the copy includes direct/terms//privacylinks. - Added an empty state to the Plans page so users see a friendly illustration + hint ("暂无可用套餐 / 请联系管理员配置套餐后再来查看") instead of a blank grid when no plans are configured.
- Added
Channel.ContainsGroup/Channel.ContainsModelallowlist helpers (comma-split, exact match; empty config allows all), providing the reusable building block for downstream auth and re-validation logic. - Embedded-theme check at startup: added
common.ValidateEmbeddedTheme(buildFS, themesRoot, theme)andcommon.ListEmbeddedThemes(buildFS, themesRoot)helpers.main.goinvokes the validator right after loggingusing theme <name>; if the configured theme is not embedded in the binary, it emits a loud[ERROR]that names the missingweb/build/<theme>/index.html, lists every theme that IS embedded, and points at three fixes (updateoptions.theme/ adjust theTHEMEenv / add the theme toweb/THEMESand rebuild). The check is non-fatal — the server still starts so the operator can fix the misconfiguration — but it puts the "blank admin page" failure mode straight into the log.
🐛 Bug Fixes
- Removed an extra
page-containerpadding in the Orders page so its margins match the other pages. - Fixed the security issue where ordinary users could bypass group isolation / model allowlists by pinning an upstream channel (see Security).
- Fixed the security issue where admin user list / search responses could expose
access_token(see Security). router/web.gono longer silently swallows the error from readingweb/build/<theme>/index.html; it now logstheme %q is not embedded ...vialogger.SysErroras a safety net, so the failure is still visible even ifSetWebRouteris ever reached before the startup check (tests, future refactors).
📚 Documentation
- README i18n now covers 8 languages: added German, Arabic, Korean, Russian, Japanese and Traditional Chinese READMEs, and updated the language navigation in both the main and English READMEs.
🔧 Tooling / CI
- Added three groups of regression tests: middleware channel-pinning auth (
middleware/auth_test.go), user-listaccess_tokenredaction (controller/user_test.go), and model allowlist helpers (model/channel_contains_test.go). - Added 5 unit tests for the embedded-theme validator (
common/embed_theme_test.go, with synthetic fixtures incommon/embed_theme_testdata/): list themes, theme present, theme missing, empty theme, and trailing-slash tolerance on the themes root.
⚠️ Upgrade Notes
- Code/frontend-only release — no database migration; safe to upgrade in place.
- Login / register / password-reset pages have been redesigned; please clear the browser cache or verify in an incognito window after upgrading.
- If you relied on anonymous "pin channel by URL parameter" proxying in open-registration deployments, note that this is no longer allowed: only admins can pin a channel (via URL parameter or token suffix).
- Stale
options.themefrom older releases will now be caught: when upgrading from an older one-api / one-api-pro that shipped the legacydefaulttheme, you may see[ERROR] theme "default" is not embedded in this binary ...at startup — that means the MySQLoptionstable still holds the oldtheme=defaultrow, which overrides the env default. RunUPDATE options SET value='default-pro' WHERE \key`='theme';` (or delete the row) and restart.