☰
Rocket.Chat 许可证引擎(@rocket.chat/license)深度解析:V2/V3 校验、licenses API 与离线授权
2026/10/20 0:10:14 网站建设 项目流程

Rocket.Chat 许可证引擎(@rocket.chat/license)深度解析:V2/V3 校验、licenses API 与离线授权

【免费下载链接】Rocket.ChatThe Secure CommsOS™ for mission-critical operations项目地址: https://gitcode.com/GitHub_Trending/ro/Rocket.Chat

本指南以 Rocket.Chat 仓库中@rocket.chat/license包的 CHANGELOG.md 为主干,结合其在ee/packages/license/src及服务端 REST API 中的源码实现,系统讲解 Rocket.Chat 企业许可证(License)的工作机制:V2/V3 两种 JWT 许可格式与运行时兼容、licenses.*端点族的验证与预览能力、offline标志对隔离网络(air-gapped)工作区的保护,以及ROCKETCHAT_LICENSE环境变量的应用优先级。读完你将能理解一次许可证从注入、校验到影响运行时的完整调用链,并知道应查看哪些源码与测试来进一步深入。

一、包定位:@rocket.chat/license在仓库中的角色

@rocket.chat/license是 Rocket.Chat 在 monorepoee/packages/下的私有工具包,当前版本 1.2.0(与 CHANGELOG 顶部一致),其 package.json 中定义了对@rocket.chat/core-typings(类型定义)、@rocket.chat/jwt(JWT 解析)、@rocket.chat/logger(日志)以及bcrypt(加密校验)的依赖,并提供build/test/typecheck等标准脚本。

从 src 目录 的源码结构可以清晰看出这个包的核心职责:

文件/目录职责
license.ts/licenseImp.ts许可证管理器主体:加载、解析、校验、应用与状态上报
applyLicense.ts将许可证写入工作区(持久化到Enterprise_License设置)
v2/convertToV3.ts将 V2 许可证在运行时转换为 V3 格式
validation/校验逻辑(模块、用户数限制、过期时间等)
AirGappedRestriction.ts无许可证隔离环境的限制逻辑
MockedLicenseBuilder.ts测试用许可证构造器
多个*.spec.ts与校验、模块、限制相关的单元测试

也就是说,CHANGELOG 并不是一份流水账——它记录的是这个"许可证引擎"从诞生到如今的真实功能演进。下面我们把其中带 PR 编号的功能条目逐一拆解,并结合源码验证。

二、License 的两种形态:V2 与 V3,以及运行时"以 V3 为准"

在 0.1.0 版本条目中,CHANGELOG 明确记载了本包引入时的核心设计:

Implemented the License library, it is used to handle the functionality like expiration date, modules, limits, etc. Also added a version v3 of the license, which contains an extended list of features. v2 is still supported, since we convert it to v3 on the fly.

这段描述确立了整个 license 引擎的基石:

  • 许可证是 JWT 承载的结构化数据,通过@rocket.chat/jwt解析与验签;
  • V3 是"信息更全"的新格式,扩展了特性(modules/limits 等)清单;
  • V2 不会立刻被废弃——任何 V2 许可证在加载后会被即时转换为 V3,后续逻辑统一以 V3 结构处理。

源码印证这一设计的关键点有三处:

  1. 在 license.ts 中,convertToV3从./v2/convertToV3导入,作为设置许可证的必经步骤之一(第 274 行setLicenseV3(convertToV3(newLicense), ...));
  2. 在预览校验路径中(第 365 行),逻辑为encryptedLicense.startsWith('RCV3_') ? decrypted : convertToV3(decrypted)——即根据密文前缀RCV3_判断是否已是 V3,否则走转换;
  3. 转换函数的实现位于 ee/packages/license/src/v2/convertToV3.ts,它把ILicenseV2映射为ILicenseV3,并补齐 V3 所需字段,例如将offline置为false(第 18 行)。

可以推断,RCV3_前缀不仅是版本标识,也是加密方式切换的标记:V2/V3 许可证分别使用不同的加解密与验签流程,包内v2/子目录与token.ts等文件正承担这些差异处理。这种"入口处统一升级为最新结构"的模式,让上层消费方永远只需面对 V3 一种数据形态,显著降低后续功能分支维护成本。

三、许可证如何进入工作区:应用链路与ROCKETCHAT_LICENSE

许可证进入 Rocket.Chat 工作区有两条典型途径:通过管理界面(把字符串写入Enterprise_License系统设置),以及通过ROCKETCHAT_LICENSE环境变量在启动时注入。后者对容器化/自动化部署尤为重要。

服务端的接入点位于 apps/meteor/ee/server/lib/license/startup.ts:

await applyNewestLicense( License, settings.get<string>('Enterprise_License') ?? '', process.env.ROCKETCHAT_LICENSE ?? '', );

