Rocket.Chat 8.7.0 发布变更详解:从防钓鱼 MFA 到 FIPS 合规与 REST API 迁移
apps/meteor 是 Rocket.Chat 的核心单体应用,其 CHANGELOG.md 记录了该包从历史版本到 8.7.0 的全部演进。本文以该变更日志为主体,围绕 8.7.0 版本中"安全登录流程重构、FIPS 合规运行、AI 搜索、REST API 取代 DDP 方法、关键竞态缺陷修复"等主线展开,并结合仓库源码与配置进行佐证。读完本文,你将掌握 8.7.0 中每一项新能力的功能要点、对应的开关或配置入口,以及如何利用这份变更日志追溯某次行为变化背后的实现。
一、如何读懂这份 CHANGELOG
apps/meteor/CHANGELOG.md 全文超过 1.8 万行,收录了 300+ 个发布版本,其格式遵循 changesets 自动生成的惯例,文档层级清晰:
- 版本标题按语义化版本(SemVer)组织,例如
## 8.7.0,同时保留预发布版本历史如## 8.7.0-rc.6,便于对照正式版与 RC 版差异; - 每个版本正文分成
### Minor Changes(新功能)与### Patch Changes(缺陷修复)两类条目; - 每条变更前都带 PR 编号标注(如
#40351),便于在代码提交历史中定位到具体改动; - 版本尾部固定出现依赖升级区段(
Updated dependencies [...]),以折叠块<details>列出本次发布连带升级的内部包版本,例如 8.7.0 连带升级了@rocket.chat/core-typings@8.7.0、@rocket.chat/models@2.4.0、@rocket.chat/gazzodown@33.0.0、@rocket.chat/apps-engine@1.65.1等一整套内部依赖; - 部分条目存在"重复的
Bump @rocket.chat/meteor version",这是 monorepo 版本协同发布(release flow)反复触发版本号递增产生的记录,不代表功能变更。
换句话说,这份文件既是给最终用户的功能通告,也是给开发者使用的"某次行为由哪个 PR 引入"的追根溯源索引。下文重点解读当前最新发布线 8.7.0 的功能全貌。
二、安全主线:防钓鱼的多因素认证与新 OAuth 登录流程
8.7.0 变更日志中最具安全价值的改动,是引入了 Phishing-Resistant Multi-Factor Authentication(防钓鱼多因素认证),其核心是把 OAuth 认证整体搬移到服务端执行。
新的 OAuth 流程带来什么
- 登录安全大幅提升:OAuth 认证现在完全在服务端完成,减少了令牌被窃取、遭受钓鱼攻击与客户端拦截凭证的风险;
- 内置 CSRF、state 校验与 PKCE 防护:通过安全的 state 校验与 PKCE(授权码换取令牌时的证明密钥)支持,抵御 CSRF 攻击、请求篡改与授权码被截获;
- OAuth 登录与两步验证打通:即使使用 Google、GitHub、GitLab 等第三方提供商登录,已开启邮箱或 TOTP 两步验证的用户也会被要求完成 2FA,不再绕过二次校验;
- 移动端与桌面端深链登录优化:桌面与移动应用获得了更平滑、更安全的 deep-link OAuth 登录体验。
功能开关位置
该能力默认关闭,需要通过管理后台(或设置覆盖)打开新设置项:
- 设置键:
Accounts_OAuth_Use_Modern_Flow - 默认值:
false(即默认仍走旧 OAuth 流程)
对应实现位于 apps/meteor/server/settings/oauth.ts,其中第 7 行即通过 this.add('Accounts_OAuth_Use_Modern_Flow', false, {...}) 注册该设置,并配置了 i18n 标签 Accounts_OAuth_Use_Modern_Flow_Label 与描述 Accounts_OAuth_Use_Modern_Flow_Description。部署者可在正式启用前先在测试环境开启该开关,验证企业 IdP 与既有 SSO 场景的兼容性后再灰度到生产。
配套的会话管理增强
同样是安全收尾,8.7.0 为 DeviceManagementSession 类型新增了 current 字段,并为 aggregateSessionsByUserId 增加 currentLoginToken 参数,使会话列表接口能够识别并标记调用者当前活跃会话。与之相关的修复是:通过设备管理(Device Management)注销当前设备时,即使注销成功,也不再错误地弹出报错信息(对应 Patch 条目)。
三、合规主线:FIPS 模式与离线(air-gapped)运行
针对政府与军工等受合规约束的部署场景,8.7.0 引入两项重要能力。
支持 FIPS 140 合规加密
- 单体(monolith)以及全部微服务(ddp-streamer、account-service、authorization-service、presence-service、queue-worker、omnichannel-transcript)现在都能通过 Node.js/OpenSSL FIPS 强制使用 FIPS 合规密码学;
- 官方提供专门的 FIPS Docker 镜像,本仓库根目录的 docker-compose-ci.fips.yml 即对应 CI 用途的 FIPS 编排文件;
- 运行 FIPS 模式需要包含新增
fips模块的许可证; - FIPS 状态会体现在服务器日志与统计(statistics)数据中,便于运维确认运行模式。
仓库目录 ee/apps 下的 account-service、authorization-service、ddp-streamer、omnichannel-transcript、presence-service、queue-worker 正是变更日志点名的各个微服务包,FIPS 能力需要这些组件协同启用。
offline 许可证标志:从源头切断外联
新增 offline 许可证标志后,工作区会在源头抑制一切指向 Rocket.Chat Cloud 服务与 Push Gateway 的出站连接,确保隔离网络(air-gapped)环境不会发起任何可能违反其安全合规要求的调用。仓库中的 offline-license-capability-enforcement 提案对该能力的实现思路做了记录。与之相关的体验修复是:设置了 OVERWRITE_SETTING_Show_Setup_Wizard=completed 的隔离工作区,在升级后首次启动时不再被强制退回注册引导步骤。
许可证管理入口升级
- 新增 REST 端点
licenses.validate:在不实际应用许可证的前提下,用当前工作区校验一份 Rocket.Chat 许可证(V2 或 V3 JWT)。有效许可证返回成功;无效许可证则返回导致其被拒绝的校验行为项,方便在 UI 应用前先做预览。 - 订阅管理页(subscription admin page)新增许可证管理流程:支持应用前校验、以及移除已存在许可证。需要注意:从本版本起,许可证管理应迁移到订阅页面进行,而不再使用 Enterprise 设置页。
- 修复了通过环境变量
ROCKETCHAT_LICENSE注入的许可证比工作区内已持久化许可证更新时未被应用的问题。
四、智能化主线:AI 搜索与可选 OpenAI 兼容回答
变更日志明确 8.7.0 引入 AI Search,包含三部分:
- 语义化消息搜索结果:基于消息语义而非纯关键词的检索能力;
- 可选的 OpenAI 兼容回答:在搜索结果基础上可选择接入兼容 OpenAI 接口的大模型生成回答;
- AI Center 配置:提供集中式的 AI 功能配置入口。
仓库中的 packages/ai-search 包即为该能力的实现载体,其 src 下包含 intelligentSearch.ts(智能检索)、clientSearch.ts(客户端检索)、llm.ts(大模型接入抽象)与配套的类型定义与单测(*.spec.ts),可据此了解语义搜索与 LLM 回答的模块边界。
五、平台能力主线:Apps 引擎的替代运行时与原生 emoji
Apps 新增 Node 运行时后端
Apps(应用)引擎新增了替代运行时后端,可通过环境变量启用:
APPS_ENGINE_RUNTIME_BACKEND='node'
默认情况下 Apps 跑在 Deno 运行时上(本仓库 packages/apps 下 deno-runtime 目录即是默认运行时);设置该环境变量后将改用 Node.js 运行时执行应用。仓库内 packages/apps/node-runtime/src 即对应新的 Node 运行时实现。对于无法使用 Deno、或已有 Node 生态诉求的私有部署,这是一个关键的兼容性选项。
原生(Unicode)emoji 取代私有 emoji
8.7.0 将私有 emoji 替换为原生(unicode)emoji,并扩大了可用 emoji 集合。配套修复还包括 emoji 选择器按钮点击异常——该问题源于一次多余的状态更新引发无限渲染循环,修复方式是移除触发循环的状态更新,并把同一 mouseover 事件的多次触发改为应使用 mouseenter 事件的时机。
桌面端与客户端体验
- 持久化音频播放器:播放音频附件后切换甚至关闭会话,音频都不会中断;侧边栏顶部会出现 "Now playing" 卡片,支持播放/暂停、进度拖动、倍速(1x/1.5x/2x)以及跳回原会话的快捷入口。另修复了音频附件无法通过进度滑块 seek 的问题;
- 桌面应用角色信息同步:desktop API 新增
setUserRolesbridge 方法,把已登录用户的角色推送给桌面端,使桌面客户端可将supportedVersions消息(如版本过期警告)仅展示给 admin 等特定角色;推送对角色变化保持响应式,旧版桌面端则回退到自身角色查询; - 键盘可访问性:Display 菜单的单选框与复选框支持键盘激活,房间成员列表支持键盘导航;
- 快速状态菜单:恢复 "Away"(离开)作为快速状态菜单、自定义状态弹窗与账户资料页的可选预设;
- 搜索细节:按用户名搜索房间时不再出现自身账户重复显示两次的问题;
/v1/spotlight搜索性能提升,房间搜索在可用时会从数据库从副本读取,降低主库压力。
六、API 演进主线:DDP 方法逐步迁移到 REST
8.7.0 完成了一批传统 DDP(Meteor 分布式数据协议)方法向 REST 端点的迁移。被取代的 DDP 方法仍保留注册并打印指向新端点的弃用日志,直到 9.0.0 版本移除。这一迁移值得关注,因为它意味着自动化脚本与外部集成可以直接改用纯 HTTP 调用:
| 被弃用的 DDP 方法 | 替代 REST 端点 | 请求体 | 说明 |
|---|---|---|---|
logoutCleanUp |
POST /v1/users.logout |
— | 登出副作用(afterLogoutCleanUpCallback 与 Apps.IPostUserLoggedOut)改为服务端运行,无需客户端往返 |
cloud:connectWorkspace |
POST /v1/cloud.connectWorkspace |
{ token } |
需 manage-cloud 权限 |
clearIntegrationHistory |
POST /v1/integrations.clearHistory |
{ integrationId } |
权限沿用 DDP 时代 |
replayOutgoingIntegration |
POST /v1/integrations.replayOutgoing |
{ integrationId, historyId } |
同上 |
authorization:addPermissionToRole |
POST /v1/permissions.addRole |
{ permissionId, role } |
复用 access-permissions、access-setting-permissions 校验 |
authorization:removeRoleFromPermission |
POST /v1/permissions.removeRole |
{ permissionId, role } |
同上 |
setAvatarFromService |
POST /v1/users.setAvatar |
multipart 增加可选 service 字段 |
值会存入用户的 avatarOrigin |
verifyEmail + afterVerifyEmail |
POST /v1/users.verifyEmail |
{ token } |
单请求内完成标记邮箱已验证并执行匿名→普通用户角色切换 |
对应端点定义位于 apps/meteor/server/api/v1(如 users.ts、cloud.ts、integrations.ts、permissions.ts),需要扩展 REST API 的读者可从此目录查找各资源端点的注册代码。
七、数据一致性专项:Patch 修复中的关键缺陷
8.7.0 的 Patch 变更中有相当一部分属于"check-then-write 竞态"与"时间/时区数据"类缺陷,理解它们能帮助你判断升级后哪些故障会自动消失:
竞态条件改为原子操作
多处先检查后写入的数据库流程被合并为单次原子操作,具体包括:CAS 登录令牌不可能再被两个并发登录同时消费;撤销房间邀请不再产生重复的移除通知;删除 integration 时,创建者权限范围校验内置于删除动作本身。修复思路是把"读→判断→写"三步收敛为一次原子写。
E2E 加密房间密钥竞态
此前在开启加密的房间中,若多名成员同时打开房间,每个客户端可能各自生成并分发不同的群组密钥,导致消息永久无法解密("incorrect encryption key")。现在服务端以 first-write-wins 的方式原子化确立房间密钥;在竞争中失败的客户端会丢弃本地生成的密钥、改采用已确立的密钥,而不是用不一致的密钥继续加密。
多营业时间(Business Hours)与部门关联丢失
- 夏令时切换或服务重启后,多营业时间会丢失其关联部门——自动时区调整在重新保存营业时间时没有带上部门关联,导致配置了时区的营业时间静默失效;
- 部门从营业时间中移除后,该部门代理人的营业时间可用性没有被清除,使其继续按已失效的营业时间保持可用/不可用;
- 当启用了多营业时间、代理被移出与营业时间关联的部门时,可用性重算步骤此前总会失败,且在
EXIT_UNHANDLEDPROMISEREJECTION或开发/测试模式下会因未处理的 Promise 拒绝使服务进程崩溃。
LDAP 相关
- LDAP 频道同步时,若某个映射频道无法解析,此前会中断整个添加/移除流程,导致开启 "Auto Remove Users from Channels" 时用户无法被移出频道,现已修复;
- LDAP 同步合并通过邮箱匹配的已有用户时,若目录中的用户名与库内不同会报
Username already exists,现已能正常合并; - LDAP 登录/同步期间,若搜索设置产生非法 LDAP filter(如空的 User Search Field),服务端会优雅失败并记录错误日志,不再终止进程。
Slack 导入器
修复了 Slack 导入器把共享文件以原始 URL 写进消息正文的问题。现在导入的文件消息会保持隐藏状态,直到用户点击 "Download Pending Files" 按钮真正抓取成功后才以带图片预览的原生附件形式展示;失败的下载(如导出链接已失效)不再被静默存为文件内容,而是计为错误并可重试。
密码策略与推送设置
- 服务端现在会拒绝保存"最大长度小于最小长度"的密码策略配置——这种配置此前会让用户无法设置任何合法密码;保存时会报错并解释约束;
- 重新启用 "Enable Push" 设置时不再崩溃:推送通知会在重新启用时被完整重配置,连禁用期间修改过的相关设置也会一并生效。
其他值得注意的修复
- 时区为负 UTC 偏移的用户不再看到日期提前一天显示;
- Omnichannel 会话中"user left"系统消息不再在转接流程结束后才追加,避免其在会话历史中乱序出现;
- 把频道转换为团队、或从已有房间创建团队时,无论以何种方式标识房间,权限检查现在都会一致执行;
- SAML Single Logout 响应中的
RelayState现与登出请求收到的值完全一致(符合 SAML 规范),而非使用 Rocket.Chat 自身 URL; - 公共频道预览期间,消息输入框中的更多操作被禁用;
- 文章开头提到的一个安全热修复(Security Hotfix)包含在 Patch 中,涉事部署建议按 Rocket.Chat 官方安全公告流程跟进升级。
八、工程化细节与升级建议
从变更日志的依赖升级区段可以看出,8.7.0 是一次跨仓库联动的整体发布:@rocket.chat/core-typings、@rocket.chat/rest-typings、@rocket.chat/model-typings、@rocket.chat/models 等核心类型/数据层包,以及 @rocket.chat/apps-engine、@rocket.chat/license、@rocket.chat/gazzodown、@rocket.chat/web-ui-registration 等依赖包均同步升版。升级时建议:
- 对安全敏感的部署:优先验证新 OAuth 流程开关
Accounts_OAuth_Use_Modern_Flow与企业登录链路(SSO、2FA)的兼容性,并在小范围试点; - 对合规有要求的部署:确认许可证是否包含
fips模块,并使用官方 FIPS Docker 镜像编排(可参考仓库根目录 docker-compose-ci.fips.yml); - 隔离网络部署:确认许可证是否带
offline标志,以彻底抑制出站连接;涉及OVERWRITE_SETTING_Show_Setup_Wizard的实例会从强制回退注册步骤的缺陷中恢复; - 有大量自动化的团队:留意第 6 节中 8 个 DDP 方法迁移为 REST 端点的清单,旧 DDP 方法保留到 9.0.0,应尽早把脚本切换到新的 HTTP 端点;
- 集成测试/回归关注点:本版修复了大量竞态与数据一致性问题(E2E 房间密钥、营业时间、LDAP、Slack 导入),升级后建议对加密房间并发进入、多营业时间与部门变更、LDAP 频道同步等场景做针对性回归。
总而言之,8.7.0 是一次同时覆盖**安全纵深(防钓鱼 OAuth + 2FA 打通)、合规运行(FIPS/offline)、智能化(AI 搜索)与 API 现代化(DDP→REST)**的重要发布,而 apps/meteor/CHANGELOG.md 正是理解这些变化来龙去脉的第一手索引。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00