这里依次读取两个来源:已持久化在系统设置Enterprise_License中的旧许可与process.env.ROCKETCHAT_LICENSE提供的新许可,再调用applyNewestLicense决定最终生效者。

1.2.0 的 Patch 条目(对应 PR #41472)修复的正是这条链路上的一个问题:

Fixes the license provided via theROCKETCHAT_LICENSEenvironment variable not being applied when it is newer than the one persisted in the workspace.

即:此前当环境变量携带的许可证版本"更新"(签发时间更晚)于已持久化的许可证时,环境变量版可能不会被正确采用。从applyNewestLicense的命名与传参顺序可以推断,它的职责是比较两者并选择较新者应用——该修复确保"较新的许可始终生效"这一语义在环境变量场景下也成立。这意味着在升级/续期场景中,运维只需在启动参数里覆盖ROCKETCHAT_LICENSE即可让新许可即时接管,而无需进入管理界面手工更新。

另一个佐证位于 enforceFipsLicense.ts:当 FIPS 环境需要许可证时,错误信息会直接引导用户 "Provide your license through theROCKETCHAT_LICENSEenvironment variable",进一步说明环境变量是官方推荐的注入通道之一。

四、licenses.*REST 端点族:查询、添加与预览校验

许可证的 HTTP 接口集中在服务端文件 apps/meteor/ee/server/api/licenses.ts。结合 CHANGELOG,端点是一步步长出来的:0.1.0 引入licenses.info,1.2.0 新增licenses.validate。目前共有四个端点:

4.1GET /api/v1/licenses.info——查询当前许可状态

  • 需要认证(authRequired: true);
  • 无limits/license详情除非调用者拥有view-privileged-setting权限;
  • 支持查询参数loadValues:仅在拥有特权时生效,用于加载当前值(如当前活跃用户数等运行时数据),见 licenses.ts;
  • 响应含license对象;若调用者还有manage-cloud权限,会附带cloudSyncAnnouncement(来自系统设置Cloud_Sync_Announcement_Payload),见第 92-104 行。

4.2POST /api/v1/licenses.add——应用新许可

  • 需要edit-privileged-setting权限;
  • 请求体为{ "license": "<许可证字符串>" };
  • 先经License.validateFormat(license)校验格式(第 123 行),失败返回Invalid license;
  • 成功后把许可证写入系统设置Enterprise_License,并通过notifyOnSettingChangedById('Enterprise_License')广播变更(第 134-135 行),触发运行中的工作区热更新。

4.3POST /api/v1/licenses.validate——预览校验而不落库(1.2.0 新增)

这是 1.2.0 版本的核心功能条目(PR #40916):

Adds a newlicenses.validateREST endpoint that validates a Rocket.Chat license (V2 or V3 JWT) against the current workspace without applying it, so a license can be previewed before it is applied from the UI. A valid license responds with success; an invalid one responds with the validation behaviors that rejected it.

实现要点(licenses.ts):

  • 同样要求edit-privileged-setting权限与{ "license": "<字符串>" }请求体;
  • 服务端调用License.validateLicenseForPreview(license);
  • 校验失败返回{ success: false, error: 'license-invalid', reasons: [...] },其中reasons数组携带所有拒绝该校验的行为明细(例如哪些模块或限制无法满足);
  • 校验成功则只返回{ success: true },不会写入Enterprise_License。

该端点对应的底层实现在 ee/packages/license/src/license.ts,核心逻辑(第 365 行)同样是"非RCV3_前缀则先convertToV3"再校验,与正式应用路径保持一致——这正是它能在 UI 上"先试后买"地预览新许可而不影响当前工作区的根基。配套的单元测试位于 validateLicenseForPreview.spec.ts,其中覆盖了:非许可证字符串被拒、管理器未就绪时抛NotReadyForValidation、以及经MockedLicenseBuilder构造的合法/非法许可的成败路径。

4.4GET /api/v1/licenses.maxActiveUsers——最大活跃用户数

  • 读取License.getMaxActiveUsers()与Users.getActiveLocalUserCount();
  • 返回{ maxActiveUsers: number | null, activeUsers: number },当许可证未定义上限时maxActiveUsers为null。

四个端点对应的请求/响应类型校验均由@rocket.chat/rest-typings包提供(如isLicensesInfoProps、isLicensesAddProps、isLicensesValidateProps等),并使用 AJV 编译的响应 schema(见 licenses.ts),保证端点的入参与出参在类型层与运行时双重受控。

五、offline标志与隔离网络(air-gapped)工作区

5.1offline标志:从源头掐断出站连接(1.2.0,PR #41148)

1.2.0 的另一个 Minor 条目描述了离线标志的语义:

Adds support for theofflinelicense flag, suppressing every outbound connection to Rocket.Chat Cloud services and the Push Gateway at its source, so air-gapped workspaces never initiate calls that would violate their security compliance.

这是面向安全合规的设计:当许可证携带offline: true时,工作区不应该发起任何指向 Rocket.Chat Cloud 服务或推送网关(Push Gateway)的出站调用,且抑制动作发生在"源头"而非请求发出后拦截——对必须满足物理/逻辑隔离(air-gapped)合规的组织,这一点至关重要。

源码中的证据链条非常完整:

  • 状态判断入口 license.ts:return this.getLicense()?.information.offline ?? false;,即无许可时默认不视为 offline 场景之外的一个独立布尔;
  • 消费方确实是"源头级"抑制,例如:
    • fetchMarketplaceApps.ts 注释明确:offline 许可在发出任何请求之前即拒绝;
    • fetchMarketplaceCategories.ts 同样在请求前拒绝;
    • apps/communication/rest.ts 注明 offline 许可在源头抑制 marketplace 请求;
  • 测试覆盖:见 license.spec.ts,包含"无许可时不视为 offline""标准许可不视为 offline""带 offline 标志时上报为 offline""移除许可后停止上报 offline"四个用例;
  • 测试构造器 MockedLicenseBuilder.ts 提供withOffline(offline = true)链式方法(第 180-182 行),方便在单测中造出带离线标志的许可。

5.2 无许可证的 air-gapped 限制(1.0.0,PR #33241)

1.0.0 的 Major 条目记录了"对无许可证的 air-gapped 环境施加限制"(Adds restrictions to air-gapped environments without a license)。与之对应,服务端存在 apps/meteor/ee/server/lib/license/airGappedRestrictions.ts,它会维护系统设置Cloud_Workspace_AirGapped_Restrictions_Remaining_Days(隔离环境剩余可用天数)并在变化时通过notifyOnSettingChangedById通知前端;包内的 AirGappedRestriction.ts 与其 spec 则承载核心判定逻辑。结合上文ROCKETCHAT_LICENSE的引导文案可以推断:隔离网络下若没有合法许可,工作区会进入受限模式并提示通过环境变量注入许可,从而解锁完整能力。

六、围绕许可的测试基座

@rocket.chat/license是"策略敏感"的包,因此自带较完备的测试资产,可作为二次开发与故障排查的入口:

  • license.spec.ts:加载、offline 标志上报、模块行为等主流程;
  • validateLicenseForPreview.spec.ts:licenses.validate所依赖的预览校验逻辑;
  • getLicenseLimit.spec.ts:用户数等 limits 的读取;
  • modules.spec.ts 与 AirGappedRestriction.spec.ts:模块启用与隔离限制;
  • MockedLicenseBuilder.ts:在测试中快速构造 V2/V3 许可并签名。

配合 license.ts 中约第 274、353、457 行的三个关键锚点(应用、预览校验、offline 读取),足以追完一条许可证"注入 → 版本归一化 → 校验 → 影响运行时行为"的完整链路。

七、版本演进小结(对照 CHANGELOG)

版本类型关键内容
0.1.0Minor引入 License 库(过期时间/模块/limits 处理);新增 V3 许可格式;V2 运行时即时转换;新增licenses.info端点
1.0.0Major对无许可的 air-gapped 环境施加限制;支持读取许可证中的 add-ons
1.1.xPatch修复企业许可生效时仍误弹 premium 弹窗等问题
1.2.0Minor新增licenses.validate预览校验端点;支持offline标志,从源头抑制出站请求
1.2.0Patch修复ROCKETCHAT_LICENSE环境变量在"比已持久化许可更新"时未被应用的问题

说明:CHANGELOG 中其余大量Updated dependencies [...]记录是由 Changesets 自动生成的依赖升级流水账(本包主要依赖@rocket.chat/core-typings的对应版本),其意义是追踪包间版本同步关系,并不代表本包自身行为变化,阅读时可将它们视为版本指纹而非功能说明。

八、进一步阅读

  • 许可证核心逻辑:ee/packages/license/src/license.ts、licenseImp.ts
  • V2→V3 转换:ee/packages/license/src/v2/convertToV3.ts
  • 服务端许可证 API:apps/meteor/ee/server/api/licenses.ts
  • 启动注入与优先级:apps/meteor/ee/server/lib/license/startup.ts
  • 隔离网络限制:AirGappedRestriction.ts、airGappedRestrictions.ts
  • 测试与构造器:license.spec.ts、validateLicenseForPreview.spec.ts、MockedLicenseBuilder.ts

【免费下载链接】Rocket.ChatThe Secure CommsOS™ for mission-critical operations项目地址: https://gitcode.com/GitHub_Trending/ro/Rocket.Chat

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询