diff --git a/locales/zh-Hans/_index.md b/locales/zh-Hans/_index.md new file mode 100644 index 00000000..bc1648c6 --- /dev/null +++ b/locales/zh-Hans/_index.md @@ -0,0 +1,302 @@ +--- +title: "Matrix 规范" +type: docs +weight: 10 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +Matrix 定义了一套用于去中心化通信的开放 API,适用于在全球开放联盟服务器网络中安全地发布、持久保存和订阅数据,无单点控制。其用途包括即时消息(IM)、VoIP(语音通信)信令、物联网(IoT)通信,以及打通各类现有通信孤岛——为构建新一代开放实时通信生态系统提供基础。 + +如需对 Matrix 规范提出更改建议,请参见 [Matrix 规范更改提案说明](/proposals)。 + +## Matrix API + +规范由以下部分组成: + +* [客户端-服务器 API](/client-server-api) +* [服务器-服务器 API](/server-server-api) +* [应用服务 API](/application-service-api) +* [身份服务 API](/identity-service-api) +* [推送网关 API](/push-gateway-api) +* [房间版本](/rooms) +* [附录](/appendices) + +此外,本介绍页面还包含了理解具体 API 所需的关键基础信息,包括 [总体架构](#architecture) 一节。 + +[Matrix API 浏览器](https://matrix.org/docs/api/) 便于浏览客户端-服务器 API。 + +## Matrix API 简介 + +Matrix 是一套开放联盟的即时消息(IM)、VoIP 与物联网(IoT)通信开放 API,旨在创建并支撑一个新的全球实时通信生态系统。其目标是在互联网上提供一个开放、去中心化的发布/订阅层,用于安全持久化和发布/订阅 JSON 对象。本规范是对用于 Matrix 生态系统各组件互通讯的 API 持续标准化的结果。 + +Matrix 遵循的原则包括: + +- 以现实可用、Web 友好的 API(即基于 REST 的 JSON)为准则 +- 保持简单明了 + - 提供简洁架构,尽量减少第三方依赖 +- 完全开放: + - 完全开放联盟——任何人都应能参与全球 Matrix 网络 + - 完全开放标准——公开记录的标准,无知识产权或专利许可负担 +- 赋能终端用户 + - 用户应可自主选择所用服务器和客户端 + - 用户应能自主控制通信的隐私程度 + - 用户应清楚了解其数据存储的位置 +- 完全去中心化——无会话或网络整体的单点控制 +- 汲取历史经验,避免重蹈覆辙 + - 采纳 XMPP、SIP、IRC、SMTP、IMAP 及 NNTP 的优点,努力规避其缺陷 + +Matrix 提供的功能包括: + +- 支持无单点控制或失效的完全分布式聊天室的创建与管理 +- 跨全球开放联盟服务器和服务,实现房间状态的最终一致且加密安全的同步 +- 在房间中可发送与接收可扩展消息,支持(可选)端到端加密 +- 可扩展的用户管理(邀请、加入、离开、踢出、封禁),基于权限级别的用户特权系统来实现 +- 可扩展的房间状态管理(房间命名、别名、主题、封禁等) +- 可扩展的用户档案管理(头像、显示名称等) +- 用户账户管理(注册、登录、登出) +- 使用第三方标识(3PID),如电子邮件地址、电话号码、Facebook 账号,进行认证、识别和发现 Matrix 用户 +- 可信赖的身份服务器联盟,用于: + - 发布用户公钥(PKI) + - 将 3PID 映射为 Matrix ID + +Matrix 的终极目标是作为一个无处不在的消息层,实现任意数据在多用户、设备和服务间的同步——无论是即时消息、VoIP 呼叫建立,还是其他需可靠持久推送的对象,都能以互操作和联盟的方式从 A 推送到 B。 + +### 需求级别 + +规范中所有部分涉及的关键词 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"MAY" 和 "OPTIONAL",应按 [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) 中所述理解。 + +根据实际情况,规范的某些完整部分可能是可选的。例如,[客户端-服务器 API 的模块](/client-server-api/#modules) 是否适用,取决于具体用例。上述关键词标明的强制级别,仅在该部分本身适用时才相关。 + +### 规范更改提案 + +如需对 Matrix 规范提出更改建议,请参见 [Matrix 规范更改提案说明](/proposals)。 + +## 架构 + +Matrix 定义了用于同步可扩展 JSON 对象(称为 “事件”)的 API,这些事件在兼容的客户端、服务器和服务间交换。客户端通常为消息/VoIP 应用或 IoT 设备/中心,通过 "客户端-服务器 API" 同步通信历史与其 “主服务器”。每个主服务器存储其所有客户端的通信历史与账户信息,并通过与其他主服务器及其客户端同步通信历史,将数据加入更广泛的 Matrix 生态。 + +客户端通常通过在虚拟 “房间” 内发送事件实现互通。房间数据会在*所有参与该房间的主服务器*之间进行复制。因此,*没有任何单个主服务器对指定房间拥有控制权或所有权*。主服务器将通信历史建模为房间的“事件图”——有向无环图(DAG),并利用 “服务器-服务器 API” 在各参与服务器间以最终一致性方式同步。不同主服务器间同步共享对话历史的过程即为“联盟”。Matrix 优先保证 CAP 定理中的可用性与分区容忍性,以牺牲一致性为代价。 + +例如,A 客户端向 B 客户端发送消息时,A 客户端通过客户端-服务器 API 向其主服务器(HS)执行一次 HTTP PUT,请求所需 JSON 事件。A 的主服务器将此事件附加到自己的房间事件图,并为保证完整性,在图的上下文中对消息签名。A 的主服务器随后通过服务器-服务器 API 的 HTTP PUT 将消息复制到 B 的主服务器。B 的主服务器验证请求、校验事件签名、授权事件内容,并将其加入自身的事件图。B 客户端再通过长连接 GET 请求从主服务器接收消息。 + +客户端间数据流动示意: + +``` + { Matrix 客户端 A } { Matrix 客户端 B } + ^ | ^ | + | 事件 | 客户端-服务器 API | 事件 | + | V | V + +------------------+ +------------------+ + | |---------( HTTPS )--------->| | + | 主服务器 | | 主服务器 | + | |<--------( HTTPS )----------| | + +------------------+ 服务器-服务器 API +------------------+ + 历史同步 + (联盟) +``` + +### 用户 + +每个客户端关联一个用户账户,在 Matrix 中通过唯一的 “用户 ID” 标识。该 ID 以分配账户的主服务器为命名空间,格式为: + + @localpart:domain + +详见附录中【标识符语法】(['Identifier Grammar' in the appendices](/appendices#identifier-grammar))。 + +### 设备 + +在 Matrix 规范中,“设备”有其特定含义。作为用户,我可能会有多个设备:如桌面客户端、若干网页浏览器、Android 设备、iPhone 等。这些大致对应现实物理设备,但一个物理设备上可以有多个浏览器,或多个 Matrix 客户端应用,每一个都将被视为独立设备。 + +设备主要用于管理端到端加密所用的密钥(每个设备各拥有其解密密钥副本),也有助于用户管理访问权限——例如,可以撤销对特定设备的访问。 + +用户首次使用某客户端时,该客户端会注册为新的设备。设备存活时间可能依客户端类型而异。Web 客户端通常在登出时清除全部状态,每次登录都会创建新设备,以防加密密钥泄漏给新用户。移动客户端则可在登录会话超时后重用设备(前提是同一用户)。 + +设备通过 `device_id` 标识,在属于该用户的设备范围内唯一。 + +用户可为设备分配一个易于辨识的显示名称,以便管理其设备。 + +### 事件 + +所有通过 Matrix 交换的数据均以“事件”形式表达。一般而言,每一次客户端操作(例如发送消息)对应恰好一个事件。每个事件都有一个 `type` 类型,用于区分不同数据。`type` 值必须全局唯一地按 Java [包命名规范](https://en.wikipedia.org/wiki/Java_package#Package_naming_conventions)命名,例如 `com.example.myapp.event`。特殊顶级命名空间 `m.` 保留为本规范定义事件类型——比如 `m.room.message` 是即时消息的事件类型。事件通常在某“房间”上下文中发送。 + +{{% boxes/warning %}} +事件体被视为不受信任数据。这意味着,任何使用 Matrix 的应用都必须在使用事件体内容之前,先校验其形状/模式是否符合预期。 + +**不能假设事件体总能完整且类型正确地包含所有预期字段。** + +详见 [MSC2801](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/2801-untrusted-event-data.md) 了解为何这种假设不安全。 +{{% /boxes/warning %}} + +### 事件图 + +房间中的事件存储于一个有向无环图(DAG),称为“事件图”。此图的部分顺序决定了房间内事件的相对时间顺序。图中每个事件有零个或多个“父事件”,用于指向主服务器视角下没有时间后继的前置事件。 + +一般情况下,事件只有一个父事件:即发送时房间中最新消息。但当多个主服务器同时发送消息时,可能竞态,导致单个事件出现多个后继,下一事件因而会有多个父节点。每个事件图都有一个无父事件的根节点。 + +为便于对事件进行时间顺序比较,主服务器会在每个事件上维护 `depth` 元数据字段。`depth` 是一个正整数,必须大于所有父事件的 `depth`,根事件 `depth` 应为 1。因此若一个事件在另一个之前,则其 `depth` 必然更小。 + +### 房间结构 + +房间是用户可发送和接收事件的概念场所。事件发往房间,房间内所有有足够权限的参与者都能收到该事件。房间在内部通过唯一 “房间 ID” 标识,格式如下: + + !opaque_id:domain + +每个房间只有一个房间 ID。虽然房间 ID 包含域名,其作用仅用于全局命名空间,房间**并不**驻留在所指明的域名上。 + +详见附录中【标识符语法】(['Identifier Grammar' in the appendices](/appendices#identifier-grammar))。 + +下图为 `m.room.message` 事件被发送到房间 `!qporfwt:matrix.org` 的示意: + + { @alice:matrix.org } { @bob:example.org } + | ^ + | | + [HTTP POST] [HTTP GET] + 房间ID: !qporfwt:matrix.org 房间ID: !qporfwt:matrix.org + 事件类型: m.room.message 事件类型: m.room.message + 内容: { JSON 对象 } 内容: { JSON 对象 } + | | + V | + +------------------+ +------------------+ + | 主服务器 | | 主服务器 | + | matrix.org | | example.org | + +------------------+ +------------------+ + | ^ + | [HTTP PUT] | + | 房间ID: !qporfwt:matrix.org | + | 事件类型: m.room.message | + | 内容: { JSON 对象 } | + `---> 指向前一条消息的指针 --------------` + 出自 matrix.org 的 PKI 签名 + 事务层元数据 + PKI 授权头 + + .................................... + | 共享数据 | + | 状态: | + | 房间ID: !qporfwt:matrix.org | + | 服务器: matrix.org, example.org | + | 成员: | + | - @alice:matrix.org | + | - @bob:example.org | + | 消息: | + | - @alice:matrix.org | + | 内容: { JSON 对象 } | + |....................................| + +联盟会在每个房间各参与主服务器之间维护*共享数据结构*。数据分为 `消息事件` 和 `状态事件`。 + +消息事件: +这些事件描述房间中的短暂“一次性”活动,例如即时消息、VoIP 呼叫建立、文件传输等,主要代表通信行为。 + +状态事件: +描述与房间有关的持久信息(状态)更新,如房间名称、主题、成员、参与服务器等。状态以房间内每个 `state_key` 和事件类型构成的键值对查找表建模。每个状态事件都会更新特定键值的内容。 + +房间在某一时刻的状态由事件图上一切前置事件和当前事件共同推导。如果事件间的状态描述冲突,会应用合并算法。状态解析算法具有传递性,与服务器状态无关,必须保证无论服务器为何或事件接收顺序如何,都能选出一致的事件。事件由来源服务器签名,签名内容包括父关系、类型、深度和负载哈希,并作为联盟消息推送到房间内其他服务器,目前采用全互联拓扑。服务器间还可拉取事件回填。 + +{{% boxes/note %}} +事件类型不限于本规范定义。开发者可随时创建新或自定义事件类型,采用 Java 包命名规范。例如,`com.example.game.score` 事件即可被客户端发送,其他客户端若有权限即可接收,前提是拥有 `com.example` 命名空间的访问权。 +{{% /boxes/note %}} + +#### 房间别名 + +每个房间还可有多个“房间别名”,格式如下: + + #room_alias:domain + +详见附录中【标识符语法】(['Identifier Grammar' in the appendices](/appendices#identifier-grammar))。 + +房间别名“指向”某个房间 ID,是对外宣传和发现房间时用的可读标签。要得知别名指向的房间 ID,需访问所指明域名。注意,房间别名映射至房间 ID 的关系不是固定的,随时可能切换至其他房间 ID。鉴于此,客户端*应*在首次解析别名时获取房间 ID,并在后续请求中直接使用房间 ID。 + +解析房间别名时,服务器还会返回参与房间、可用于加入的服务器列表。 + + HTTP GET + #matrix:example.org !aaabaa:matrix.org + | ^ + | | + _______V____________________|____ + | example.org | + | 映射: | + | #matrix >> !aaabaa:matrix.org | + | #golf >> !wfeiofh:sport.com | + | #bike >> !4rguxf:matrix.org | + |________________________________| + +### 身份 + +Matrix 用户以 Matrix 用户 ID 唯一标识。但也支持使用现有第三方身份命名空间。Matrix“身份”描述用户的用户 ID 及其与账户*关联*的所有第三方标识(3PID)。Matrix 用户可将电子邮箱、社交账号、电话号码等 3PID 关联到其用户 ID。关联 3PID 便在 3PID 与用户 ID 之间建立映射,进而方便用户根据 3PID 搜索联系人对应的用户 ID。为确保 3PID 到用户 ID 的映射真实可靠,Matrix 采用全球联盟的可信“身份服务器”(IS)来验证 3PID、持久存储并复制映射关系。 + +客户端不强制接入 IS 即可接入 Matrix 生态;但如果没有 IS 将无法通过 3PID 查询用户 ID。 + +### 用户档案 + +用户可公开与账户关联的任意键值对数据——如显示名称、头像 URL、联系邮箱、电话、网站等。 + +### 用户私人数据 + +用户也可在账户中存储任意私有键值对数据——比如客户端偏好设置,或尚无专用 API 的服务器配置。此 API 与用户档案管理对称。 + +## 通用概念 + +多项通用概念适用于所有 Matrix API,在此统一说明。 + +### 命名空间 + +命名空间用于防止多应用及规范自身产生冲突。规范中用 `m.` 前缀表明该字段受规范控制。实际使用时,凡非规范字段,都*必须*遵循 Java 包命名惯例,防止冲突。 + +如,规范定义的事件类型都以 `m.` 前缀命名,但客户端也可发送诸如 `com.example.game.score` 的自定义事件类型(前提客户端有该命名空间权利),无需将事件纳入 `m.` 命名空间。 + +### 时间戳 + +除非另有说明,时间戳为自 UNIX 纪元(1970-01-01 00:00:00 UTC)以来的毫秒数,不计闰秒,即每天精确为 86,400,000 毫秒。 + +这导致在闰秒期间,时间戳可能重复。多数编程语言本地支持此格式,例如 [ECMAScript](https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-time-values-and-time-range)。规范中,可用 POSIX、[Unix](https://en.wikipedia.org/wiki/Unix_time) 或“毫秒时间”等表述。 + +## 规范版本 + +Matrix 作为整体以单一规范号 `vX.Y` 发布。 + +* `X` 的变动表示有破坏性或重大结构性更改。具体何时递增由规范核心团队决定,或如移除 JSON、变更签名算法,或当累积足够多的 `Y` 级更动时,提升大版本。 +* `Y` 的变动表示向后兼容,或“可控”向后兼容的变动,通常表现为功能补充。 + +此外,规范版本后可加 `-` 跟随任意元数据,如 `v1.1-alpha`。对此无强制性规范,主要用于规范预发布版本。 + +注意,`v1.2` 设计上与 `v1.1` 向后兼容,但日后版本不保证一定与 `v1.1` 完全兼容。例如,若 `/test` 于 `v1.1` 引入、`v1.2` 弃用,则可于 `v1.3` 移除。详见下面的[弃用政策](#deprecation-policy)。 + +### 接口版本化 + +所有 API 接口均单独版本化。例如,`/v3/sync` 被废弃时可用 `/v4/sync` 替代,并不影响 `/v3/profile`。服务器支持 `/v4/sync` 时,仍照常提供 `/v3/profile`。 + +MSC 若提议给某接口带来破坏性变更,亦应同时废弃现有接口。部分场景下,这可通过引入新版本接口(如 `/v4/sync` 替代 `/v3/sync`)隐式完成,复杂场景则需要 MSC 明确声明接口弃用。 + +### 弃用政策 + +MSC 负责将规范中某项内容从稳定(默认)状态过渡为弃用。某项内容弃用足够长时间(常见为 1 个版本)后,可经由后续 MSC 从规范中彻底移除。 + +Matrix 实现需实现规范中的弃用功能。但一旦相关功能自规范移除,实现可自行放弃支持(如其不对外声明支持含弃用功能的版本)。例如,若 `/test` 在 `v1.2` 弃用、`v1.3` 移除,则希望声明支持 `v1.2` 的实现必须实现 `/test`,即便其同时支持 `v1.3`。若实现*仅*声明支持 `v1.3`,则无需实现 `/test`。 + +### 传统版本化 + +新版本系统推行前,Matrix 的各 API 单独版本化。新规范版本模式下不再适用。 + +历史上,API 版本号为 `rX.Y.Z`,其中 X 约等于重大变更、Y 为向后兼容更新,Z 为补丁或微小调整。 + +现行全局版本从 `v1.1` 起。 [Matrix 1.0](https://matrix.org/blog/2019/06/11/introducing-matrix-1-0-and-the-matrix-org-foundation/) 并未直接与某规范版本对应,而对应各 API 的如下版本: + +| API/规范 | 版本 | +|--------------------------|------------| +| 客户端-服务器 API | r0.5.0 | +| 服务器-服务器 API | r0.1.2 | +| 应用服务 API | r0.1.1 | +| 身份服务 API | r0.2.0 | +| 推送网关 API | r0.1.0 | +| 房间版本 | 1, 2, 3, 4, 5 | + +`v1.0` **不得** 由服务器在 [`GET /_matrix/client/versions`](/client-server-api/#get_matrixclientversions) 响应中返回。 + +## 许可协议 + +Matrix 规范遵循 [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 授权。 diff --git a/locales/zh-Hans/appendices.md b/locales/zh-Hans/appendices.md new file mode 100644 index 00000000..8b42b245 --- /dev/null +++ b/locales/zh-Hans/appendices.md @@ -0,0 +1,1005 @@ +--- +title: "附录" +weight: 70 +type: docs +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 无补位的 Base64 + +*无补位* Base64 指的是 [RFC 4648](https://tools.ietf.org/html/rfc4648) 中定义的“标准”Base64 编码,但不包含等号 `"="` 补位。具体来说,RFC 4648 要求编码数据长度需为 4 的整数倍时,使用 `=` 字符进行补位,而无补位 Base64 则省略此补位。 + +供参考,RFC 4648 中 Base64 的编码字母表如下: + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w + 15 P 32 g 49 x + 16 Q 33 h 50 y + +使用无补位 Base64 编码的字符串示例: + + UNPADDED_BASE64("") = "" + UNPADDED_BASE64("f") = "Zg" + UNPADDED_BASE64("fo") = "Zm8" + UNPADDED_BASE64("foo") = "Zm9v" + UNPADDED_BASE64("foob") = "Zm9vYg" + UNPADDED_BASE64("fooba") = "Zm9vYmE" + UNPADDED_BASE64("foobar") = "Zm9vYmFy" + +在解码 Base64 时,建议各实现尽可能接受含有或不含有补位字符的输入,以最大程度增强互操作性。 + +## 二进制数据 + +在一些情况下,需要封装二进制数据,例如公钥或签名。鉴于 JSON 无法安全地表示原始二进制数据,所有二进制值应按上述无补位 Base64 字符串编码并在 JSON 中表示。 + +当 Matrix 规范中提到“opaque byte”或“opaque Base64”值时,指的是在 Base64 解码之后的对应值应视作不可解释的二进制数据,而不是其编码表示。 + +无论何时,客户端或服务端实现都可以检测 Base64 编码值的正确性,并直接拒绝非法编码的值。但这并非强制要求,可视为实现细节。 + +针对未来协议转换(如不用 JSON 的场景),如无需 Base64 编码即可安全表示二进制值,则 Base64 可完全省略。 + +## JSON 签名 + +Matrix 规范中多个位置要求对 JSON 对象进行加密签名。这要求将 JSON 编码为二进制字符串。不幸的是,同样的 JSON 结构可以通过更改空白符或调整键顺序产生不同的字节表示。 + +因此,对对象签名需使用 [规范化 JSON](#canonical-json) 编码为字节序列,并计算该序列的签名,然后将签名添加到原始 JSON 对象。 + +### 规范化 JSON + +为确保所有实现都使用相同方式编码 JSON,我们定义“规范化 JSON”。本定义与规格外对“Canonical JSON”的其它使用不同。 + +对于一个值,规范化编码指以 UTF-8 最短编码、字典键按 Unicode 码点字典序排序的 JSON 字符串。JSON 中的数字须为 `[-(2**53)+1, (2**53)-1]` 范围内的整数,不允许指数形式或小数,不允许出现负零 `-0`。 + +我们选用 UTF-8 作为编码方式,因为所有平台均可用且网络上的 JSON 多为 UTF-8 编码。采用键排序以保证顺序一致。整数范围限定为可用 IEEE 双精度浮点精确表示的范围,因许多 JSON 库以此存储数字。 + +{{% boxes/warning %}} +房间版本 1、2、3、4 和 5 中的事件可能并不完全符合上述限制。服务器应尽可能能够处理被这些限制判为无效的 JSON。 + +需特别注意的是,整数可能不在上述指定范围。 +{{% /boxes/warning %}} + +{{% boxes/note %}} +此编码不允许浮点型。 +{{% /boxes/note %}} + +```py +import json + +def canonical_json(value): + return json.dumps( + value, + # 将 ASCII 之外的码点编码为 UTF-8,而不是 \u 转义 + ensure_ascii=False, + # 移除多余空白。 + separators=(',',':'), + # 字典键进行排序。 + sort_keys=True, + # 结果 Unicode 编码成 UTF-8 字节。 + ).encode("UTF-8") +``` + +#### 语法 + +参照 的语法,移除无关紧要的空白、分数、小数及冗余字符转义。 + + value = false / null / true / object / array / number / string + false = %x66.61.6C.73.65 + null = %x6E.75.6C.6C + true = %x74.72.75.65 + object = %x7B [ member *( %x2C member ) ] %x7D + member = string %x3A value + array = %x5B [ value *( %x2C value ) ] %x5D + number = [ %x2D ] int + int = %x30 / ( %x31-39 *digit ) + digit = %x30-39 + string = %x22 *char %x22 + char = unescaped / %x5C escaped + unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + escaped = %x22 ; " 引号 U+0022 + / %x5C ; \ 反斜杠 U+005C + / %x62 ; b 退格符 U+0008 + / %x66 ; f 换页符 U+000C + / %x6E ; n 换行 U+000A + / %x72 ; r 回车 U+000D + / %x74 ; t 制表符 U+0009 + / %x75.30.30.30 (%x30-37 / %x62 / %x65-66) ; u000X + / %x75.30.30.31 (%x30-39 / %x61-66) ; u001X + +#### 示例 + +为帮助开发兼容实现,以下测试值可用于验证规范化转换代码。 + +给定如下 JSON 对象: + +```json +{} +``` + +应输出如下规范化 JSON: + +```json +{} +``` + +给定如下 JSON 对象: + +```json +{ + "one": 1, + "two": "Two" +} +``` + +应输出如下规范化 JSON: + +```json +{"one":1,"two":"Two"} +``` + +给定如下 JSON 对象: + +```json +{ + "b": "2", + "a": "1" +} +``` + +应输出如下规范化 JSON: + +```json +{"a":"1","b":"2"} +``` + +给定如下 JSON 对象: + +```json +{"b":"2","a":"1"} +``` + +应输出如下规范化 JSON: + +```json +{"a":"1","b":"2"} +``` + +给定如下 JSON 对象: + +```json +{ + "auth": { + "success": true, + "mxid": "@john.doe:example.com", + "profile": { + "display_name": "John Doe", + "three_pids": [ + { + "medium": "email", + "address": "john.doe@example.org" + }, + { + "medium": "msisdn", + "address": "123456789" + } + ] + } + } +} +``` + +应输出如下规范化 JSON: + +```json +{"auth":{"mxid":"@john.doe:example.com","profile":{"display_name":"John Doe","three_pids":[{"address":"john.doe@example.org","medium":"email"},{"address":"123456789","medium":"msisdn"}]},"success":true}} +``` + +给定如下 JSON 对象: + +```json +{ + "a": "日本語" +} +``` + +应输出如下规范化 JSON: + +```json +{"a":"日本語"} +``` + +给定如下 JSON 对象: + +```json +{ + "本": 2, + "日": 1 +} +``` + +应输出如下规范化 JSON: + +```json +{"日":1,"本":2} +``` + +给定如下 JSON 对象: + +```json +{ + "a": "\u65E5" +} +``` + +应输出如下规范化 JSON: + +```json +{"a":"日"} +``` + +给定如下 JSON 对象: + +```json +{ + "a": null +} +``` + +应输出如下规范化 JSON: + +```json +{"a":null} +``` + +给定如下 JSON 对象: + +```json +{ + "a": -0, + "b": 1e10 +} +``` + +应输出如下规范化 JSON: + +```json +{"a":0,"b":10000000000} +``` + +### 签名细节 + +对 JSON 进行签名时,需先移除 `signatures` 和 `unsigned` 相关的键,然后采用上述规范化编码方式编码对象。对获得的字节数据进行签名,并将签名结果采用[无补位 Base64](#unpadded-base64)编码。得到的 base64 签名应按*签名密钥标识符*添加至 `signatures` 中,其下为签名实体的名称,共同返回原始 JSON 对象,并同时恢复 `unsigned` 字段。 + +*签名密钥标识符*由*签名算法*和*密钥标识符*拼接而成。*签名算法*标识用于签名的算法,目前支持的值为 `ed25519`,参见 NACL ()。*密钥标识符*用于区分同一实体使用的不同签名密钥。 + +`unsigned` 和 `signatures` 字段不受签名覆盖。因此,中间实体可添加未签名数据(比如时间戳)或额外签名。 + +```json +{ + "name": "example.org", + "signing_keys": { + "ed25519:1": "XSl0kuyvrXNj6A+7/tkrB9sxSbRi08Of5uRhxOqZtEQ" + }, + "unsigned": { + "age_ts": 922834800000 + }, + "signatures": { + "example.org": { + "ed25519:1": "s76RUgajp8w172am0zQb/iPTHsRnb4SkrzGoeCOSFfcBY2V/1c8QfrmdXHpvnc2jK5BD1WiJIxiMW95fMjK7Bw" + } + } +} +``` + +```py +def sign_json(json_object, signing_key, signing_name): + signatures = json_object.pop("signatures", {}) + unsigned = json_object.pop("unsigned", None) + + signed = signing_key.sign(encode_canonical_json(json_object)) + signature_base64 = encode_base64(signed.signature) + + key_id = "%s:%s" % (signing_key.alg, signing_key.version) + signatures.setdefault(signing_name, {})[key_id] = signature_base64 + + json_object["signatures"] = signatures + if unsigned is not None: + json_object["unsigned"] = unsigned + + return json_object +``` + +### 验证签名 + +要检查某实体是否已对 JSON 对象签名,具体步骤如下: + +1. 检查对象的 `signatures` 成员下是否有该实体的条目。如缺失则验证失败。 +2. 从该条目中移除本实现不理解算法的*签名密钥标识符*。如剩下的*签名密钥标识符*为空则验证失败。 +3. 从本地缓存或可信密钥服务器查询剩余*签名密钥标识符*的*校验密钥*。找不到则验证失败。 +4. 解码 base64 编码的签名字节。失败则验证失败。 +5. 移除对象中的 `signatures` 和 `unsigned` 成员。 +6. 使用[规范化 JSON](#canonical-json)方式编码剩余 JSON。 +7. 用*校验密钥*对签名字节和编码对象进行校验。如失败则验证失败,否则成功。 + +## 标识符语法 + +部分标识符特定于某些房间版本,详见 [房间版本规范](/rooms)。 + +### 通用命名空间标识符语法 + +{{% added-in v="1.2" %}} + +本规范定义了一些标识符采用*通用命名空间标识符语法*。该语法适用于非面向用户的标识符,并为实现创建新标识符提供统一机制。 + +语法定义如下: + + * 标识符长度不少于 1 个字符且不超过 255 个字符。 + * 标识符必须以 `[a-z]` 开头,全由 `[a-z]`、`[0-9]`、`-`、`_` 和 `.` 构成。 + * 以 `m.` 开头的标识符为 Matrix 官方保留,不得使用。 + * 规范未描述的标识符应遵循 Java 包命名约定进行命名空间区分,通常采用反向域名格式,如 `com.example.identifier`。 + +{{% boxes/note %}} +标识符可继承本规范的语法。例如,“该标识符使用通用命名空间标识符语法,但无强制命名空间要求”——这意味着 `m.` 依然保留,但实现可以不使用反向 DNS 格式命名自定义标识符。 +{{% /boxes/note %}} + +{{% boxes/rationale %}} +ASCII 字符不会因同形异义或编码差异影响标识符用途。此外,全部小写可避免大小写带来的敏感性问题。 +{{% /boxes/rationale %}} + +### 服务器名 + +一个主服务器通过服务器名唯一标识。此值在多个标识符中被引用,详见下文。 + +服务器名表示其他主服务器可通信的该服务器的地址。下述语法包括所有有效服务器名: + + server_name = hostname [ ":" port ] + + port = 1*5DIGIT + + hostname = IPv4address / "[" IPv6address "]" / dns-name + + IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT + + IPv6address = 2*45IPv6char + + IPv6char = DIGIT / %x41-46 / %x61-66 / ":" / "." + ; 0-9, A-F, a-f, :, . + + dns-name = 1*255dns-char + + dns-char = DIGIT / ALPHA / "-" / "." + +——换句话说,服务器名为主机名,后可带可选的数字端口。主机名可以是点分十进制 IPv4 地址、方括号包裹的 IPv6 地址,或 DNS 名称。 + +IPv4 字面量须为 0-255 的四段十进制数字,用 `.` 分隔。IPv6 字面量参见 [RFC3513, section 2.2](https://tools.ietf.org/html/rfc3513#section-2.2)。 + +用于 Matrix 的 DNS 名称应遵守互联网主机名的通用约束:以 `.` 分隔的标签,每个标签为字母数字或连字符。 + +有效服务器名示例: + +- `matrix.org` +- `matrix.org:8888` +- `1.2.3.4`(IPv4 字面量) +- `1.2.3.4:1234`(IPv4 字面量含端口) +- `[1234:5678::abcd]`(IPv6 字面量) +- `[1234:5678::abcd]:5678`(IPv6 字面量含端口) + +{{% boxes/note %}} +此语法基于互联网主机名标准 [RFC1123, section 2.1](https://tools.ietf.org/html/rfc1123#page-13),扩展了对 IPv6 字面量的支持。 +{{% /boxes/note %}} + +服务器名必须区分大小写:例如,`@user:matrix.org` 与 `@user:MATRIX.ORG` 表示不同用户。 + +关于服务器名选择,建议如下: + +- 服务器名总长度不应超过 230 个字符。 +- 服务器名不应包含大写字母。 + +### 通用标识符格式 + +Matrix 协议为多个实体(如用户、事件、房间)分配唯一标识符,采用通用格式: + + &string + +其中 `&` 为前缀符号(sigil);`string` 为标识符内容。 + +前缀符号如下: + +- `@`:用户 ID +- `!`:房间 ID +- `$`:事件 ID +- `#`:房间别名 + +用户 ID、房间 ID、房间别名及部分事件 ID 格式如下: + + &localpart:domain + +其中 `domain` 为创建该标识符的主服务器 [服务器名](#server-name),`localpart` 由该主服务器分配。 + +标识符的具体格式与类型相关。例如,事件 ID 有时可以包含 `domain`,详见下方的 [事件 ID](#event-ids) 章节。 + +#### 用户标识符 + +{{% changed-in v="1.8" %}} + +Matrix 系统内用户通过用户 ID 唯一标识。用户 ID 归属于分配账户的主服务器,格式如下: + + @localpart:domain + +用户 ID 的 `localpart` 为该用户的不透明标识符。不得为空,仅可包含 `a-z`、`0-9`、`.`、`_`、`=`、`-`、`/`、`+` 字符。 + +`domain` 为创建账户的主服务器 [服务器名](#server-name)。 + +用户 ID 总长(含 `@` 和域名)不得超过 255 字节。 + +合法用户 ID 完整语法如下: + + user_id = "@" user_id_localpart ":" server_name + user_id_localpart = 1*user_id_char + user_id_char = DIGIT + / %x61-7A ; a-z + / "-" / "." / "=" / "_" / "/" / "+" + +{{% boxes/rationale %}} +在定义用户 ID 可用字符时,我们综合考虑了若干要素。 + +首先,排除了 US-ASCII 基本字符集外的字符。用户 ID 主要用于协议层级标识,作为人类可读名称属于第二层。在一些情况下用户 ID 也用于区分具有相似显示名的用户。支持全 Unicode 字符集将大大增加人工区分难度。选择有限字符集意味着即使不熟悉拉丁字母的用户,也能辨别相似用户 ID。 + +我们禁止大写字符,是因为不希望出现仅以大小写区分的两个用户 ID:例如可用 `@USER:matrix.org` 替代 `@user:matrix.org`。但在部分场景(如 `m.room.member` 事件的 `state_key`)中用户 ID 必须区分大小写。禁止大写字符并要求主服务器在为新用户生成 ID 时统一小写,是避免 `@USER:matrix.org` 与 `@user:matrix.org` 产生歧义的简便做法。 + +我们还限制了可用标点符号,以减少特殊字符冲突。例如,部分 API(如过滤器 API)用 `"*"` 作为通配符,所以不能作为合法用户 ID 字符。 + +长度限制则源自事件中 `sender` 关键字的长度上限。由于用户 ID 出现在用户发送的每个事件中,为防止其长度大幅超过实际内容而设限。 +{{% /boxes/rationale %}} + +Matrix 用户 ID 有时被非正式地称为 MXID。 + +##### 历史用户 ID + +本规范早期版本允许更广泛的字符作为用户 ID `localpart`。目前仍有活跃用户 ID 不符合现行字符集要求,也有部分房间历史事件的 `sender` 不合规。为了兼容这些房间,客户端和服务器*必须*能够接收 `localpart` 为除 `:` 和 `NUL`(U+0000)以外的任意合法非代理 Unicode 码点(包括其它控制字符及空字符串)的用户 ID。 + +如 `localpart` 含 U+0021~U+007E 以外的字符,或为空,用户 ID 被视为不合规。对于当前房间版本,服务器在联邦传递事件时仍需接受这些历史用户 ID,但*不应*在事件上下文外将其转发给客户端(如设备列表更新等数据应被丢弃)。 + +未来房间版本可能直接阻止使用历史字符集的用户参与。历史字符集*已废弃*。 + +##### 跨字符集映射 + +某些情况下需将更广泛字符集映射到受限的用户 ID `localpart` 字符集。例如主服务器接受 `/register` 注册时根据用户名创建用户 ID,或桥接其他协议的用户 ID。 + +具体映射方式实现可自定。由于用户 ID 对外为不透明字符串,唯一要求是实现能保持映射一致。建议算法如下: + +1. 以 UTF-8 编码字符字符串。 +2. 将 `A-Z` 字节转为小写。 + - 若桥接需区分大小写用户,先加 `_` 转义大写再转换。如 `A` 编码为 `_a`,真实 `_` 则写为 `__`。 +3. 其余不在允许字符集的字节及 `=`,以十六进制值、前缀 `=` 形式编码。例如 `#` 写为 `=23`,`á` 写为 `=c3=a1`。 + +{{% boxes/rationale %}} +建议映射试图最大化简单 ASCII 标识符的人类可读性(区别于 base32),同时能编码*所有*字符(区别于 punycode,不支持 ASCII 标点编码)。 +{{% /boxes/rationale %}} + +#### 房间 ID + +房间有唯一的房间 ID。格式如下: + + !opaque_id:domain + +`domain` 为创建房间的主服务器 [服务器名](#server-name) 仅用于名称空间防止冲突,并不一定代表房间现仍由该服务器维护。 + +房间 ID 区分大小写。不建议为人类可读,客户端应完全以不可解释字符串处理之。 + +房间 ID 的 `localpart`(即 `opaque_id`)可包含除 `:` 和 `NUL`(U+0000)外的任意合法非代理 Unicode 码点(包括控制字符),但建议生成时仅用 ASCII 字母与数字 (`A–Z`, `a–z`, `0–9`)。 + +房间 ID 总长(含 `!` 和域名)不得超过 255 字节。 + +#### 房间别名 + +房间可有零个或多个别名。格式如下: + + #room_alias:domain + +`domain` 为创建别名的主服务器 [服务器名](#server-name),其他服务器可通过该主服务器解析别名。 + +别名的 `localpart` 可包含除 `:` 和 `NUL` 的任意合法非代理 Unicode 码点。 + +房间别名总长(含 `#` 和域名)不得超过 255 字节。 + +#### 事件 ID + +事件有唯一事件 ID。格式如下: + + $opaque_id + +但具体格式依 [房间版本规范](/rooms) 而异。早期房间版本事件 ID 包含 `domain` 组件,较新版本则省略,使用 base64 编码散列。 + +除房间版本要求外,事件 ID (含 `$` 和 domain,如有)总长不得超过 255 字节。 + +事件 ID 区分大小写。不建议为人类可读,客户端应完全视为不透明字符串处理。 + +### URI + +Matrix 内资源有两种主要引用方式:matrix.to 及 `matrix:` URI。当前规范均认定上述两者为有效的实体/资源引用方式。 + +房间、用户及别名均可通过 URI 表示。可用于特定上下文引用对象,如在消息中提及用户或提供房间历史的永久链接(permalink)。 + +#### Matrix URI 方案 + +{{% added-in v="1.2" %}} + +Matrix URI 格式定义如下(`[]` 表存在可选部分,`{}` 表变量): +``` +matrix:[//{authority}/]{type}/{id without sigil}[/{type}/{id without sigil}...][?{query}][#{fragment}] +``` + +作为模式,可表示为: + +``` +MatrixURI = "matrix:" hier-part [ "?" query ] [ "#" fragment ] +hier-part = [ "//" authority "/" ] path +path = entity-descriptor ["/" entity-descriptor] +entity-descriptor = nonid-segment / type-qualifier id-without-sigil +nonid-segment = segment-nz ; 见 RFC 3986 +type-qualifier = segment-nz "/" ; 见 RFC 3986 +id-without-sigil = string ; 详见上方 Matrix 标识符规范 +query = query-element *( "&" query-item ) +query-item = action / routing / custom-query-item +action = "action=" ( "join" / "chat" ) +routing = "via=” authority +custom-query-item = custom-item-name "=" custom-item-value +custom-item-name = 1*unreserved ; 反向 DNS 名 +custom-item-value = +``` + +此格式遵循 [RFC 3986](https://tools.ietf.org/html/rfc3986),以确保与现有工具最大兼容。方案名(`matrix`)已被 IANA 注册:[点此查看](https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml)。 + +目前,`authority` 与 `fragment` 未由本规范使用,仅作预留。Matrix 并无可合理填充 `authority` 的中央权威。`schema` 中的 `nonid-segment` 也为未来预留。 + +`type` 指明实体类型,`id without sigil` 即去除开头符号的标识符。目前用法如下: + +* `r`:房间别名 +* `u`:用户 +* `roomid`:房间 ID(区别于房间别名) +* `e`:事件(位于房间 ID `roomid` 之后),跟在房间别名 `r` 后的 `e` 已不推荐使用。 + +{{% boxes/note %}} +在此 URI 格式开发过程中曾使用过 `user`、`room`、`event` 等类型,现在必须转为 `u`、`r`、`e`。`roomid` 没有变化。 +{{% /boxes/note %}} + +{{% boxes/note %}} +{{% changed-in v="1.11" %}} +在通过房间别名(`r`)而非房间 ID(`roomid`)引用房间内事件 ID 的方式现已弃用。未发现实际用例,以及房间别名本身可变,故不再支持。 +{{% /boxes/note %}} + +`id without sigil` 即实体标识符去掉 sigil。例如 `!room:example.org` 变为 `room:example.org`(`!` 为房间 ID sigil),sigil 定义见 [通用标识符格式](#common-identifier-format)。 + +`query` 可选,用于提示客户端 URI 意图。当前规范如下: + +* `action`——用于指示客户端具体动作。无 `action` 则表明 URI 只标识资源,无建议操作(如可跳转到对象信息页)。 + * `action=join`——表明客户端应尝试加入 URI 所示房间,仅适用于房间相关 URI。若用户未加入房间,客户端应先询问用户。 + * `action=chat`——表明客户端应尝试发起/打开与 URI 指定用户的 DM(私聊),仅适用于用户相关 URI。如支持 Canonical DM,应重用现有 DM。若未跳转到已有 DM,客户端宜先询问用户。 +* `via`——指定解析或操作资源时可尝试的服务器(authority 语法)。如 [下文](#routing) 所述,用于房间 ID 路由推荐,也适合用于非公开联邦的标识符解析。更完整方案见 [MSC3020](https://github.com/matrix-org/matrix-spec-proposals/pull/3020)。 + +自定义参数可用 [通用命名空间标识符格式](#common-namespaced-identifier-grammar),并按规定编码(如百分比编码和转义 `&`)。与规范参数冲突时,客户端应优先标准项。为兼容不同客户端,建议自定义参数保持一致;建议广泛有用的参数提案纳入规范。 + +常见 URI 示例: + +* 指向 `#somewhere:example.org` 的链接:`matrix:r/somewhere:example.org` +* 指向 `!somewhere:example.org` 的链接:`matrix:roomid/somewhere:example.org?via=elsewhere.ca` +* 指向房间 `!somewhere:example.org` 内事件 `$event` 的链接:`matrix:roomid/somewhere:example.org/e/event?via=elsewhere.ca` +* 与 `@alice:example.org` 私聊链接:`matrix:u/alice:example.org?action=chat` + +推荐客户端实现算法见 [原始 MSC 文档](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/2312-matrix-uri.md#recommended-implementation)。 + +#### matrix.to 导航 + +{{% boxes/note %}} +matrix.to 是早于 `matrix:` URI 方案的命名空间 URI。*不要*将其视为可公开解析 Web 服务,仅做规范说明。 +{{% /boxes/note %}} + +matrix.to URI 格式如下,基于 [RFC 3986](https://tools.ietf.org/html/rfc3986): + +``` +https://matrix.to/#//? +``` + +其中 `` 可为房间 ID、房间别名或用户 ID。仅在引用事件 ID 的永久链接中使用 ``。matrix.to URI 需以 `https://matrix.to/#/` 和标识符开头。 + +`` 及前导问号可选,详见下文。 + +客户端不应用后台回退至 Web 服务器而应在客户端内解析。例如点击房间别名 URI 时弹出参与房间的界面。 + +URI 组成部分应按 RFC 3986 百分号编码。 + +matrix.to URI 示例: + +* 指向 `#somewhere:example.org` 的链接:`https://matrix.to/#/%23somewhere%3Aexample.org` +* 指向 `!somewhere:example.org` 的链接:`https://matrix.to/#/!somewhere%3Aexample.org?via=elsewhere.ca` +* 指向房间 `!somewhere:example.org` 内事件 `$event` 的链接:`https://matrix.to/#/!somewhere%3Aexample.org/%24event%3Aexample.org?via=elsewhere.ca` +* 指向 `@alice:example.org` 的链接:`https://matrix.to/#/%40alice%3Aexample.org` + +{{% boxes/note %}} +{{% changed-in v="1.11" %}} +通过房间别名指代房间内事件 ID 的方式现已弃用。未发现实际用例,且房间别名非唯一、可变,不应继续支持。 +{{% /boxes/note %}} + +{{% boxes/note %}} +历史上,客户端生成的 URI 未总是充分编码。客户端应尽力兼容,例:未编码的房间别名应尽量支持。 +{{% /boxes/note %}} + +{{% boxes/note %}} +解码 matrix.to URI 可能出现多余斜杠,这与部分 [房间版本](/rooms) 有关。生成 URI 时推荐编码斜杠。 +{{% /boxes/note %}} + +{{% boxes/note %}} +旧版规范曾提及用“群组”组织房间,但未正式引入规范内容,现已被 [Spaces](/client-server-api/#spaces) 取代。历史 matrix.to URI 指向群组形式如 `https://matrix.to/#/%2Bexample%3Aexample.org`(`+` sigil 可编码也可不编码)。 +{{% /boxes/note %}} + +#### 路由 + +房间 ID 本身不可路由,无可靠域名接收请求。引入 `via` 参数后可部分缓解,但不可彻底解决。客户端应尽力选择好路由目标,但也应注意相关 [问题 #1579](https://github.com/matrix-org/matrix-spec/issues/355)。 + +若房间或其永久链接未用房间别名,建议 URI 查询参数含至少一个 `via` 指定服务器。可多次添加 `via` 指定多个服务器。 + +`via` 参数内容建议用于 [客户端服务器 `/join/{roomIdOrAlias}` API](/client-server-api/#post_matrixclientv3joinroomidoralias)。 + +生成房间链接和永久链接时,应选能长期存在的高概率服务器。具体选择方法为实现细节,当前建议选取 3 个唯一服务器,规则如下: + +- 第一个服务器为房间内最高权限且等级不低于 50 的用户所在服务器,若无则选成员最多的服务器。高权限用户(通常100)稳定性高,更能长期留在房间。 +- 第二个服务器为按规模排序的下一个或成员最多的服务器。因用户多的服务器更可能长期参与,不易被移除。 +- 第三个服务器为下一个成员最多的服务器。 +- 被服务器 ACL 阻止的服务器不得被选择。 +- IP 地址不得作服务器,应更倾向使用域名。IP 不可迁移,风险高。 +- 三个服务器应互不重复。实际不足三台则只指定现有数量。例如仅 2 用户的房间最多提供 2 个 `via`。 + +### 不透明标识符 + +规范定义某些标识符采用*不透明标识符语法*。本语法适用于无需解析或解释的非用户可见标识符,仅要求全局唯一。 + +语法定义: + +* 标识符仅可含 `[0-9]`、`[A-Z]`、`[a-z]`、`-`、`.`、`_` 和 `~`。 +* 若无特殊说明,长度不少于 1 字符且不超过 255 字符。 + +{{% boxes/note %}} +字符集与 [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3) 的 unreserved 字符一致。 +{{% /boxes/note %}} + +## 密钥表示约定 + +有时需在用户界面展示私有加密密钥。 + +此时,密钥 *应* 以如下字符串格式呈现: + +1. 创建字节数组,先为 `0x8B` 和 `0x01` 两字节,再接原始密钥字节。 +2. 将上述所有字节(含前两字节)异或,得出校验字节,并将该字节附加至数组尾。 +3. 用 base58 编码全部字节,字母表为 `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`。 +4. 每 4 个字符插入一个空格。 + +读取密钥时,客户端应忽略所有空白,并按 1-4 步逆序解析。 + +{{% boxes/note %}} +base58 字母表与[比特币地址](https://en.bitcoin.it/wiki/Base58Check_encoding#Base58_symbol_chart)一致。 +{{% /boxes/note %}} + +## 3PID 类型 + +第三方标识符(3PID)是指在其它命名空间中与某人关联的标识符。由 `medium`(标识命名空间)与 `address`(该空间内的字符串)元组组成。`address` 必须是标识符的规范格式,即在可有多种表示的情况下,只能选用其中一种。 + +例如,电邮的 `medium` 为 'email',`address` 为 email 地址,如 `bob@example.com`。域名解析不区分大小写,因此 `bob@Example.com` 的 3PID 也应写为 `bob@example.com`(小写 'e'),而非 `bob@Example.com`。 + +本规范下定义命名空间如下,后续版本可扩展更多。 + +### 电子邮件 + +Medium: `email` + +表示电子邮件地址,`address` 格式为 `user@domain` 且域名全部小写,不能含姓名、尖括号或 mailto: 前缀。 + +除将电邮域名部分转为小写外,实现还应遵循 [Unicode 标准第五章“无大小写匹配”](https://www.unicode.org/versions/Unicode13.0.0/ch05.pdf#G21790) 算法进行大小写归一。例如 `Strauß@Example.com` 处理时应视作 `strauss@example.com`。 + +### PSTN 电话号码 + +Medium: `msisdn` + +表示公用电话网电话号码。`address` 以 MSISDN(E.164 编号规则)格式表示的电话号码。注意 MSISDN 不带 '+' 前缀。 + +## Glob 风格匹配 + +某些场景下需要用 glob(通配符)匹配字符串。Matrix 的 glob 匹配遵循: + +* `*` 匹配零个或多个字符。 +* `?` 匹配恰好一个字符。 + +## 点分属性路径 + +通过“点”连接属性名能直观表达事件属性路径,如 `content.body` 表示事件的 `content` 下 `body` 属性。 + +如属性名自身包含点,为避免歧义,点与反斜杠应以反斜杠转义。例如,`content.m\.relates_to` 表示 `content` 下名为 `m.relates_to` 的属性。类似地,`content.m\\foo` 表示名为 `m\foo` 的属性。 + +其它转义序列原样保留,例如 `\x` 按字面解释为反斜杠加 x。建议实现不做冗余转义,因其它转义序列将来也可能赋予特殊含义。 + +## 安全威胁模型 + +### 拒绝服务 + +攻击者可能尝试阻止消息送达或发送,从而: + +- 破坏竞争对手的服务或市场推广 +- 审查讨论或某参与者 +- 实施一般性破坏 + +#### 威胁:资源耗尽 + +攻击者可能导致受害服务器消耗殆尽某项资源(如开放 TCP 连接、CPU、内存、磁盘) + +#### 威胁:不可恢复一致性冲突 + +攻击者可发送消息导致集群产生无法恢复的“脑裂”状态,致使受害服务器无法得出房间一致状态。 + +#### 威胁:篡改历史 + +攻击者可能诱使受害者接受无效消息,被其他服务器拒绝,并因此波及依赖其消息的后续消息。 + +#### 威胁:阻断网络流量 + +攻击者可试图隔离受害服务器与部分或全部房间服务器间流量。 + +#### 威胁:高流量消息攻击 + +攻击者可向目标房间发送高流量消息,致其难以使用。 + +#### 威胁:无授权用户封禁 + +攻击者可能未经授权封禁房间用户。 + +### 冒充 + +攻击者可能尝试伪造受害者身份发送消息,以: + +- 从事非法活动冒充受害者 +- 窃取受害者权限 + +#### 威胁:篡改消息内容 + +攻击者可能修改受害者已发消息内容。 + +#### 威胁:伪造消息 "origin" 字段 + +攻击者可能发送新消息,冒充受害者并伪造 "origin" 字段。 + +### 垃圾信息(Spam) + +攻击者可尝试向受害者批量发送消息,以: + +- 寻找诈骗对象 +- 推销不需要的商品 + +#### 威胁:非请求消息 + +攻击者可向不愿接收者发送消息。 + +#### 威胁:辱骂消息 + +攻击者可向受害者发送辱骂或威胁消息。 + +### 窃听 + +攻击者可尝试获取并非发往自身的受害者消息内容或元数据,以: + +- 获取敏感个人信息或商业信息 +- 利用信息冒充受害者(如重置密码邮件) +- 了解受害者的交流对象与时间 + +#### 威胁:传输泄露 + +攻击者可能在服务器间传输中泄露消息内容或元数据。 + +#### 威胁:泄露给房间外服务器 + +攻击者可能诱使房间内服务器向未获授权的攻击者服务器发送消息。 + +#### 威胁:泄露给房间内服务器 + +攻击者占有房间内服务器后可暴露该房间消息及元数据。 + +## 加密测试向量 + +为帮助开发兼容实现,以下测试值可用于验证加密事件签名代码。 + +### 签名密钥 + +以下所有测试向量均使用下列 base64 编码字符串解码得出的 32 字节值,作为生成 `ed25519` 签名密钥的种子: + + SIGNING_KEY_SEED = decode_base64( + "YJDBA9Xnr2sVqXD9Vj7XVUnmFZcZrlw8Md7kMW+3XA1" + ) + +均采用以下服务器名及密钥 ID: + + SERVER_NAME = "domain" + + KEY_ID = "ed25519:1" + +### JSON 签名 + +给定空 JSON 对象: + +```json +{} +``` + +签名算法应输出: + +```json +{ + "signatures": { + "domain": { + "ed25519:1": "K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ" + } + } +} +``` + +给定有内容的 JSON 对象: + +```json +{ + "one": 1, + "two": "Two" +} +``` + +签名算法应输出: + +```json +{ + "one": 1, + "signatures": { + "domain": { + "ed25519:1": "KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw" + } + }, + "two": "Two" +} +``` + +### 事件签名 + +极简事件如下: + +```json +{ + "room_id": "!x:domain", + "sender": "@a:domain", + "origin": "domain", + "origin_server_ts": 1000000, + "signatures": {}, + "hashes": {}, + "type": "X", + "content": {}, + "prev_events": [], + "auth_events": [], + "depth": 3, + "unsigned": { + "age_ts": 1000000 + } +} +``` + +签名算法应输出: + +```json +{ + "auth_events": [], + "content": {}, + "depth": 3, + "hashes": { + "sha256": "5jM4wQpv6lnBo7CLIghJuHdW+s2CMBJPUOGOC89ncos" + }, + "origin": "domain", + "origin_server_ts": 1000000, + "prev_events": [], + "room_id": "!x:domain", + "sender": "@a:domain", + "signatures": { + "domain": { + "ed25519:1": "KxwGjPSDEtvnFgU00fwFz+l6d2pJM6XBIaMEn81SXPTRl16AqLAYqfIReFGZlHi5KLjAWbOoMszkwsQma+lYAg" + } + }, + "type": "X", + "unsigned": { + "age_ts": 1000000 + } +} +``` + +带有可撤回内容的事件如下: + +```json +{ + "content": { + "body": "Here is the message content" + }, + "event_id": "$0:domain", + "origin": "domain", + "origin_server_ts": 1000000, + "type": "m.room.message", + "room_id": "!r:domain", + "sender": "@u:domain", + "signatures": {}, + "unsigned": { + "age_ts": 1000000 + } +} +``` + +签名算法应输出: + +```json +{ + "content": { + "body": "Here is the message content" + }, + "event_id": "$0:domain", + "hashes": { + "sha256": "onLKD1bGljeBWQhWZ1kaP9SorVmRQNdN5aM2JYU2n/g" + }, + "origin": "domain", + "origin_server_ts": 1000000, + "type": "m.room.message", + "room_id": "!r:domain", + "sender": "@u:domain", + "signatures": { + "domain": { + "ed25519:1": "Wm+VzmOUOz08Ds+0NTWb1d4CZrVsJSikkeRxh6aCcUwu6pNC78FunoD7KNWzqFn241eYHYMGCA5McEiVPdhzBA" + } + }, + "unsigned": { + "age_ts": 1000000 + } +} +``` + +## Matrix API 约定 + +本节主要用于指导 Matrix 新 API 的设计人员,统一 API 行为规则,以保持协议一致性,提升开发体验。 + +### HTTP 接口和 JSON 属性命名 + +HTTP 传输的 API 接口名称一律使用下划线分隔。例如 `/delete_devices`。 + +API 中 JSON 对象的键名也遵循该命名约定。 + +{{% boxes/note %}} +历史上有部分例外,如 `/createRoom`。这些不一致的问题未来版本可能会统一。 +{{% /boxes/note %}} + +### 分页 + +支持多页结果的 REST API 端点应符合如下约定。 + + * 若有更多结果,接口返回名为 `next_batch` 的属性,其值为字符串 token,可在后续接口请求中用以获取下一页。 + + 若无更多结果,则 *省略* `next_batch` 属性。 + + * 接口接受名为 `from` 的查询参数,客户端应赋以前次返回的 `next_batch` 值。 + + * 若接口支持双向分页(如 `/messages`,可向前/后遍历时间线),则应返回 `prev_batch` 属性,可指向上一页。 + + 避免用额外的“方向”参数。`next_batch` 与 `prev_batch` 的 token 应已包含区分页向的信息。 diff --git a/locales/zh-Hans/application-service-api.md b/locales/zh-Hans/application-service-api.md new file mode 100644 index 00000000..9cfe27e0 --- /dev/null +++ b/locales/zh-Hans/application-service-api.md @@ -0,0 +1,314 @@ +--- +title: "应用服务 API" +weight: 30 +type: docs +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +Matrix 客户端-服务器 API 与服务器-服务器 API 提供了实现一致的、自包含的去中心化消息结构的手段。然而,它们在实现 Matrix 中自定义服务器端行为(例如网关、过滤器、可扩展钩子等)方面手段有限。应用服务 API (AS API) 定义了一套标准 API,不受底层主服务器实现的影响,以便实现这些可扩展功能。 + +## 应用服务 + +应用服务为被动组件,只能观察来自主服务器的事件。它们可以向参与的房间注入事件,但无法阻止事件的发送,也不能修改事件内容。为了观察来自主服务器的事件,主服务器需要配置,将某些类型的流量传递给应用服务。要实现这一点,需要手动在主服务器配置中加入应用服务的相关信息。 + +### 注册 + +{{% boxes/note %}} +此前,应用服务曾可通过 HTTP API 注册到主服务器。这一机制因安全风险被移除。被攻陷的应用服务可重新注册全局 `*` 正则,从而窃取主服务器上*所有*流量。为防止此类风险,现在应用服务必须通过配置文件进行注册,并将这些配置文件与主服务器的配置文件关联。添加配置文件后,主服务器管理员可对注册过程中的可疑正则表达式做合理性检查。 +{{% /boxes/note %}} + +应用服务注册一组用户 ID、房间别名和房间 ID 的“命名空间”。如果某事件与任何命名空间匹配,则称该应用服务对该事件“感兴趣”。 + +应用服务还可以声明是否应由其独占管理指定命名空间,这称为“独占”命名空间。独占命名空间会阻止用户及其它应用服务在该命名空间内创建或删除实体。通常,当房间映射到另一个服务的真实房间(如 IRC)时,会使用独占命名空间;当应用服务仅对房间本身提供增强功能(如记录或搜索功能)时,可使用非独占命名空间。 + +注册信息以一组键值对表示,通常编码为 YAML 文件中的对象。其结构如下: + +{{% definition path="api/application-service/definitions/registration" %}} + +独占的用户和别名命名空间应在符号后以下划线开头,以避免与主服务器的其他用户发生冲突。应用服务还应尽量在保留命名空间中体现其所代表的具体服务。例如,`@_irc_.*` 适合作为处理 IRC 的应用服务注册命名空间。 + +以下是用于 IRC 桥接应用服务的注册文件示例: + +```yaml +id: "IRC Bridge" +url: "http://127.0.0.1:1234" +as_token: "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46" +hs_token: "312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e" +sender_localpart: "_irc_bot" # 最终为 @_irc_bot:example.org +namespaces: + users: + - exclusive: true + regex: "@_irc_bridge_.*" + aliases: + - exclusive: false + regex: "#_irc_bridge_.*" + rooms: [] +``` + +{{% boxes/note %}} +针对 `users` 命名空间,应用服务只能对*本地*用户注册感兴趣(即,用户 ID 以本地主服务器的 `server_name` 结尾)。影响其他主服务器用户的事件不会发送给应用服务,即便这些用户恰好匹配 `users` 命名空间(当然,除非事件影响的房间本身就属于应用服务感兴趣范围,例如该房间中还有另一个应用服务关心的用户)。 + +对于 `rooms` 和 `aliases` 命名空间,所有匹配房间中的事件都会被发送给应用服务。 +{{% /boxes/note %}} + +{{% boxes/warning %}} +如果某主服务器上存在多个应用服务,则每个应用服务的 `as_token` 和 `id` *必须*唯一,这些项用于标识不同应用服务。主服务器*必须*强制执行此要求。 +{{% /boxes/warning %}} + +### 主服务器 -> 应用服务 API + +#### 授权 + +{{% changed-in v="1.4" %}} + +主服务器在向应用服务发出请求时,*必须*包含 `Authorization` 头,内容为注册文件中的 `hs_token`。应用服务*必须*校验所提供的 `Bearer` 令牌与其已知的 `hs_token` 是否匹配,若不匹配则以 `M_FORBIDDEN` 错误拒绝请求。 + +`Authorization` 头的格式类似于 [客户端-服务器 API](/client-server-api/#client-authentication): +`Bearer TheHSTokenGoesHere`. + +{{% boxes/note %}} +在本规范的早期版本中,曾使用 `access_token` 查询参数。服务器仅在兼容旧版本规范时需发送此查询参数。 + +如需发送 `query_string`,建议与 `Authorization` 头一同发送,以获得最大兼容性。 + +若两者均提供,应用服务应校验其值是否一致。 +{{% /boxes/note %}} + +#### 旧路由 + +早期规格的应用服务 API 混合定义了多种在实际部署中被采用的端点。当前应用服务规范对所有端点定义了版本,以便与 Matrix 其他规范及未来更好兼容。 + +主服务器在与应用服务通信时应优先尝试当前规范指定的端点,但若应用服务返回非成功的 HTTP 状态码(如 404、500、501 等),则主服务器应回退到旧端点。 + +旧端点和当前端点拥有完全相同的请求体和响应格式,只是路径不同。各端点的对应关系如下: + +- `/_matrix/app/v1/transactions/{txnId}` 回退到 `/transactions/{txnId}` +- `/_matrix/app/v1/users/{userId}` 回退到 `/users/{userId}` +- `/_matrix/app/v1/rooms/{roomAlias}` 回退到 `/rooms/{roomAlias}` +- `/_matrix/app/v1/thirdparty/protocol/{protocol}` 回退到 `/_matrix/app/unstable/thirdparty/protocol/{protocol}` +- `/_matrix/app/v1/thirdparty/user/{user}` 回退到 `/_matrix/app/unstable/thirdparty/user/{user}` +- `/_matrix/app/v1/thirdparty/location/{location}` 回退到 `/_matrix/app/unstable/thirdparty/location/{location}` +- `/_matrix/app/v1/thirdparty/user` 回退到 `/_matrix/app/unstable/thirdparty/user` +- `/_matrix/app/v1/thirdparty/location` 回退到 `/_matrix/app/unstable/thirdparty/location` + +主服务器应定期重试新版端点,因为应用服务可能已经升级。 + +#### 未知路由 + +如果收到对不受支持(或未知)端点的请求,服务器必须响应 404 `M_UNRECOGNIZED` 错误。 + +同样,对于已知端点但不支持的 HTTP 方法,应使用 405 `M_UNRECOGNIZED` 错误指示。 + +#### 推送事件 + +应用服务 API 提供事务接口以发送事件列表。每批事件都包含事务 ID,其运行机制如下: + +``` + 正常情况 + HS ---> AS : 主服务器以事务 ID T 发送事件。 + <--- : 应用服务返回 200 OK。 +``` + +``` + AS ACK 丢失 + HS ---> AS : 主服务器以事务 ID T 发送事件。 + <-/- : AS 200 OK 丢失。 + HS ---> AS : 主服务器以相同事务 ID T 重试。 + <--- : 应用服务返回 200 OK。若 AS 已处理过这些事件,可对请求 NO-OP(它可通过事务 ID 判断事件是否相同)。 +``` + +发送给应用服务的事件应为线性处理(仿佛来自事件流)。主服务器*必须*维护一个待发送给应用服务的事务队列。如果无法连接到应用服务,主服务器*应*指数退避,直至应用服务恢复可达。由于应用服务无法*修改*这些事件,主服务器可异步处理这些请求,不阻塞其它功能。主服务器在重试同一事务 ID 时*不得*修改(如增加额外)要发送的事件,因为应用服务可能已经处理过这些事件。 + +{{% http-api spec="application-service" api="transactions" %}} + +##### 推送临时数据 + +{{% added-in v="1.13" %}} + +若在[注册文件](#registration)中启用了 `receive_ephemeral` 设置,主服务器*必须*通过事务 API,通过请求体的 `ephemeral` 属性向应用服务发送与其相关的临时数据。此属性为数组,实际为客户端-服务器 [`/sync`](/client-server-api/#get_matrixclientv3sync) API 的 `presence` 和 `ephemeral` 部分的组合。 + +当前共可向应用服务传递三种事件类型: + +- **[`m.presence`](/client-server-api/#mpresence)**:如上下文要求,*必须*发送。例如,为与应用服务共享房间的用户,或匹配应用服务命名空间的用户发生的状态更新。 +- **[`m.typing`](/client-server-api/#mtyping)**:应用与普通事件相同的规则,*必须*发送。即应用服务需注册房间本身或对房间内某用户感兴趣。数据格式应与客户端-服务器 API 相同,但需在顶层增加 `room_id` 字段,指明事件所属房间。 +- **[`m.receipt`](/client-server-api/#mreceipt)**:应用与普通事件相同的规则,*必须*发送。数据格式与客户端-服务器 API 相同,并需在顶层增加 `room_id` 字段。针对[私有已读回执](/client-server-api/#private-read-receipts),只需针对匹配应用服务命名空间的用户发送。普通已读回执和线程已读回执则总会发送。 + +#### 心跳机制 + +{{% added-in v="1.7" %}} + +应用服务 API 包含心跳(ping)机制,以便应用服务确保主服务器能访问自身。应用服务可利用此机制检测错误配置并适当报告。 + +实现时应注意,遇到临时性故障(如应用服务先于主服务器启动)不应导致完全失效,而应平滑处理。 + +机制如下(为简洁省略了可读性错误信息): + +**正常情况** + +``` +AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"} + HS ---> AS : /_matrix/app/v1/ping {"transaction_id": "meow"} + HS <--- AS : 200 OK {} +AS <--- HS : 200 OK {"duration_ms": 123} +``` + +**`hs_token` 错误** + +``` +AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"} + HS ---> AS : /_matrix/app/v1/ping {"transaction_id": "meow"} + HS <--- AS : 403 Forbidden {"errcode": "M_FORBIDDEN"} +AS <--- HS : 502 Bad Gateway {"errcode": "M_BAD_STATUS", "status": 403, "body": "{\"errcode\": \"M_FORBIDDEN\"}"} +``` + +**无法连接至应用服务** + +``` +AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"} + HS -/-> AS : /_matrix/app/v1/ping {"transaction_id": "meow"} +AS <--- HS : 502 Bad Gateway {"errcode": "M_CONNECTION_FAILED"} +``` + +`/_matrix/app/v1/ping` 端点如上说明,[`/_matrix/client/v1/appservice/{appserviceId}/ping`](#post_matrixclientv1appserviceappserviceidping) 端点见下文客户端-服务器 API 扩展部分。 + +{{% http-api spec="application-service" api="ping" %}} + +#### 查询 + +应用服务 API 包含两个查询 API:房间别名与用户 ID。应用服务*应*在处理查询请求时自行创建所查询的实体。如果应用服务愿意,可主动创建实体。在此过程中,主服务器会阻塞直至实体被创建并配置完成。若主服务器未收到该请求的响应,应重试数次,最终超时。这样,发起请求的客户端会收到 HTTP 408 “请求超时”。 + +{{% boxes/rationale %}} +阻塞主服务器,并让应用服务通过客户端-服务器 API 创建实体,比返回 initial sync 风格的 JSON 数据让主服务器初始化房间/用户更简单灵活。同时,也无需建立“回传通道”通知应用服务有关实体的信息,如房间 ID 到别名的映射。 +{{% /boxes/rationale %}} + +{{% http-api spec="application-service" api="query_user" %}} + +{{% http-api spec="application-service" api="query_room" %}} + +#### 第三方网络 + +应用服务可通过向主服务器注册时的配置声明所支持的协议。这些网络通常为应用服务管理的第三方服务(如 IRC)。应用服务可为其注册协议填充 Matrix 房间目录,如客户端-服务器 API 扩展部分定义。 + +每种协议可包括若干“位置”(Location,亦称“第三方位置”或 “3PL”)。协议中的“位置”通常是第三方网络中的某处,如 IRC 频道。第三方网络上的用户也可由应用服务表示。 + +位置和用户可根据应用服务定义的字段检索,如显示名或其他属性。当客户端请求主服务器在特定“网络”(协议)中搜索时,搜索字段会被传递给应用服务进行筛选。 + +{{% http-api spec="application-service" api="protocols" %}} + +### 客户端-服务器 API 扩展 + +应用服务可通过向主服务器表明自身身份,使用更强大的客户端-服务器 API 版本。 + +本节定义的端点主服务器*必须*在客户端-服务器 API 中仅向应用服务开放。 + +#### 身份声明 + +客户端-服务器 API 通过每个请求中的 `access_token` 推断用户 ID。为避免应用服务需为每个用户维护 access_token,应用服务应同时以其 `as_token` 作为 `access_token`,并声明希望以哪一用户(属于应用服务命名空间的用户)伪装身份访问。 + +输入项: +- 应用服务令牌(`as_token`) +- 要模拟的应用服务命名空间内的用户 ID + +注意事项: +- 适用客户端-服务器 API 的所有方面,除帐户管理。 +- 把 `as_token` 赋值给 `access_token`,即通常客户端令牌所在的位置,如查询参数或 `Authorization` 头。这有助于应用服务复用客户端 SDK。 +- 推荐通过 `Authorization` 头提供 `access_token`,避免其出现在 HTTP 请求日志中。 + +应用服务可通过在请求 URL 中追加 `user_id` 查询字符串参数,指定虚拟用户。该 user_id 必须在应用服务的 `user` 命名空间范围内。若缺省,则主服务器假定应用服务希望以注册文件中 `sender_localpart` 所指定用户的身份操作。 + +请求示例: + + GET /_matrix/client/v3/account/whoami?user_id=@_irc_user:example.org + Authorization: Bearer YourApplicationServiceTokenHere + +#### 时间戳调整 + +{{% added-in v="1.3" %}} + +应用服务可以修改事件关联的时间戳,从而更准确地反映事件的“真实”发送时间。这不会影响事件在服务器端的顺序,但能更好地反映(如桥接服务因对方网络有延迟而希望为消息打上原始时间)的实际时间。 + +以应用服务身份认证请求时,可追加 `ts` 查询参数以变更结果事件的 `origin_server_ts`。如时间戳不被 `origin_server_ts` 接受,服务器应以错误请求拒绝。 + +如未指定,则服务器行为不变:以服务器本地系统时间打时间戳,视为“当前”。 + +`ts` 查询参数仅以下端点有效: + +* [`PUT /rooms/{roomId}/send/{eventType}/{txnId}`](/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid) +* [`PUT /rooms/{roomId}/state/{eventType}/{stateKey}`](/client-server-api/#put_matrixclientv3roomsroomidstateeventtypestatekey) + +其它端点(如 `/kick`)不支持 `ts`,如需类似行为请用 `PUT /state` 端点模拟。 + +{{% boxes/warning %}} +变更事件时间不会改变事件在服务器端(DAG)顺序。事件仍会像以“当前时间”发送那样添加到 DAG 顶端。未来的 MSC,如 [MSC2716](https://github.com/matrix-org/matrix-spec-proposals/pull/2716),预计会提供更彻底的 DAG 顺序操作功能(如历史导入等)。 +{{% /boxes/warning %}} + +#### 服务器管理员级权限 + +主服务器需赋予应用服务对其命名空间内所有用户和房间别名“完全控制”权限。这意味着应用服务应能管理命名空间内任意用户和房间别名。无需对房间别名控制权作额外 API 更改。 + +创建用户需要对 API 作如下调整: + +- 绕过验证码。 +- 支持“无密码”用户。 + +为此需完全绕过注册流程。方法是在 `/register` 请求中附带 `as_token`,以及登录类型 `m.login.application_service`,从而指定无需密码的目标用户 ID。 + + POST /_matrix/client/v3/register + Authorization: Bearer YourApplicationServiceTokenHere + + 内容: + { + type: "m.login.application_service", + username: "_irc_example" + } + +同样,应用服务以用户身份登录,也要允许在无需该用户密码的情况下完成。具体方法是在 `/login` 请求中附带 `as_token`,并指定登录类型 `m.login.application_service`: + +{{% added-in v="1.2" %}} + + POST /_matrix/client/v3/login + Authorization: Bearer YourApplicationServiceTokenHere + + 内容: + { + type: "m.login.application_service", + "identifier": { + "type": "m.id.user", + "user": "_irc_example" + } + } + +应用服务如试图*超出*其定义命名空间创建用户或别名,或以超出命名空间的用户登录,将会收到 `M_EXCLUSIVE` 错误码。 +同理,普通用户试图在*应用服务定义的*命名空间内创建用户或别名(且该命名空间为独占)同样会收到 `M_EXCLUSIVE` 错误码。 + +若带 `m.login.application_service` 登录类型的 `/register` 或 `/login` 请求未附带有效 `as_token`,将返回 `M_MISSING_TOKEN` 或 `M_UNKNOWN_TOKEN` 错误码,HTTP 状态码为 401。其行为与客户端-服务器 API 的无效认证相同(参见[使用访问令牌](/client-server-api/#using-access-tokens))。 + +#### 心跳 + +{{% added-in v="1.7" %}} + +这是[心跳机制](#pinging)的客户端-服务器 API 对应端点。 + +{{% http-api spec="client-server" api="appservice_ping" %}} + +#### 使用 `/sync` 和 `/events` + +希望使用客户端-服务器 API 的 `/sync` 或 `/events` 端点的应用服务,*必须*以虚拟用户身份访问(通过查询字符串提供 `user_id`)。建议应用服务通过推送事务的方式处理事件,而非以 `sender_localpart` 标识的用户同步。 + +#### 应用服务房间目录 + +应用服务可为其定义的第三方协议维护独立的房间目录。这些房间目录可通过客户端-服务器 API 的 `/publicRooms` 端点及额外参数由客户端访问。 + +{{% http-api spec="client-server" api="appservice_room_directory" %}} + +### 引用来自第三方网络的消息 + +应用服务应在所发送事件的 `content` 中包含 `external_url` 字段,用于指示消息来源。此字段主要用于桥接其它网络(如 IRC)的应用服务,通常会提供 HTTP URL 以供引用。 + +如果 `external_url` 存在,客户端应为用户提供访问该 URL 的方式。同时,客户端应确保 URL 的协议为 `https` 或 `http` 后再使用。 + +事件中出现 `external_url` 并不必然意味着事件来自应用服务。客户端在使用该 URL 时应保持警惕,因其可能不是事件来源的合法引用。 diff --git a/locales/zh-Hans/changelog/_index.md b/locales/zh-Hans/changelog/_index.md new file mode 100644 index 00000000..86ec1bd6 --- /dev/null +++ b/locales/zh-Hans/changelog/_index.md @@ -0,0 +1,12 @@ +--- +title: 更新日志 +type: docs +weight: 1000 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + + diff --git a/locales/zh-Hans/changelog/historical.md b/locales/zh-Hans/changelog/historical.md new file mode 100644 index 00000000..dded706b --- /dev/null +++ b/locales/zh-Hans/changelog/historical.md @@ -0,0 +1,51 @@ +--- +title: 历史版本 +type: docs +outputs: + - html +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +在 1.1 版本之前,版本控制应用于各个单独的 API 规范级别。本节包含了这些 API 版本的相关链接。 + +## 客户端-服务器 API + + - [r0.6.1](https://matrix.org/docs/spec/client_server/r0.6.1.html) + - [r0.6.0](https://matrix.org/docs/spec/client_server/r0.6.0.html) + - [r0.5.0](https://matrix.org/docs/spec/client_server/r0.5.0.html) + - [r0.4.0](https://matrix.org/docs/spec/client_server/r0.4.0.html) + - [r0.3.0](https://matrix.org/docs/spec/client_server/r0.3.0.html) + - [r0.2.0](https://matrix.org/docs/spec/client_server/r0.2.0.html) + - [r0.1.0](https://matrix.org/docs/spec/client_server/r0.1.0.html) + - [r0.0.1](https://matrix.org/docs/spec/r0.0.1/client_server.html) + - [r0.0.0](https://matrix.org/docs/spec/r0.0.0/client_server.html) + - [旧版](https://matrix.org/docs/spec/legacy/#client-server-api): + r0.0.0 正式发布前的最后一个规范草案。 + +## 服务器-服务器 API + + - [r0.1.4](https://matrix.org/docs/spec/server_server/r0.1.4.html) + - [r0.1.3](https://matrix.org/docs/spec/server_server/r0.1.3.html) + - [r0.1.2](https://matrix.org/docs/spec/server_server/r0.1.2.html) + - [r0.1.1](https://matrix.org/docs/spec/server_server/r0.1.1.html) + - [r0.1.0](https://matrix.org/docs/spec/server_server/r0.1.0.html) + +## 应用服务 API + + - [r0.1.1](https://matrix.org/docs/spec/application_service/r0.1.1.html) + - [r0.1.0](https://matrix.org/docs/spec/application_service/r0.1.0.html) + +## 身份服务 API + + - [r0.3.0](https://matrix.org/docs/spec/identity_service/r0.3.0.html) + - [r0.2.1](https://matrix.org/docs/spec/identity_service/r0.2.1.html) + - [r0.2.0](https://matrix.org/docs/spec/identity_service/r0.2.0.html) + - [r0.1.0](https://matrix.org/docs/spec/identity_service/r0.1.0.html) + +## 推送网关 API + + - [r0.1.0](https://matrix.org/docs/spec/push_gateway/r0.1.0.html) diff --git a/locales/zh-Hans/changelog/v1.1.md b/locales/zh-Hans/changelog/v1.1.md new file mode 100644 index 00000000..5c8a272d --- /dev/null +++ b/locales/zh-Hans/changelog/v1.1.md @@ -0,0 +1,142 @@ +--- +title: v1.1 更新日志 +linkTitle: v1.1 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2021-11-09 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务端 API + +重大变更 + +- 按照 [MSC2630](https://github.com/matrix-org/matrix-doc/pull/2630) 记录 `curve25519-hkdf-sha256` 作为 SAS 验证的密钥协商方法,并弃用旧方法。([#2687](https://github.com/matrix-org/matrix-doc/issues/2687)) +- 按照 [MSC2366](https://github.com/matrix-org/matrix-doc/pull/2366) 将 `m.key.verification.ready` 和 `m.key.verification.done` 加入密钥验证框架。([#3139](https://github.com/matrix-org/matrix-doc/issues/3139)) + +弃用事项 + +- 按照 [MSC3122](https://github.com/matrix-org/matrix-doc/pull/3122) 弃用未以 `m.key.verification.request` 开头的验证启动方式。([#3199](https://github.com/matrix-org/matrix-doc/issues/3199)) + +新增端点 + +- 按照 [MSC1219](https://github.com/matrix-org/matrix-doc/pull/1219) 添加密钥备份(`/room_keys/*`)端点。([#2387](https://github.com/matrix-org/matrix-doc/issues/2387), [#2639](https://github.com/matrix-org/matrix-doc/issues/2639)) +- 按照 [MSC1756](https://github.com/matrix-org/matrix-doc/pull/1756) 添加 `POST /keys/device_signing/upload` 和 `POST /keys/signatures/upload`。([#2536](https://github.com/matrix-org/matrix-doc/issues/2536)) +- 按照 [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403) 添加 `/knock` 端点。([#3154](https://github.com/matrix-org/matrix-doc/issues/3154)) +- 按照 [MSC2858](https://github.com/matrix-org/matrix-doc/pull/2858) 添加 `/login/sso/redirect/{idpId}`。([#3163](https://github.com/matrix-org/matrix-doc/issues/3163)) + +移除端点 + +- 按照 [MSC2610](https://github.com/matrix-org/matrix-doc/pull/2610) 和 [MSC2611](https://github.com/matrix-org/matrix-doc/pull/2611) 移除未实现的 `m.login.oauth2` 和 `m.login.token` 用户交互式认证机制。([#2609](https://github.com/matrix-org/matrix-doc/issues/2609)) + +向后兼容变更 + +- 按照 [MSC2399](https://github.com/matrix-org/matrix-doc/pull/2399) 记录客户端如何告知接收方其保留了解密密钥。([#2399](https://github.com/matrix-org/matrix-doc/issues/2399)) +- 按照 [MSC1756](https://github.com/matrix-org/matrix-doc/pull/1756) 向 `POST /keys/query` 响应中添加跨签名属性。([#2536](https://github.com/matrix-org/matrix-doc/issues/2536)) +- 按照 [MSC1946](https://github.com/matrix-org/matrix-doc/pull/1946) 和 [MSC2472](https://github.com/matrix-org/matrix-doc/pull/2472) 记录安全密钥存储与共享。([#2597](https://github.com/matrix-org/matrix-doc/issues/2597)) +- 按照 [MSC2604](https://github.com/matrix-org/matrix-doc/pull/2604) 向登录回退中添加 `device_id` 参数。([#2709](https://github.com/matrix-org/matrix-doc/issues/2709)) +- 为 SAS Emoji 新增了一套通用翻译。([#2728](https://github.com/matrix-org/matrix-doc/issues/2728)) +- 按照 [MSC2367](https://github.com/matrix-org/matrix-doc/pull/2367) 为所有成员事件及相关端点新增 `reason` 支持。([#2795](https://github.com/matrix-org/matrix-doc/issues/2795)) +- 按照 [MSC2663](https://github.com/matrix-org/matrix-doc/pull/2663) 向推送规则端点新增 404 `M_NOT_FOUND` 错误。([#2796](https://github.com/matrix-org/matrix-doc/issues/2796)) +- 按照 [MSC2414](https://github.com/matrix-org/matrix-doc/pull/2414) 使内容举报 API 中的 `reason` 和 `score` 参数可选。([#2807](https://github.com/matrix-org/matrix-doc/issues/2807)) +- 按照 [MSC2689](https://github.com/matrix-org/matrix-doc/pull/2689) 允许访客获取房间成员列表。([#2808](https://github.com/matrix-org/matrix-doc/issues/2808)) +- 按照 [MSC2010](https://github.com/matrix-org/matrix-doc/pull/2010) 和 [MSC2557](https://github.com/matrix-org/matrix-doc/pull/2557) 新增剧透支持,并按 [MSC2422](https://github.com/matrix-org/matrix-doc/pull/2422) 添加 `color` 属性。([#3098](https://github.com/matrix-org/matrix-doc/issues/3098)) +- 按照 [MSC2184](https://github.com/matrix-org/matrix-doc/pull/2184) 向建议的 HTML 子集添加 `
` 和 ``。([#3100](https://github.com/matrix-org/matrix-doc/issues/3100)) +- 按照 [MSC2241](https://github.com/matrix-org/matrix-doc/pull/2241) 新增基于房间内消息的密钥验证。([#3139](https://github.com/matrix-org/matrix-doc/issues/3139)、[#3150](https://github.com/matrix-org/matrix-doc/issues/3150)) +- 增补如何使用 SSSS 进行跨签名和密钥备份的信息。([#3147](https://github.com/matrix-org/matrix-doc/issues/3147)) +- 按照 [MSC1544](https://github.com/matrix-org/matrix-doc/pull/1544) 新增基于二维码的密钥验证方法。([#3149](https://github.com/matrix-org/matrix-doc/issues/3149)) +- 按照 [MSC2874](https://github.com/matrix-org/matrix-doc/pull/2874) 记录客户端如何简化安全密钥存储的使用。([#3151](https://github.com/matrix-org/matrix-doc/issues/3151)) +- 按照 [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403) 新增“敲门”功能(Knocking)支持。([#3154](https://github.com/matrix-org/matrix-doc/issues/3154), [#3254](https://github.com/matrix-org/matrix-doc/issues/3254)) +- 按照 [MSC2858](https://github.com/matrix-org/matrix-doc/pull/2858) 支持通过 `m.login.sso` 实现多 SSO 提供商。([#3163](https://github.com/matrix-org/matrix-doc/issues/3163)) +- 按照 [MSC2033](https://github.com/matrix-org/matrix-doc/pull/2033) 向 `/account/whoami` 响应中添加 `device_id`。([#3166](https://github.com/matrix-org/matrix-doc/issues/3166)) +- 按照 [MSC2284](https://github.com/matrix-org/matrix-doc/pull/2284) 对身份服务器发现失败降级为 `FAIL_PROMPT`。([#3169](https://github.com/matrix-org/matrix-doc/issues/3169)) +- 按照 [MSC2844](https://github.com/matrix-org/matrix-doc/pull/2844) 将所有端点的版本号重定为以 `v3` 为起点,而非 `r0`。([#3421](https://github.com/matrix-org/matrix-doc/issues/3421)) + +规范说明澄清 + +- 修复 `age` 和 `unsigned` 出现位置错误的问题。([#2591](https://github.com/matrix-org/matrix-doc/issues/2591)) +- 修正房间版本能力的定义。([#2592](https://github.com/matrix-org/matrix-doc/issues/2592)) +- 修复全规范文档内的多处拼写错误。([#2594](https://github.com/matrix-org/matrix-doc/issues/2594), [#2599](https://github.com/matrix-org/matrix-doc/issues/2599), [#2809](https://github.com/matrix-org/matrix-doc/issues/2809), [#2878](https://github.com/matrix-org/matrix-doc/issues/2878), [#2885](https://github.com/matrix-org/matrix-doc/issues/2885), [#2888](https://github.com/matrix-org/matrix-doc/issues/2888), [#3116](https://github.com/matrix-org/matrix-doc/issues/3116), [#3339](https://github.com/matrix-org/matrix-doc/issues/3339)) +- 澄清 OpenID Connect 规范链接。([#2605](https://github.com/matrix-org/matrix-doc/issues/2605)) +- 澄清 SSO 登录与 UI-Auth 的行为。([#2608](https://github.com/matrix-org/matrix-doc/issues/2608)) +- 从 `/sync` 示例中移除多余的 `room_id`。([#2629](https://github.com/matrix-org/matrix-doc/issues/2629)) +- 重组推送通知模块中的信息,使表述更清晰。([#2634](https://github.com/matrix-org/matrix-doc/issues/2634)) +- 改进事件 schema `title` 的一致性和清晰度。([#2647](https://github.com/matrix-org/matrix-doc/issues/2647)) +- 修正 `m.key.verification.accept` 和密钥存储中的 schema 问题。([#2653](https://github.com/matrix-org/matrix-doc/issues/2653)) +- 将"UI Authorization"重新表述为"User-Interactive Authentication"以增加清晰度。([#2667](https://github.com/matrix-org/matrix-doc/issues/2667)) +- 修正推送规则动作的 schema,以支持其替代的对象形式。([#2669](https://github.com/matrix-org/matrix-doc/issues/2669)) +- 修正 `highlight` tweak 的用法以保证一致。([#2670](https://github.com/matrix-org/matrix-doc/issues/2670)) +- 澄清带懒加载的 `/sync` 操作的 `state` 行为。([#2754](https://github.com/matrix-org/matrix-doc/issues/2754)) +- 澄清 `m.room.redaction` 事件的描述。([#2814](https://github.com/matrix-org/matrix-doc/issues/2814)) +- 标明在 `PUT /_matrix/client/r0/sendToDevice/{eventType}/{txnId}` 调用时 `messages` 是 JSON 主体必填字段。([#2928](https://github.com/matrix-org/matrix-doc/issues/2928)) +- 修正 `client_secret` 请求主体参数示例,避免包含无效字符。([#2985](https://github.com/matrix-org/matrix-doc/issues/2985)) +- 修正 `m.presence` 的 MXC URI 示例。([#3091](https://github.com/matrix-org/matrix-doc/issues/3091)) +- 按照 [MSC2801](https://github.com/matrix-org/matrix-doc/pull/2801) 澄清事件正文内容为不可信。([#3099](https://github.com/matrix-org/matrix-doc/issues/3099)) +- 修正事件最大大小限制(65535 字节→65536 字节)。([#3127](https://github.com/matrix-org/matrix-doc/issues/3127)) +- 更新 `Access-Control-Allow-Headers` 建议以符合 CORS 规范。([#3225](https://github.com/matrix-org/matrix-doc/issues/3225)) +- 明确指出 `m.room.tombstone` 事件中的 `replacement_room` 是房间 ID。([#3233](https://github.com/matrix-org/matrix-doc/issues/3233)) +- 澄清所有请求体均为必填项。([#3238](https://github.com/matrix-org/matrix-doc/issues/3238), [#3332](https://github.com/matrix-org/matrix-doc/issues/3332)) +- 为部分 schema 补充缺失的标题。([#3330](https://github.com/matrix-org/matrix-doc/issues/3330)) +- 按照 [MSC1756](https://github.com/matrix-org/matrix-doc/pull/1756) 向跨签名 API 添加用户交互式认证字段。([#3331](https://github.com/matrix-org/matrix-doc/issues/3331)) +- 指出如果房间是带别名创建的,应添加规范别名事件。([#3337](https://github.com/matrix-org/matrix-doc/issues/3337)) +- 向附录新增“API 约定”章节。([#3350](https://github.com/matrix-org/matrix-doc/issues/3350)) +- 澄清 `/sync`、`/rooms/{room_id}/messages`、`/initialSync`、`/rooms/{room_id}/initialSync` 及 `/notifications` 所用分页令牌的文档。([#3353](https://github.com/matrix-org/matrix-doc/issues/3353)) +- 移除不准确的“分页”章节。([#3366](https://github.com/matrix-org/matrix-doc/issues/3366)) +- 澄清 `redacted_because` 的工作原理。([#3411](https://github.com/matrix-org/matrix-doc/issues/3411)) +- 按照 [MSC2582](https://github.com/matrix-org/matrix-doc/pull/2582) 从 `EncryptedFile` 示例中移除多余的 `mimetype`。([#3412](https://github.com/matrix-org/matrix-doc/issues/3412)) +- 描述 [MSC2844](https://github.com/matrix-org/matrix-doc/pull/2844) 如何影响 `/versions` 端点。([#3420](https://github.com/matrix-org/matrix-doc/issues/3420)) +- 修正关于 `threepid_creds` 的文档错误。([#3471](https://github.com/matrix-org/matrix-doc/issues/3471)) + +## 服务器-服务器 API + +新增端点 + +- 按照 [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403) 添加 `/make_knock` 和 `/send_knock` 端点。([#3154](https://github.com/matrix-org/matrix-doc/issues/3154)) + +向后兼容变更 + +- 按照 [MSC1756](https://github.com/matrix-org/matrix-doc/pull/1756) 向 `GET /user/keys` 、`GET /user/devices/{userId}`、`m.device_list_update` EDU 以及新增的 `m.signing_key_update` EDU 中添加跨签名信息。([#2536](https://github.com/matrix-org/matrix-doc/issues/2536)) +- 按照 [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403) 支持“敲门”功能。([#3154](https://github.com/matrix-org/matrix-doc/issues/3154)) + +规范说明澄清 + +- 指明 `GET /_matrix/federation/v1/make_join/{roomId}/{userId}` 若房间未知可返回 404。([#2688](https://github.com/matrix-org/matrix-doc/issues/2688)) +- 修复全规范文档内的多处拼写错误。([#2888](https://github.com/matrix-org/matrix-doc/issues/2888), [#3116](https://github.com/matrix-org/matrix-doc/issues/3116), [#3128](https://github.com/matrix-org/matrix-doc/issues/3128), [#3207](https://github.com/matrix-org/matrix-doc/issues/3207)) +- 修正 `/_matrix/federation/v1/user/devices/{userId}` 实际返回 `"self_signing_key"` 而非 `"self_signing_keys"`。([#3312](https://github.com/matrix-org/matrix-doc/issues/3312)) +- 解释为何 SRV 委托情况下需使用 `` 的 TLS 证书而不是 ``。([#3322](https://github.com/matrix-org/matrix-doc/issues/3322)) +- 微调 PDU 示例图,更好地展示多重 `prev_events` 情况。([#3340](https://github.com/matrix-org/matrix-doc/issues/3340)) + +## 应用服务 API + +规范说明澄清 + +- 修复全规范文档内的多处拼写错误。([#2888](https://github.com/matrix-org/matrix-doc/issues/2888)) + +## 身份服务 API + +新增端点 + +- 按照 [MSC2320](https://github.com/matrix-org/matrix-doc/pull/2320) 添加 `GET /_matrix/identity/versions` API。([#3101](https://github.com/matrix-org/matrix-doc/issues/3101)) + +移除端点 + +- 按照 [MSC2713](https://github.com/matrix-org/matrix-doc/pull/2713) 移除 v1 身份服务 API,推荐使用 v2 API。([#3170](https://github.com/matrix-org/matrix-doc/issues/3170)) + +规范说明澄清 + +- 修复全规范文档内的多处拼写错误。([#2888](https://github.com/matrix-org/matrix-doc/issues/2888)) +- 按照 [MSC2265](https://github.com/matrix-org/matrix-doc/pull/2265) 澄清某些标识符在处理前必须先进行大小写归一化。([#3167](https://github.com/matrix-org/matrix-doc/issues/3167), [#3176](https://github.com/matrix-org/matrix-doc/issues/3176)) +- 描述 [MSC2844](https://github.com/matrix-org/matrix-doc/pull/2844) 如何影响 `/versions` 端点。([#3459](https://github.com/matrix-org/matrix-doc/issues/3459)) + +## 推送网关 API + +规范说明澄清 + +- 澄清通知端点各参数值获取的渠道。([#2763](https://github.com/matrix-org/matrix-doc/issues/2763)) diff --git a/locales/zh-Hans/changelog/v1.10.md b/locales/zh-Hans/changelog/v1.10.md new file mode 100644 index 00000000..36873091 --- /dev/null +++ b/locales/zh-Hans/changelog/v1.10.md @@ -0,0 +1,98 @@ +--- +title: v1.10 更新日志 +linkTitle: v1.10 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2024-03-22 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +**向后兼容的变更** + +- 允许 `/versions` 端点可选接受认证,详见 [MSC4026](https://github.com/matrix-org/matrix-spec-proposals/pull/4026)。([#1728](https://github.com/matrix-org/matrix-spec/issues/1728)) +- 增加本地删除请求,详见 [MSC4025](https://github.com/matrix-org/matrix-spec-proposals/pull/4025)。([#1730](https://github.com/matrix-org/matrix-spec/issues/1730)) +- 按照 [MSC2530](https://github.com/matrix-org/matrix-spec-proposals/pull/2530) 的规定,将 `body` 字段作为媒体可选说明使用。([#1731](https://github.com/matrix-org/matrix-spec/issues/1731)) +- 增加服务器支持能力发现端点,详见 [MSC1929](https://github.com/matrix-org/matrix-spec-proposals/pull/1929)。([#1733](https://github.com/matrix-org/matrix-spec/issues/1733)) +- 增加对多流 VoIP 的支持,详见 [MSC3077](https://github.com/matrix-org/matrix-spec-proposals/pull/3077)。([#1735](https://github.com/matrix-org/matrix-spec/issues/1735)) +- 指定 `Retry-After` 头部可用于限制客户端请求速率,详见 [MSC4041](https://github.com/matrix-org/matrix-spec-proposals/pull/4041)。([#1737](https://github.com/matrix-org/matrix-spec/issues/1737)) +- 为 `GET /relations` 端点增加递归支持,详见 [MSC3981](https://github.com/matrix-org/matrix-spec-proposals/pull/3981)。([#1746](https://github.com/matrix-org/matrix-spec/issues/1746)) + +**规范澄清** + +- [strike](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/strike) 元素在 HTML 规范中已废弃,客户端应优先使用 [s](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/s) 元素。([#1629](https://github.com/matrix-org/matrix-spec/issues/1629)) +- 明确已读回执应根据线程和房间进行批量处理。([#1685](https://github.com/matrix-org/matrix-spec/issues/1685)) +- 明确线程可以基于回复创建。([#1687](https://github.com/matrix-org/matrix-spec/issues/1687)) +- 在回复的回退示例中,明确每行都应重复使用前缀序列。([#1690](https://github.com/matrix-org/matrix-spec/issues/1690)) +- 明确加密密钥存储的账户数据对象格式。([#1695](https://github.com/matrix-org/matrix-spec/issues/1695),[#1734](https://github.com/matrix-org/matrix-spec/issues/1734)) +- 明确密钥备份 MAC 实现不正确,未将密文经过 HMAC-SHA-256 处理。([#1712](https://github.com/matrix-org/matrix-spec/issues/1712)) +- 明确示例中一次性密钥和回退密钥的类型。([#1715](https://github.com/matrix-org/matrix-spec/issues/1715)) +- 指明 SAS 的 HKDF 计算应使用 base64 编码密钥,而不是原始密钥字节。([#1719](https://github.com/matrix-org/matrix-spec/issues/1719)) +- 明确如何在 SAS 流程第 12 步执行 ECDH 交换。([#1720](https://github.com/matrix-org/matrix-spec/issues/1720)) +- 按照 [MSC4077](https://github.com/matrix-org/matrix-spec-proposals/pull/4077),说明 HTML 标签的弃用策略。([#1732](https://github.com/matrix-org/matrix-spec/issues/1732)) +- [font](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/font) 元素在 HTML 规范中已废弃,客户端应优先使用带 `data-mx-bg-color` 和 `data-mx-color` 属性的 [span](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/span) 元素。([#1739](https://github.com/matrix-org/matrix-spec/issues/1739)) +- 明确 `GET /hierarchy` 端点 `PublicRoomsChunk` 的具体用途。([#1740](https://github.com/matrix-org/matrix-spec/issues/1740)) +- 明确 `m.call.candidates` 中 `sdpMid` 和 `sdpMLineIndex` 非必需。([#1742](https://github.com/matrix-org/matrix-spec/issues/1742)) +- 修正规范文档中的各种错别字。([#1748](https://github.com/matrix-org/matrix-spec/issues/1748)) +- 明确每种 `Content-Type` 在非 JSON 请求/响应中的行为可能不同。([#1756](https://github.com/matrix-org/matrix-spec/issues/1756)) +- 按照 [MSC4010](https://github.com/matrix-org/matrix-spec-proposals/pull/4010),明确 `/account_data` API 不能用于设置 `m.push_rules` 账户数据类型。([#1763](https://github.com/matrix-org/matrix-spec/issues/1763)) + + +## 服务器-服务器 API + +**规范澄清** + +- 使用 `POST` HTTP 方法优化服务器-服务器 API 请求签名示例,因为 `GET` 请求没有请求体。([#1721](https://github.com/matrix-org/matrix-spec/issues/1721)) +- 明确 `GET /hierarchy` 端点中 `PublicRoomsChunk` 的具体用途。([#1740](https://github.com/matrix-org/matrix-spec/issues/1740)) +- 明确 `GET /hierarchy` 响应中 `children` 数组项的 `children_state`、`room_type` 和 `allowed_room_ids` 属性不是必需的。([#1741](https://github.com/matrix-org/matrix-spec/issues/1741)) + + +## 应用服务 API + +**规范澄清** + +- 明确当使用 `m.login.application_service` 登录类型且无效 `as_token` 时,`/login` 和 `/register` 端点应返回失败。([#1744](https://github.com/matrix-org/matrix-spec/issues/1744)) + + +## 身份服务 API + +无重大变更。 + + +## 推送网关 API + +无重大变更。 + + +## 房间版本 + +**规范澄清** + +- 针对房间版本 7 到 11:明确 `invite->knock` 不是合法的状态转移。([#1717](https://github.com/matrix-org/matrix-spec/issues/1717)) + + +## 附录 + +无重大变更。 + + +## 内部变更/工具 + +**规范澄清** + +- 更新规范发布流程。([#1680](https://github.com/matrix-org/matrix-spec/issues/1680)) +- 对贡献指南进行细微澄清。([#1697](https://github.com/matrix-org/matrix-spec/issues/1697)) +- 将 Docsy 升级至 v0.8.0。([#1699](https://github.com/matrix-org/matrix-spec/issues/1699),[#1762](https://github.com/matrix-org/matrix-spec/issues/1762)) +- 修复 `@matrix-org/spec` 的 npm 发布脚本。([#1713](https://github.com/matrix-org/matrix-spec/issues/1713)) +- 针对 MSC 的实现要求添加相关澄清说明。([#1718](https://github.com/matrix-org/matrix-spec/issues/1718)) +- 更新 HTML 模板以包含对象模式定义的链接。([#1724](https://github.com/matrix-org/matrix-spec/issues/1724)) +- 归纳整理 `/relations` 各类 API 的通用参数。([#1745](https://github.com/matrix-org/matrix-spec/issues/1745)) +- 在 OpenAPI 定义和 JSON schema 中增加对含有片段的 `$ref` URI 的支持。([#1751](https://github.com/matrix-org/matrix-spec/issues/1751),[#1754](https://github.com/matrix-org/matrix-spec/issues/1754)) diff --git a/locales/zh-Hans/changelog/v1.11.md b/locales/zh-Hans/changelog/v1.11.md new file mode 100644 index 00000000..5d2d3c30 --- /dev/null +++ b/locales/zh-Hans/changelog/v1.11.md @@ -0,0 +1,159 @@ +--- +title: v1.11 更新日志 +linkTitle: v1.11 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2024-06-20 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +**弃用说明** + +- 根据 [MSC4126](https://github.com/matrix-org/matrix-spec-proposals/issues/4126),通过查询字符串进行认证现已弃用,应改为使用 `Authorization` 头。([#1808](https://github.com/matrix-org/matrix-spec/issues/1808)) +- `/_matrix/media/*` 端点的使用现已弃用。已提供新的认证端点。([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) + +**新增端点** + +- [`GET /_matrix/client/v1/media/config`](/client-server-api/#get_matrixclientv1mediaconfig) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) +- [`GET /_matrix/client/v1/media/download/{serverName}/{mediaId}`](/client-server-api/#get_matrixclientv1mediadownloadservernamemediaid) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) +- [`GET /_matrix/client/v1/media/download/{serverName}/{mediaId}/{fileName}`](/client-server-api/#get_matrixclientv1mediadownloadservernamemediaidfilename) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) +- [`GET /_matrix/client/v1/media/preview_url`](/client-server-api/#get_matrixclientv1mediapreview_url) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) +- [`GET /_matrix/client/v1/media/thumbnail/{serverName}/{mediaId}`](/client-server-api/#get_matrixclientv1mediathumbnailservernamemediaid) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) + +**向后兼容更改** + +- 按照 [MSC3291](https://github.com/matrix-org/matrix-spec-proposals/pull/3291) 增加对 VoIP 通话静音功能的支持。([#1755](https://github.com/matrix-org/matrix-spec/issues/1755)) +- 按照 [MSC2705](https://github.com/matrix-org/matrix-spec-proposals/pull/2705) ,为 `GET /thumbnail` 增加可选的 `animated` 查询字符串选项。([#1757](https://github.com/matrix-org/matrix-spec/issues/1757)) +- 按照 [MSC1692](https://github.com/matrix-org/matrix-spec-proposals/pull/1692) ,在注册时指定服务条款。([#1812](https://github.com/matrix-org/matrix-spec/issues/1812)) +- 按照 [MSC2191](https://github.com/matrix-org/matrix-spec-proposals/pull/2191) ,增加对数学消息的支持。([#1816](https://github.com/matrix-org/matrix-spec/issues/1816)) +- 按照 [MSC3967](https://github.com/matrix-org/matrix-spec-proposals/pull/3967) ,首次上传交叉签名密钥时不再需要 UIA。([#1828](https://github.com/matrix-org/matrix-spec/issues/1828)) +- 按照 [MSC4115](https://github.com/matrix-org/matrix-spec-proposals/pull/4115) ,为事件添加新的 `unsigned.membership` 属性。([#1847](https://github.com/matrix-org/matrix-spec/issues/1847)) +- 按照 [MSC3916](https://github.com/matrix-org/matrix-spec-proposals/pull/3916) ,媒体下载和缩略图现需认证。([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) +- 按照 [MSC3916](https://github.com/matrix-org/matrix-spec-proposals/pull/3916) ,部分媒体端点已统一迁移至 `/_matrix/client/{version}/media/*`,不再使用 `/_matrix/media/*`。([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) + +**规范澄清** + +- 增加 `/logout` 端点,并明确哪些端点不需 JSON 请求体。([#1644](https://github.com/matrix-org/matrix-spec/issues/1644)) +- 明确 `POST /login` 请求的 `type` 必须为 `GET /login` 响应返回的类型之一。([#1776](https://github.com/matrix-org/matrix-spec/issues/1776)) +- 类型中链接现有语法(如适用)。([#1813](https://github.com/matrix-org/matrix-spec/issues/1813)) +- 将“恢复密钥”重命名为“备份解密密钥”。([#1819](https://github.com/matrix-org/matrix-spec/issues/1819)) +- 明确在二维码验证中应使用设备的 Ed25519 签名密钥(而非 Curve25519 身份密钥)。([#1829](https://github.com/matrix-org/matrix-spec/issues/1829)) +- 修复规范中的各种拼写错误。([#1832](https://github.com/matrix-org/matrix-spec/issues/1832), [#1841](https://github.com/matrix-org/matrix-spec/issues/1841), [#1852](https://github.com/matrix-org/matrix-spec/issues/1852), [#1853](https://github.com/matrix-org/matrix-spec/issues/1853)) +- 规范生成设备验证二维码时应使用的编码。([#1839](https://github.com/matrix-org/matrix-spec/issues/1839)) +- 明确在 `POST /account/password` 和 `POST /account/deactivate` 端点访问令牌为可选项。([#1843](https://github.com/matrix-org/matrix-spec/issues/1843)) +- 更一致地使用 RFC 2119 关键词。([#1846](https://github.com/matrix-org/matrix-spec/issues/1846), [#1861](https://github.com/matrix-org/matrix-spec/issues/1861)) +- 将用户、房间和事件 ID 的长度限制移至附录,并明确长度以字节为单位计量。([#1850](https://github.com/matrix-org/matrix-spec/issues/1850)) +- 明确关系递归应限制深度。([#1854](https://github.com/matrix-org/matrix-spec/issues/1854)) +- 在功能配置表中补充缺失的 secrets、第三方邀请及房间标签模块。([#1860](https://github.com/matrix-org/matrix-spec/issues/1860)) +- 明确服务器名称的使用时机并链接其定义。([#1862](https://github.com/matrix-org/matrix-spec/issues/1862)) +- 明确在检查 `m.room.encrypted` 事件时密钥的存放位置。([#1863](https://github.com/matrix-org/matrix-spec/issues/1863)) +- 明确 `/media/v3/upload/{serverName}/{mediaId}` 端点需要认证。([#1872](https://github.com/matrix-org/matrix-spec/issues/1872)) + +## 服务器-服务器 API + +**弃用说明** + +- 客户端-服务器 API 下的 `/_matrix/media/*` 端点使用现已弃用。已提供新的认证端点。([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) + +**新增端点** + +- [`GET /_matrix/federation/v1/media/download/{mediaId}`](/server-server-api/#get_matrixfederationv1mediadownloadmediaid) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) +- [`GET /_matrix/federation/v1/media/thumbnail/{mediaId}`](/server-server-api/#get_matrixfederationv1mediathumbnailmediaid) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) + +**向后兼容更改** + +- 按照 [MSC3916](https://github.com/matrix-org/matrix-spec-proposals/pull/3916) ,媒体下载和缩略图现需认证。([#1858](https://github.com/matrix-org/matrix-spec/issues/1858), [#1869](https://github.com/matrix-org/matrix-spec/issues/1869)) + +**规范澄清** + +- 类型中链接现有语法(如适用)。([#1813](https://github.com/matrix-org/matrix-spec/issues/1813)) +- 明确在 `X-Matrix` `Authorization` 头的参数列表中逗号前后允许存在空格。([#1818](https://github.com/matrix-org/matrix-spec/issues/1818)) +- 明确 `/v2/send_join` 响应的 `event` 字段仅在事件由本地服务器签名时才为必需。([#1834](https://github.com/matrix-org/matrix-spec/issues/1834), [#1840](https://github.com/matrix-org/matrix-spec/issues/1840)) +- 更新被 RFC 9110 替代的 RFC 7235 和 RFC 7230 引用。([#1844](https://github.com/matrix-org/matrix-spec/issues/1844)) +- 修复规范中的各种拼写错误。([#1877](https://github.com/matrix-org/matrix-spec/issues/1877)) + +## 应用服务 API + +**规范澄清** + +- 明确应用服务应收到与 `sender_localpart` 用户相关的事件通知。([#1810](https://github.com/matrix-org/matrix-spec/issues/1810)) + +## 身份服务 API + +**弃用说明** + +- 根据 [MSC4126](https://github.com/matrix-org/matrix-spec-proposals/issues/4126),通过查询字符串进行认证现已弃用,应改为使用 `Authorization` 头。([#1808](https://github.com/matrix-org/matrix-spec/issues/1808)) + +## 推送网关 API + +无重大更改。 + +## 房间版本 + +**规范澄清** + +- 明确撤回事件仍须遵守所有相关认证规则。([#1824](https://github.com/matrix-org/matrix-spec/issues/1824)) +- 修复规范中的各种拼写错误。([#1827](https://github.com/matrix-org/matrix-spec/issues/1827), [#1848](https://github.com/matrix-org/matrix-spec/issues/1848)) +- 修复房间版本 1 和 2 的事件格式渲染问题。([#1883](https://github.com/matrix-org/matrix-spec/issues/1883)) +- 使用 Hugo 而非 JavaScript 生成目录。([#1884](https://github.com/matrix-org/matrix-spec/issues/1884)) + +## 附录 + +**弃用说明** + +- 按照 [MSC4132](https://github.com/matrix-org/matrix-spec-proposals/pull/4132) ,弃用通过房间别名链接房间内事件的做法。([#1823](https://github.com/matrix-org/matrix-spec/issues/1823)) + +**规范澄清** + +- 定义“不透明标识符语法”。([#1791](https://github.com/matrix-org/matrix-spec/issues/1791)) +- 定义通用加密密钥表示。([#1819](https://github.com/matrix-org/matrix-spec/issues/1819)) +- 将用户、房间和事件 ID 的长度限制移至附录,并明确长度以字节为单位计量。([#1850](https://github.com/matrix-org/matrix-spec/issues/1850)) + +## 内部更改/工具 + +**规范澄清** + +- 更新规范发布流程及相关文档。([#1759](https://github.com/matrix-org/matrix-spec/issues/1759)) +- 修复 `@matrix-org/spec` 的 npm 发布脚本。([#1765](https://github.com/matrix-org/matrix-spec/issues/1765)) +- 修正 `CONTRIBUTING.rst` 中的格式问题。([#1769](https://github.com/matrix-org/matrix-spec/issues/1769)) +- 改善移动设备下的渲染效果。([#1770](https://github.com/matrix-org/matrix-spec/issues/1770), [#1771](https://github.com/matrix-org/matrix-spec/issues/1771)) +- 修正安全方案的 OpenAPI 定义。([#1772](https://github.com/matrix-org/matrix-spec/issues/1772)) +- 简化 `resolve-refs` partial 的使用。([#1773](https://github.com/matrix-org/matrix-spec/issues/1773)) +- 修复 Hugo 警告。([#1775](https://github.com/matrix-org/matrix-spec/issues/1775), [#1788](https://github.com/matrix-org/matrix-spec/issues/1788)) +- 修复 `github-labels.rst`。([#1781](https://github.com/matrix-org/matrix-spec/issues/1781)) +- 更新依赖项。([#1786](https://github.com/matrix-org/matrix-spec/issues/1786), [#1803](https://github.com/matrix-org/matrix-spec/issues/1803), [#1804](https://github.com/matrix-org/matrix-spec/issues/1804)) +- 在 OpenAPI 和 JSON Schemas 中递归解析 `allOf`。([#1787](https://github.com/matrix-org/matrix-spec/issues/1787)) +- 修正 `render-object-table` partial 属性类型解析。([#1789](https://github.com/matrix-org/matrix-spec/issues/1789)) +- 抽取出通用的 `Tag` 类型定义。([#1793](https://github.com/matrix-org/matrix-spec/issues/1793)) +- 将规范渲染所用 Hugo 版本升级至 v0.124.1。([#1794](https://github.com/matrix-org/matrix-spec/issues/1794)) +- 增加对 `patternProperties` 的模式格式支持。([#1796](https://github.com/matrix-org/matrix-spec/issues/1796)) +- 清理 OpenAPI 定义中不必要的 `allOf`。([#1797](https://github.com/matrix-org/matrix-spec/issues/1797)) +- 在对象表格中显示“附加属性”信息。([#1798](https://github.com/matrix-org/matrix-spec/issues/1798)) +- 修正 `oneOf` 下 schemas 的锚点。([#1799](https://github.com/matrix-org/matrix-spec/issues/1799)) +- 在 OpenAPI 定义中引用 `OneTimeKeys` schema。([#1800](https://github.com/matrix-org/matrix-spec/issues/1800)) +- 不对只包含 `additionalProperties` 或 `patternProperties` 的对象使用 `title`。([#1801](https://github.com/matrix-org/matrix-spec/issues/1801)) +- 在 `definition` shortcode 中添加锚点。([#1802](https://github.com/matrix-org/matrix-spec/issues/1802)) +- 为 Towncrier CI 任务设置 python 版本。([#1805](https://github.com/matrix-org/matrix-spec/issues/1805)) +- 在 CI 中用环境文件替换 `set-output`。([#1806](https://github.com/matrix-org/matrix-spec/issues/1806)) +- 渲染响应头信息。([#1809](https://github.com/matrix-org/matrix-spec/issues/1809)) +- 更多地方在受支持格式下使用 `patternProperties`。([#1813](https://github.com/matrix-org/matrix-spec/issues/1813)) +- 增加对字符串格式渲染的支持。([#1814](https://github.com/matrix-org/matrix-spec/issues/1814)) +- 重构内容存储库端点的 OpenAPI 定义。([#1822](https://github.com/matrix-org/matrix-spec/issues/1822)) +- 清理拉取请求模板。([#1831](https://github.com/matrix-org/matrix-spec/issues/1831)) +- 示例中不再添加空数组。([#1849](https://github.com/matrix-org/matrix-spec/issues/1849)) +- 使用 Hugo 而非 JavaScript 生成目录。([#1851](https://github.com/matrix-org/matrix-spec/issues/1851), [#1885](https://github.com/matrix-org/matrix-spec/issues/1885)) +- 修正规范发布议题模板中的语法错误。([#1856](https://github.com/matrix-org/matrix-spec/issues/1856)) +- Netlify 构建任务使用环境变量。([#1865](https://github.com/matrix-org/matrix-spec/issues/1865)) +- 在请求与响应内容类型信息中渲染新增/变更内容。([#1876](https://github.com/matrix-org/matrix-spec/issues/1876)) +- 修正生成 HTML 的验证错误。([#1880](https://github.com/matrix-org/matrix-spec/issues/1880)) +- 确保大部分生成的 HTML ID 唯一。([#1881](https://github.com/matrix-org/matrix-spec/issues/1881)) +- 允许为 API 端点生成的 HTML ID 指定前缀。([#1882](https://github.com/matrix-org/matrix-spec/issues/1882)) diff --git a/locales/zh-Hans/changelog/v1.12.md b/locales/zh-Hans/changelog/v1.12.md new file mode 100644 index 00000000..69cf109e --- /dev/null +++ b/locales/zh-Hans/changelog/v1.12.md @@ -0,0 +1,118 @@ +--- +title: v1.12 变更日志 +linkTitle: v1.12 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2024-10-07 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +**弃用** + +- 按照 [MSC4156](https://github.com/matrix-org/matrix-spec-proposals/pull/4156) 的规定,弃用 `POST /_matrix/client/v3/join/{roomIdOrAlias}` 和 `POST /_matrix/client/v3/knock/{roomIdOrAlias}` 接口中的 `server_name` 查询参数。([#1933](https://github.com/matrix-org/matrix-spec/issues/1933)) + +**移除的接口** + +- 移除对设备专属推送规则的引用。([#1842](https://github.com/matrix-org/matrix-spec/issues/1842)) +- 按照 [MSC4159](https://github.com/matrix-org/matrix-spec-proposals/pull/4159) 的规定,移除 HTML 锚点元素中已弃用的 name 属性。([#1870](https://github.com/matrix-org/matrix-spec/issues/1870)) + +**向后兼容的变更** + +- 按照 [MSC4170](https://github.com/matrix-org/matrix-spec-proposals/pull/4170) 的规定,在 `GET /_matrix/client/v3/profile/{userId}/avatar_url` 和 `GET /_matrix/client/v3/profile/{userId}/displayname` 接口中新增 403 响应。([#1867](https://github.com/matrix-org/matrix-spec/issues/1867)) +- 按照 [MSC2867](https://github.com/matrix-org/matrix-spec-proposals/pull/2867),新增对房间标记为未读的支持。([#1895](https://github.com/matrix-org/matrix-spec/issues/1895), [#1941](https://github.com/matrix-org/matrix-spec/issues/1941)) +- 按照 [MSC4156](https://github.com/matrix-org/matrix-spec-proposals/pull/4156),在 `POST /_matrix/client/v3/join/{roomIdOrAlias}` 和 `POST /_matrix/client/v3/knock/{roomIdOrAlias}` 接口中新增 `via` 查询参数。([#1933](https://github.com/matrix-org/matrix-spec/issues/1933)) +- 按照 [MSC3939](https://github.com/matrix-org/matrix-spec-proposals/pull/3939),新增账户锁定功能。([#1934](https://github.com/matrix-org/matrix-spec/issues/1934)) +- 按照 [MSC4189](https://github.com/matrix-org/matrix-spec-proposals/pull/4189),访客账户现可通过新认证接口下载/获取媒体缩略图。([#1959](https://github.com/matrix-org/matrix-spec/issues/1959)) + +**规范澄清** + +- 重命名并排序特性概要表中的模块,以便于浏览。([#1855](https://github.com/matrix-org/matrix-spec/issues/1855)) +- 明确房间头像不可加密。([#1871](https://github.com/matrix-org/matrix-spec/issues/1871)) +- 记录“Secrets”部分的缩写及别名。([#1875](https://github.com/matrix-org/matrix-spec/issues/1875)) +- 提高事务 ID 生成建议的准确性。([#1888](https://github.com/matrix-org/matrix-spec/issues/1888)) +- 明确说明已弃用的 `dont_notify` 和 `coalesce` 推送动作必须被忽略而非拒绝。([#1890](https://github.com/matrix-org/matrix-spec/issues/1890)) +- 修复规范中各处的拼写错误。([#1892](https://github.com/matrix-org/matrix-spec/issues/1892)) +- 在功能表中补充缺失的 `m.set_displayname`、`m.set_avatar_url` 和 `m.3pid_changes` 的引用。([#1897](https://github.com/matrix-org/matrix-spec/issues/1897)) +- 明确回退登录页面调用的是 `window.matrixLogin.onLogin` 而非 `window.onLogin`。([#1899](https://github.com/matrix-org/matrix-spec/issues/1899)) +- 移除有关无任何有效条件的受限房间的混淆性描述。([#1903](https://github.com/matrix-org/matrix-spec/issues/1903)) +- 明确 `window.matrixLogin.onLogin` 调用时传递的是 `POST /_matrix/client/v3/login` 的响应体。([#1905](https://github.com/matrix-org/matrix-spec/issues/1905)) +- 按照 [MSC3882](https://github.com/matrix-org/matrix-spec-proposals/pull/3882),记录 `m.get_login_token` 能力。([#1908](https://github.com/matrix-org/matrix-spec/issues/1908)) +- 明确 `POST /_matrix/client/v3/login` 中的“用户标识符”对象包含依赖标识类型的其他属性。([#1909](https://github.com/matrix-org/matrix-spec/issues/1909)) +- 不再特别说明 `GET /_matrix/client/v3/profile/{userId}` 可以返回附加属性,因为几乎所有接口都如此。([#1910](https://github.com/matrix-org/matrix-spec/issues/1910)) +- 改进未认证媒体弃用提示框的描述,贡献者:@HarHarLinks。([#1916](https://github.com/matrix-org/matrix-spec/issues/1916)) +- `GET /.well-known/matrix/client` 中的附加属性不再强制要求为对象类型。([#1920](https://github.com/matrix-org/matrix-spec/issues/1920)) +- 记录规范中使用了 [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) 关键词。贡献者:@HarHarLinks。([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) +- 按照 [MSC2701](https://github.com/matrix-org/matrix-spec-proposals/pull/2701) 与 [MSC2702](https://github.com/matrix-org/matrix-spec-proposals/pull/2702),明确媒体库中 `Content-Type` 和 `Content-Disposition` 的用法。([#1935](https://github.com/matrix-org/matrix-spec/issues/1935)) +- `GET /_matrix/client/v3/capabilities` 的附加键值不再强制要求为对象类型。([#1945](https://github.com/matrix-org/matrix-spec/issues/1945)) + + +## 服务器-服务器 API + +**向后兼容的变更** + +- 按照 [MSC4170](https://github.com/matrix-org/matrix-spec-proposals/pull/4170),在 `GET /_matrix/federation/v1/query/profile` 接口中新增 403 响应。([#1867](https://github.com/matrix-org/matrix-spec/issues/1867)) + +**规范澄清** + +- 因已不再出现在 schema,移除 PDU 示例中的 `origin` 字段。([#1918](https://github.com/matrix-org/matrix-spec/issues/1918)) +- 记录规范中使用了 [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) 关键词。贡献者:@HarHarLinks。([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) +- 修正 `GET /_matrix/key/v2/server` 响应 schema 中的必需字段。([#1930](https://github.com/matrix-org/matrix-spec/issues/1930)) +- 用“服务器名称”替代“DNS 名称”,以避免和附录中定义的“服务器名称”包含的“DNS 名称”混淆。([#1946](https://github.com/matrix-org/matrix-spec/issues/1946)) + + +## 应用服务 API + +**规范澄清** + +- 记录规范中使用了 [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) 关键词。贡献者:@HarHarLinks。([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) + + +## 身份验证服务 API + +**规范澄清** + +- 记录规范中使用了 [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) 关键词。贡献者:@HarHarLinks。([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) + + +## 推送网关 API + +**规范澄清** + +- 记录规范中使用了 [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) 关键词。贡献者:@HarHarLinks。([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) + + +## 房间版本 + +**规范澄清** + +- 修复 state resolution v2 中的格式问题。([#1896](https://github.com/matrix-org/matrix-spec/issues/1896)) +- 记录规范中使用了 [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) 关键词。贡献者:@HarHarLinks。([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) + + +## 附录 + +**规范澄清** + +- 记录规范中使用了 [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) 关键词。贡献者:@HarHarLinks。([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) + + +## 内部变更/工具链 + +**规范澄清** + +- Matrix.org 基金会不再要求贡献者需提供“真实”或“法律可识别”的姓名。([#1886](https://github.com/matrix-org/matrix-spec/issues/1886), [#1914](https://github.com/matrix-org/matrix-spec/issues/1914)) +- 记录 `removal` 变更日志分类。([#1907](https://github.com/matrix-org/matrix-spec/issues/1907)) +- 启用专用字体以更好地支持数学符号。([#1919](https://github.com/matrix-org/matrix-spec/issues/1919)) +- 记录规范中使用了 [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) 关键词。贡献者:@HarHarLinks。([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) +- 为变更日志在 `/changelog/$VERSION/checklist.md` 下提供 markdown 检查表。([#1937](https://github.com/matrix-org/matrix-spec/issues/1937), [#1954](https://github.com/matrix-org/matrix-spec/issues/1954)) +- 在 OpenAPI 定义和 JSON Schema 属性中新增 `deprecated` 字段。([#1940](https://github.com/matrix-org/matrix-spec/issues/1940)) +- 使用相对永久链接跳转到最新变更日志。([#1956](https://github.com/matrix-org/matrix-spec/issues/1956)) diff --git a/locales/zh-Hans/changelog/v1.13.md b/locales/zh-Hans/changelog/v1.13.md new file mode 100644 index 00000000..e9cc0ed6 --- /dev/null +++ b/locales/zh-Hans/changelog/v1.13.md @@ -0,0 +1,113 @@ +--- +title: v1.13 更新日志 +linkTitle: v1.13 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2024-12-19 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +**新增端点** + +- 增加 `POST /_matrix/client/v3/rooms/{roomId}/report`,参见 [MSC4151](https://github.com/matrix-org/matrix-spec-proposals/pull/4151)。([#1938](https://github.com/matrix-org/matrix-spec/issues/1938)、[#2028](https://github.com/matrix-org/matrix-spec/issues/2028)) + +**向后兼容的修改** + +- 为 requestToken 端点新增错误码,参见 [MSC4178](https://github.com/matrix-org/matrix-spec-proposals/pull/4178)。([#1944](https://github.com/matrix-org/matrix-spec/issues/1944)) +- 移除回复降级处理,参见 [MSC2781](https://github.com/matrix-org/matrix-spec-proposals/issues/2781)。([#1994](https://github.com/matrix-org/matrix-spec/issues/1994)) +- 明确 CORS 响应中允许的 HTTP 方法,参见 [MSC4138](https://github.com/matrix-org/matrix-spec-proposals/pull/4138)。([#1995](https://github.com/matrix-org/matrix-spec/issues/1995)、[#2011](https://github.com/matrix-org/matrix-spec/issues/2011)) +- 新增 `M_USER_SUSPENDED` 错误码行为,参见 [MSC3823](https://github.com/matrix-org/matrix-spec-proposals/pull/3823)。([#2014](https://github.com/matrix-org/matrix-spec/issues/2014)) + +**规范澄清** + +- 在 `POST /_matrix/client/v3/rooms/{roomId}/report/{eventId}` 接口中,`reason` 参数可以省略而不是留空,参见 [MSC2414](https://github.com/matrix-org/matrix-spec-proposals/pull/2414)。([#1938](https://github.com/matrix-org/matrix-spec/issues/1938)) +- 修正 `GET /_matrix/client/v3/thirdparty/location/{protocol}` 端点中查询参数的 OpenAPI 规范。([#1947](https://github.com/matrix-org/matrix-spec/issues/1947)) +- 语义化排序 VoIP 事件。([#1967](https://github.com/matrix-org/matrix-spec/issues/1967)) +- 明确服务器在向推送网关发送通知时必须转发 `PusherData` 中的自定义键值对。([#1973](https://github.com/matrix-org/matrix-spec/issues/1973)) +- 明确字符串类型的格式。([#1978](https://github.com/matrix-org/matrix-spec/issues/1978)、[#1979](https://github.com/matrix-org/matrix-spec/issues/1979)、[#1980](https://github.com/matrix-org/matrix-spec/issues/1980)) +- 明确异步上传端点在某些情况下会返回 404。([#1983](https://github.com/matrix-org/matrix-spec/issues/1983)) +- 移除 `StateFilter` 与 `RoomEventFilter` 之间的区别。([#2015](https://github.com/matrix-org/matrix-spec/issues/2015)) +- 在整个规范中增加超链接。([#2016](https://github.com/matrix-org/matrix-spec/issues/2016)) +- 语法高亮从 `json5` 改为 `json`。([#2017](https://github.com/matrix-org/matrix-spec/issues/2017)) +- 指定 `/keys/claim` 发放一次性密钥的顺序,参见 [MSC4225](https://github.com/matrix-org/matrix-spec-proposals/pull/4225)。([#2029](https://github.com/matrix-org/matrix-spec/issues/2029)) + + +## 服务器-服务器 API + +**向后兼容的修改** + +- 使 ACL 应用于 EDU,参见 [MSC4163](https://github.com/matrix-org/matrix-spec-proposals/pull/4163)。([#2004](https://github.com/matrix-org/matrix-spec/issues/2004)) + +**规范澄清** + +- 为 `/_matrix/federation/v1/state_ids/{roomId}` 增加 403 错误响应。([#1926](https://github.com/matrix-org/matrix-spec/issues/1926)) + + +## 应用服务 API + +**向后兼容的修改** + +- 允许向应用服务发送临时数据,参见 [MSC2409](https://github.com/matrix-org/matrix-spec-proposals/pull/2409)。([#2018](https://github.com/matrix-org/matrix-spec/issues/2018)) + + +## 身份服务 API + +无重大更改。 + + +## 推送网关 API + +**规范澄清** + +- 记录 `PusherData` 的数据结构。([#1968](https://github.com/matrix-org/matrix-spec/issues/1968)) +- HTTP pusher URL 的路径固定为 `/_matrix/push/v1/notify`。([#1974](https://github.com/matrix-org/matrix-spec/issues/1974)) + + +## 房间版本 + +**规范澄清** + +- 澄清房间版本 11 授权规则的 4.3.1 条,明确需要匹配哪个事件的 `sender` 和 `state_key`。([#2024](https://github.com/matrix-org/matrix-spec/issues/2024)) + + +## 附录 + +**规范澄清** + +- 移除关于参考实现的说明。([#1966](https://github.com/matrix-org/matrix-spec/issues/1966)) + + +## 内部变更/工具 + +**规范澄清** + +- 为使用 `event-group` 短代码渲染的事件排序新增 `x-weight` 属性。([#1967](https://github.com/matrix-org/matrix-spec/issues/1967)) +- 强制端点定义各段落之间的垂直间距一致。([#1969](https://github.com/matrix-org/matrix-spec/issues/1969)、[#2005](https://github.com/matrix-org/matrix-spec/issues/2005)) +- 移除 `boxes/added-in-paragraph` 短代码。([#1970](https://github.com/matrix-org/matrix-spec/issues/1970)) +- 移除 `rver-fragment` 短代码的 `withVersioning` 参数。([#1971](https://github.com/matrix-org/matrix-spec/issues/1971)) +- 从 `added-in` 和 `changed-in` 短代码中移除 `span` 元素。([#1972](https://github.com/matrix-org/matrix-spec/issues/1972)) +- 通过使用 `%` 分隔符修正 `added-in` 与 `changed-in` 短代码的格式化问题。([#1975](https://github.com/matrix-org/matrix-spec/issues/1975)) +- 移除有关滚动锚点的 CSS 兼容性处理。([#1976](https://github.com/matrix-org/matrix-spec/issues/1976)) +- 将 `custom-formats.yaml` 重命名为 `string-formats.yaml`,并更新相关文档。([#1977](https://github.com/matrix-org/matrix-spec/issues/1977)) +- 在使用自定义 `baseURL` 时修正规范的相对链接。([#1984](https://github.com/matrix-org/matrix-spec/issues/1984)、[#1997](https://github.com/matrix-org/matrix-spec/issues/1997)) +- 将 `.htmltest.yaml` 重命名为 `.htmltest.yml`。([#1985](https://github.com/matrix-org/matrix-spec/issues/1985)) +- 改进 JS 脚本以高亮当前目录项。([#1991](https://github.com/matrix-org/matrix-spec/issues/1991)、[#2002](https://github.com/matrix-org/matrix-spec/issues/2002)) +- 将 docsy 升级到 0.11.0,hugo 升级到 0.139.0。([#1996](https://github.com/matrix-org/matrix-spec/issues/1996)、[#2007](https://github.com/matrix-org/matrix-spec/issues/2007)) +- 提高渲染图表的质量([#1999](https://github.com/matrix-org/matrix-spec/issues/1999)) +- 更新 Inter 字体,并允许浏览器在字体加载前先渲染页面([#2000](https://github.com/matrix-org/matrix-spec/issues/2000)) +- 使用正式的 Matrix favicon([#2001](https://github.com/matrix-org/matrix-spec/issues/2001)) +- 清理 `openapi/render-operation` 局部模板中未使用的 CSS 类。([#2003](https://github.com/matrix-org/matrix-spec/issues/2003)) +- 修正 `changed-in` 局部模板在多段落场景下的表现。([#2006](https://github.com/matrix-org/matrix-spec/issues/2006)) +- 通过移除未使用的选择器优化生成的 CSS。([#2008](https://github.com/matrix-org/matrix-spec/issues/2008)) +- 在 void 类型 HTML 元素上去除多余的斜杠。([#2009](https://github.com/matrix-org/matrix-spec/issues/2009)) +- 移除 `script` 元素的 `type` 和 `language` 属性。([#2021](https://github.com/matrix-org/matrix-spec/issues/2021)) +- 修改信息框的无障碍访问角色为 `note`。([#2022](https://github.com/matrix-org/matrix-spec/issues/2022)) diff --git a/locales/zh-Hans/changelog/v1.14.md b/locales/zh-Hans/changelog/v1.14.md new file mode 100644 index 00000000..c46ab8f9 --- /dev/null +++ b/locales/zh-Hans/changelog/v1.14.md @@ -0,0 +1,98 @@ +--- +title: v1.14 变更日志 +linkTitle: v1.14 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2025-03-27 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +**新增端点** + +- 按照 [MSC4260](https://github.com/matrix-org/matrix-spec-proposals/pull/4260) 添加 `POST /_matrix/client/v3/users/{userId}/report`。([#2093](https://github.com/matrix-org/matrix-spec/issues/2093)) + +**移除端点** + +- 按照 [MSC4213](https://github.com/matrix-org/matrix-spec-proposals/pull/4213),从 `/_matrix/client/v3/join/{roomIdOrAlias}` 和 `/_matrix/client/v3/knock/{roomIdOrAlias}` 中移除 `server_name` 参数。([#2059](https://github.com/matrix-org/matrix-spec/issues/2059)) + +**规范澄清** + +- `POST /_matrix/client/v3/rooms/{roomId}/initialSync` 端点不再弃用,因为它仍用于窥视。([#2036](https://github.com/matrix-org/matrix-spec/issues/2036)) +- 明确 `/join` 端点摘要和描述中的措辞。贡献者:@HarHarLinks。([#2038](https://github.com/matrix-org/matrix-spec/issues/2038)) +- 明确字符串类型的格式。([#2046](https://github.com/matrix-org/matrix-spec/issues/2046)) +- 修正规范中的各种拼写错误。([#2047](https://github.com/matrix-org/matrix-spec/issues/2047)、[#2048](https://github.com/matrix-org/matrix-spec/issues/2048)、[#2080](https://github.com/matrix-org/matrix-spec/issues/2080)、[#2091](https://github.com/matrix-org/matrix-spec/issues/2091)) +- 在 `GET /_matrix/client/v3/thirdparty/protocols` 和 `GET /_matrix/client/v3/thirdparty/protocol/{protocol}` 的响应中,记录 `Protocol Instance` 的 `instance_id` 字段。([#2051](https://github.com/matrix-org/matrix-spec/issues/2051)) +- 客户端对擦除(redaction)的应用为 SHOULD。([#2055](https://github.com/matrix-org/matrix-spec/issues/2055)) +- 明确 `/hierarchy` 返回了哪些房间。([#2064](https://github.com/matrix-org/matrix-spec/issues/2064)) +- 创建房间时,客户端可自行决定向用户提供哪些历史可见性选项。([#2072](https://github.com/matrix-org/matrix-spec/issues/2072)) + + +## 服务器-服务器 API + +**规范澄清** + +- 移除 `PUT /send_join` 响应中的 `origin` 字段,因为它从未实际发送过。([#2050](https://github.com/matrix-org/matrix-spec/issues/2050)) +- 明确 `m.join_rules` 应包含于 `membership` 为 `knock` 的 `m.room.member` 事件的 `auth_events` 中。([#2063](https://github.com/matrix-org/matrix-spec/issues/2063)) +- 移除部分示例中错误的 `room_id` 字段。([#2076](https://github.com/matrix-org/matrix-spec/issues/2076)) + + +## 应用服务 API + +无重大变化。 + + +## 身份服务 API + +无重大变化。 + + +## 推送网关 API + +无重大变化。 + + +## 房间版本 + +**向后兼容的更改** + +- 按照 [MSC4239](https://github.com/matrix-org/matrix-spec-proposals/pull/4239),将默认房间版本更新为 11。([#2105](https://github.com/matrix-org/matrix-spec/issues/2105)) + +**规范澄清** + +- 针对房间版本 6 和 7,在授权规则中明确必须检查 `m.federate` 且对于包含被拒绝的授权事件的事件也须拒绝,以符合其他所有房间版本的标准。([#2065](https://github.com/matrix-org/matrix-spec/issues/2065)) +- 修正规范中的各种拼写错误。([#2066](https://github.com/matrix-org/matrix-spec/issues/2066)) +- 重构 PDU 定义以减少重复。([#2070](https://github.com/matrix-org/matrix-spec/issues/2070)) +- 明确房间版本 6、7、8、9、10 和 11 的最大 `depth` 值。([#2114](https://github.com/matrix-org/matrix-spec/issues/2114)) + + +## 附录 + +**规范澄清** + +- 明确用户/房间 ID 及房间别名中允许使用任意 Unicode 字符。([#1506](https://github.com/matrix-org/matrix-spec/issues/1506)) + + +## 内部更改/工具支持 + +**规范澄清** + +- 使用 Hugo 生成变更日志的发布信息,取代原有的变更日志生成脚本。([#2033](https://github.com/matrix-org/matrix-spec/issues/2033)) +- 更新发布步骤相关文档。([#2041](https://github.com/matrix-org/matrix-spec/issues/2041)) +- 从 Hugo 配置中移除未使用的 `release_date`。([#2042](https://github.com/matrix-org/matrix-spec/issues/2042)) +- 明确 Matrix v1.0 是在现有全局版本管理系统之前的一个发布版本。([#2045](https://github.com/matrix-org/matrix-spec/issues/2045)) +- 修复通过消除多余 CSS 来提升代码块语法高亮和一键复制按钮体验。([#2049](https://github.com/matrix-org/matrix-spec/issues/2049)) +- 修复 Matrix 1.0 引入时身份服务 API 的版本问题。([#2061](https://github.com/matrix-org/matrix-spec/issues/2061)) +- 修复 `resolve-refs` 和 `resolve-allof` 局部处理中的嵌套切片解析。([#2069](https://github.com/matrix-org/matrix-spec/issues/2069)) +- 对 `RoomKeysUpdateResponse` 的定义去重。([#2073](https://github.com/matrix-org/matrix-spec/issues/2073)) +- 对 `Invite3pid` 的定义去重。([#2074](https://github.com/matrix-org/matrix-spec/issues/2074)) +- 支持在 OpenAPI 定义及 JSON schema 中更灵活地放置示例。([#2076](https://github.com/matrix-org/matrix-spec/issues/2076)) +- 为不稳定变更日志添加指向 Git 提交的链接。([#2078](https://github.com/matrix-org/matrix-spec/issues/2078)) diff --git a/locales/zh-Hans/changelog/v1.2.md b/locales/zh-Hans/changelog/v1.2.md new file mode 100644 index 00000000..58e2878a --- /dev/null +++ b/locales/zh-Hans/changelog/v1.2.md @@ -0,0 +1,117 @@ +--- +title: v1.2 更新日志 +linkTitle: v1.2 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2022-02-02 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +不兼容变更 + +- 根据 [MSC3442](https://github.com/matrix-org/matrix-doc/pull/3442),`prev_content` 字段现在作为事件的 `unsigned` 属性返回,而不是顶层返回。([#3524](https://github.com/matrix-org/matrix-doc/issues/3524)) +- 按照 [MSC2432](https://github.com/matrix-org/matrix-doc/pull/2432),从 `/publicRooms` 返回的数据块中移除了 `aliases` 属性。([#3624](https://github.com/matrix-org/matrix-doc/issues/3624)) + +新增接口 + +- 增加空间层级 API (`GET /_matrix/client/v1/rooms/{roomId}/hierarchy`),参见 [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946)。([#3610](https://github.com/matrix-org/matrix-doc/issues/3610)) +- 增加 `/_matrix/client/v1/register/m.login.registration_token/validity` 接口,参见 [MSC3231](https://github.com/matrix-org/matrix-doc/pull/3231)。([#3616](https://github.com/matrix-org/matrix-doc/issues/3616)) + +向后兼容变更 + +- 扩展 `/_matrix/client/r0/login` 接口以接受 `m.login.appservice`,参见 [MSC2778](https://github.com/matrix-org/matrix-doc/pull/2778)。([#3324](https://github.com/matrix-org/matrix-doc/issues/3324)) +- 增加对 `restricted` 房间的支持,参见 [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083)、[MSC3289](https://github.com/matrix-org/matrix-doc/pull/3289) 和 [MSC3375](https://github.com/matrix-org/matrix-doc/pull/3375)。([#3387](https://github.com/matrix-org/matrix-doc/issues/3387)) +- 按照 [MSC3069](https://github.com/matrix-org/matrix-doc/pull/3069) 增加 `/account/whoami` 接口的 `is_guest` 字段。([#3605](https://github.com/matrix-org/matrix-doc/issues/3605)) +- 按照 [MSC3419](https://github.com/matrix-org/matrix-doc/pull/3419),扩展访客权限至可发送任意房间事件和状态事件。([#3605](https://github.com/matrix-org/matrix-doc/issues/3605)) +- 按照 [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) 和 [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946) 增加 Spaces 与房间类型。([#3610](https://github.com/matrix-org/matrix-doc/issues/3610)) +- 按照 [MSC3283](https://github.com/matrix-org/matrix-doc/pull/3283) 增加新的 `m.set_displayname`、`m.set_avatar_url` 和 `m.3pid_changes` 功能。([#3614](https://github.com/matrix-org/matrix-doc/issues/3614)) +- 按照 [MSC2732](https://github.com/matrix-org/matrix-doc/pull/2732) 增加后备密钥(在一次性密钥用尽后使用的可选密钥)的支持。([#3615](https://github.com/matrix-org/matrix-doc/issues/3615)) +- 按照 [MSC3231](https://github.com/matrix-org/matrix-doc/pull/3231) 增加令牌认证注册支持。([#3616](https://github.com/matrix-org/matrix-doc/issues/3616)) + +规范释义 + +- 使 `AesHmacSha2KeyDescription` 与 `KeyDescription` 保持一致,将 `name` 标记为可选。([#3481](https://github.com/matrix-org/matrix-doc/issues/3481)) +- 修正规范内容中的各种拼写错误。([#3482](https://github.com/matrix-org/matrix-doc/issues/3482)、[#3495](https://github.com/matrix-org/matrix-doc/issues/3495)、[#3509](https://github.com/matrix-org/matrix-doc/issues/3509)、[#3535](https://github.com/matrix-org/matrix-doc/issues/3535)、[#3591](https://github.com/matrix-org/matrix-doc/issues/3591)、[#3601](https://github.com/matrix-org/matrix-doc/issues/3601)、[#3611](https://github.com/matrix-org/matrix-doc/issues/3611)、[#3671](https://github.com/matrix-org/matrix-doc/issues/3671)、[#3680](https://github.com/matrix-org/matrix-doc/issues/3680)) +- 在 `m.location` 事件定义中明确引用 RFC5870。([#3492](https://github.com/matrix-org/matrix-doc/issues/3492)) +- 按照 [MSC3550](https://github.com/matrix-org/matrix-doc/pull/3550) ,为 `/profile/{userId}` 增加 `403 M_FORBIDDEN` 错误码。([#3530](https://github.com/matrix-org/matrix-doc/issues/3530)) +- 明确 `/sync` API 的说明,并修正 ASCII 图示。([#3543](https://github.com/matrix-org/matrix-doc/issues/3543)) +- 说明客户端 `well_known` 配置中的 `base_url` 可包含或不包含结尾斜杠。([#3562](https://github.com/matrix-org/matrix-doc/issues/3562)) +- 说明解密 `m.olm.v1.curve25519-aes-sha2` 消息时应校验哪个签名。([#3573](https://github.com/matrix-org/matrix-doc/issues/3573)) +- 按照 [MSC3173](https://github.com/matrix-org/matrix-doc/pull/3173) 说明“Stripped State”是什么及其作用。([#3606](https://github.com/matrix-org/matrix-doc/issues/3606)) +- 说明如何理解缺失的一次性密钥计数。([#3636](https://github.com/matrix-org/matrix-doc/issues/3636)) +- 修正多个 API 接口响应结构的 schema。([#3650](https://github.com/matrix-org/matrix-doc/issues/3650)) +- 明确说明群体提及(group mentions)已不在规范范围内。([#3652](https://github.com/matrix-org/matrix-doc/issues/3652)) +- 区分“联邦”事件格式(Federation API 交换)与客户端事件格式(Client-Server 及 AS API 使用)。([#3658](https://github.com/matrix-org/matrix-doc/issues/3658)) +- 修正多个 API 接口响应内容的渲染。([#3674](https://github.com/matrix-org/matrix-doc/issues/3674)) + +## 服务器-服务器 API + +新增接口 + +- 按照 [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946) 增加空间层级 API (`GET /_matrix/federation/v1/hierarchy/{roomId}`)。([#3610](https://github.com/matrix-org/matrix-doc/issues/3610)、[#3660](https://github.com/matrix-org/matrix-doc/issues/3660)) + +向后兼容变更 + +- 按照 [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083)、[MSC3289](https://github.com/matrix-org/matrix-doc/pull/3289) 和 [MSC3375](https://github.com/matrix-org/matrix-doc/pull/3375) 增加对 `restricted` 房间的支持。([#3387](https://github.com/matrix-org/matrix-doc/issues/3387)) + +规范释义 + +- 修正规范文中的各种拼写错误。([#3527](https://github.com/matrix-org/matrix-doc/issues/3527)、[#3528](https://github.com/matrix-org/matrix-doc/issues/3528)) +- 说明 `GET /_matrix/federation/v1/event_auth/{roomId}/{eventId}` *不会* 返回房间完整状态下的验证链。([#3583](https://github.com/matrix-org/matrix-doc/issues/3583)) +- 修正多个 API 接口响应内容的渲染。([#3674](https://github.com/matrix-org/matrix-doc/issues/3674)) + +## 应用服务 API + +规范释义 + +- 区分“联邦”事件格式(Federation API 交换)与客户端事件格式(Client-Server 及 AS API 使用)。([#3658](https://github.com/matrix-org/matrix-doc/issues/3658)) +- 修正多个 API 接口响应内容的渲染。([#3674](https://github.com/matrix-org/matrix-doc/issues/3674)) +- 更正文档中 `GET /_matrix/app/v1/thirdparty/protocol/{protocol}` 接口响应值的说明。([#3675](https://github.com/matrix-org/matrix-doc/issues/3675)) + +## 身份验证服务 API + +向后兼容变更 + +- 按照 [MSC3288](https://github.com/matrix-org/matrix-doc/pull/3288) 为存储的邀请增加 `room_type` 字段。([#3610](https://github.com/matrix-org/matrix-doc/issues/3610)) + +规范释义 + +- 修正多个 API 接口响应内容的渲染。([#3674](https://github.com/matrix-org/matrix-doc/issues/3674)) + +## 推送网关 API + +规范释义 + +- 修正多个 API 接口响应内容的渲染。([#3674](https://github.com/matrix-org/matrix-doc/issues/3674)) + +## 房间版本 + +向后兼容变更 + +- 按照 [MSC3289](https://github.com/matrix-org/matrix-doc/pull/3289) 增加房间版本 8。([#3387](https://github.com/matrix-org/matrix-doc/issues/3387)) +- 按照 [MSC3375](https://github.com/matrix-org/matrix-doc/pull/3375) 增加房间版本 9。([#3387](https://github.com/matrix-org/matrix-doc/issues/3387)) + +规范释义 + +- 完整规范房间版本,说明哪些内容继承自父版本。([#3432](https://github.com/matrix-org/matrix-doc/issues/3432)、[#3661](https://github.com/matrix-org/matrix-doc/issues/3661)) +- 明确事件 ID 和事件格式相关章节。([#3501](https://github.com/matrix-org/matrix-doc/issues/3501)) +- 移除若干误标为联邦 PDU `unsigned` 字段的数据项。([#3522](https://github.com/matrix-org/matrix-doc/issues/3522)) +- 修正房间版本规范的标题顺序保持一致。([#3683](https://github.com/matrix-org/matrix-doc/issues/3683)) +- 为房间版本 6 增补缺失的“签名密钥有效期”章节。([#3683](https://github.com/matrix-org/matrix-doc/issues/3683)) +- 修正 v7/v8/v9 版本下 `knock` -> `leave` 的成员关系许可规则。([#3694](https://github.com/matrix-org/matrix-doc/issues/3694)) + +## 附录 + +向后兼容变更 + +- 按照 [MSC2758](https://github.com/matrix-org/matrix-doc/pull/2758) 描述“通用命名空间标识符语法”。([#3171](https://github.com/matrix-org/matrix-doc/issues/3171)) +- 按照 [MSC2312](https://github.com/matrix-org/matrix-doc/pull/2312) 描述 `matrix:` URI 方案。([#3608](https://github.com/matrix-org/matrix-doc/issues/3608)) diff --git a/locales/zh-Hans/changelog/v1.3.md b/locales/zh-Hans/changelog/v1.3.md new file mode 100644 index 00000000..1be82985 --- /dev/null +++ b/locales/zh-Hans/changelog/v1.3.md @@ -0,0 +1,102 @@ +--- +title: v1.3 变更日志 +linkTitle: v1.3 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2022-06-15 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +弃用内容 + +- 根据 [MSC3700](https://github.com/matrix-org/matrix-spec-proposals/pull/3700) 的要求,弃用 `m.megolm.v1.aes-sha2` 事件中的 `sender_key` 和 `device_id`,以及发往设备的消息 `m.room_key_request` 中的 `sender_key`。([#1101](https://github.com/matrix-org/matrix-spec/issues/1101)) + +向后兼容的变更 + +- 根据 [MSC3567](https://github.com/matrix-org/matrix-spec-proposals/pull/3567),使 `GET /_matrix/client/v3/messages` 的 `from` 参数可选,以便能从房间历史的起始或结尾请求事件。([#1002](https://github.com/matrix-org/matrix-spec/issues/1002)) +- 新增刷新令牌支持,详见 [MSC2918](https://github.com/matrix-org/matrix-spec-proposals/pull/2918)。([#1056](https://github.com/matrix-org/matrix-spec/issues/1056), [#1113](https://github.com/matrix-org/matrix-spec/issues/1113)) +- 放宽富回复(Rich Replies)的限制,参见 [MSC3676](https://github.com/matrix-org/matrix-spec-proposals/pull/3676)。([#1062](https://github.com/matrix-org/matrix-spec/issues/1062)) +- 描述事件之间的结构化关联系统,根据 [MSC2674](https://github.com/matrix-org/matrix-spec-proposals/pull/2674)。([#1062](https://github.com/matrix-org/matrix-spec/issues/1062)) +- 描述事件间的关系如何“聚合”,参见 [MSC2675](https://github.com/matrix-org/matrix-spec-proposals/pull/2675) 和 [MSC3666](https://github.com/matrix-org/matrix-spec-proposals/pull/3666)。([#1062](https://github.com/matrix-org/matrix-spec/issues/1062)) +- 在受支持的房间版本中,增加对新的 `knock_restricted` 加入规则的支持,依据 [MSC3787](https://github.com/matrix-org/matrix-spec-proposals/pull/3787)。([#1099](https://github.com/matrix-org/matrix-spec/issues/1099)) + +规范澄清 + +- 澄清 `m.room.avatar` 事件中的 url 字段不是必需的。([#987](https://github.com/matrix-org/matrix-spec/issues/987)) +- 澄清用户交互式认证中的 `type` 可以省略。([#989](https://github.com/matrix-org/matrix-spec/issues/989)) +- 调整 OpenAPI 规范,确保渲染客户端-服务器 API 时明确定义 Flow information 类型。([#1003](https://github.com/matrix-org/matrix-spec/issues/1003)) +- 更正 `m.room.power_levels` 事件中未指定 `invite` 时的默认值。([#1021](https://github.com/matrix-org/matrix-spec/issues/1021)) +- 更新指向旧 `matrix-doc` github 仓库的各种链接。([#1032](https://github.com/matrix-org/matrix-spec/issues/1032)) +- 按照 [MSC3582](https://github.com/matrix-org/matrix-spec-proposals/pull/3582) 移除 `m.room.message.feedback`。([#1035](https://github.com/matrix-org/matrix-spec/issues/1035)) +- 修复规范中的各种拼写错误。([#1051](https://github.com/matrix-org/matrix-spec/issues/1051), [#1054](https://github.com/matrix-org/matrix-spec/issues/1054), [#1059](https://github.com/matrix-org/matrix-spec/issues/1059), [#1081](https://github.com/matrix-org/matrix-spec/issues/1081), [#1097](https://github.com/matrix-org/matrix-spec/issues/1097), [#1110](https://github.com/matrix-org/matrix-spec/issues/1110), [#1115](https://github.com/matrix-org/matrix-spec/issues/1115), [#1126](https://github.com/matrix-org/matrix-spec/issues/1126), [#1127](https://github.com/matrix-org/matrix-spec/issues/1127), [#1128](https://github.com/matrix-org/matrix-spec/issues/1128), [#1129](https://github.com/matrix-org/matrix-spec/issues/1129), [#3681](https://github.com/matrix-org/matrix-spec-proposals/issues/3681), [#3708](https://github.com/matrix-org/matrix-spec-proposals/issues/3708)) +- 澄清以 `@` 开头的 state key 实际上是保留的。这是 [#3658](https://github.com/matrix-org/matrix-spec-proposals/pull/3658) 引入的回退。([#1100](https://github.com/matrix-org/matrix-spec/issues/1100)) +- 移除 `m.room.name` 事件 `name` 字段的未强制执行的长度限制。([#3669](https://github.com/matrix-org/matrix-spec-proposals/issues/3669)) +- 从 `/sync` 中 `m.read`、`m.typing` 示例及房间账户数据中的 `m.fully_read` 示例移除错误出现的 `room_id` 字段。([#3679](https://github.com/matrix-org/matrix-spec-proposals/issues/3679)) +- 澄清推送规则条件中 `event_match` 的行为。([#3690](https://github.com/matrix-org/matrix-spec-proposals/issues/3690)) +- 更正错误引用的 `m.login.appservice` 登录标识符,改用 `m.login.application_service`。([#3711](https://github.com/matrix-org/matrix-spec-proposals/issues/3711)) +- 修正成员状态转移描述,明确 `invite->knock` 和 `external->leave` 是有效转移。([#3730](https://github.com/matrix-org/matrix-spec-proposals/issues/3730)) + +## 服务器-服务器 API + +向后兼容的变更 + +- 在 Authorization header 中新增 `destination` 属性,见 [MSC3383](https://github.com/matrix-org/matrix-spec-proposals/pull/3383)。([#1067](https://github.com/matrix-org/matrix-spec/issues/1067)) + +规范澄清 + +- 从 PDU 中移除基本未被使用的 `origin` 字段。([#998](https://github.com/matrix-org/matrix-spec/issues/998)) +- 更新指向旧 `matrix-doc` github 仓库的各种链接。([#1032](https://github.com/matrix-org/matrix-spec/issues/1032)) +- 澄清 Authorization header 的格式。([#1038](https://github.com/matrix-org/matrix-spec/issues/1038), [#1067](https://github.com/matrix-org/matrix-spec/issues/1067)) +- 澄清在检查收到的 PDU 时,“有效事件”的含义。([#1045](https://github.com/matrix-org/matrix-spec/issues/1045)) +- 澄清 `valid_until_ts` 为毫秒单位,与 Matrix 中其他时间戳保持一致。([#1055](https://github.com/matrix-org/matrix-spec/issues/1055)) +- 澄清 PDU 检查应参考事件前的状态。([#1070](https://github.com/matrix-org/matrix-spec/issues/1070)) +- 澄清历史上如何处理非整数权限级别。([#1099](https://github.com/matrix-org/matrix-spec/issues/1099)) +- 修正规范中各种拼写错误。([#1110](https://github.com/matrix-org/matrix-spec/issues/1110)) +- 更正 `/send_join` 响应的误导性文本。([#3703](https://github.com/matrix-org/matrix-spec-proposals/issues/3703)) +- 澄清用于 `X-Matrix` 签名验证的 `content` 是已解析的 JSON 正文。([#3727](https://github.com/matrix-org/matrix-spec-proposals/issues/3727)) + +## 应用服务 API + +向后兼容的变更 + +- 按照 [MSC3316](https://github.com/matrix-org/matrix-spec-proposals/pull/3316) 新增时间戳校准(timestamp massaging)支持。([#1094](https://github.com/matrix-org/matrix-spec/issues/1094)) + +## 身份服务 API + +无重大变更。 + +## 推送网关 API + +无重大变更。 + +## 房间版本 + +向后兼容的变更 + +- 按照 [MSC3604](https://github.com/matrix-org/matrix-spec-proposals/pull/3604) 添加房间版本 10。([#1099](https://github.com/matrix-org/matrix-spec/issues/1099)) +- 根据 [MSC3667](https://github.com/matrix-org/matrix-spec-proposals/pull/3667) 在房间版本 10 强制使用整数权限级别。([#1099](https://github.com/matrix-org/matrix-spec/issues/1099)) +- 根据 [MSC3787](https://github.com/matrix-org/matrix-spec-proposals/pull/3787) 在房间版本 10 中新增对 `knock_restricted` 加入规则的支持。([#1099](https://github.com/matrix-org/matrix-spec/issues/1099)) +- 按照 [MSC3589](https://github.com/matrix-org/matrix-spec-proposals/pull/3589) 将默认房间版本更新为 9。([#3739](https://github.com/matrix-org/matrix-spec-proposals/issues/3739)) + +规范澄清 + +- 提升状态解析算法表述的可读性和理解度。([#1037](https://github.com/matrix-org/matrix-spec/issues/1037), [#1042](https://github.com/matrix-org/matrix-spec/issues/1042), [#1043](https://github.com/matrix-org/matrix-spec/issues/1043), [#1120](https://github.com/matrix-org/matrix-spec/issues/1120)) +- 提高授权规则表述的可读性。([#1050](https://github.com/matrix-org/matrix-spec/issues/1050)) +- 对于房间版本 8、9 和 10:澄清哪些 homeserver 需签名加入事件。([#1093](https://github.com/matrix-org/matrix-spec/issues/1093)) +- 澄清房间版本 1 至 9 接受字符串类型的权限级别,见 [MSC3667](https://github.com/matrix-org/matrix-spec-proposals/pull/3667)。([#1099](https://github.com/matrix-org/matrix-spec/issues/1099)) +- 所有房间版本:在授权规则中新增 `m.federate`,以符合最初意图。([#1103](https://github.com/matrix-org/matrix-spec/issues/1103)) +- 房间版本 2 至 10:更明确地定义权限事件的主线(mainline)及其他事件的主线排序。([#1107](https://github.com/matrix-org/matrix-spec/issues/1107)) +- 房间版本 7、8、9 和 10:修正当 `join_rule` 为 `knock` 时的加入成员授权规则。([#3737](https://github.com/matrix-org/matrix-spec-proposals/issues/3737)) + +## 附录 + +无重大变更。 diff --git a/locales/zh-Hans/changelog/v1.4.md b/locales/zh-Hans/changelog/v1.4.md new file mode 100644 index 00000000..22e51d46 --- /dev/null +++ b/locales/zh-Hans/changelog/v1.4.md @@ -0,0 +1,109 @@ +--- +title: v1.4 更新日志 +linkTitle: v1.4 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2022-09-29 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +移除的端点 + +- 移除未使用的策略房间共享机制,详见 [MSC3844](https://github.com/matrix-org/matrix-spec-proposals/pull/3844)。([#1196](https://github.com/matrix-org/matrix-spec/issues/1196)) + +向后兼容的变更 + +- 增加 `.m.rule.room.server_acl` 推送规则,以匹配 `m.room.server_acl` 事件,详见 [MSC3786](https://github.com/matrix-org/matrix-spec-proposals/pull/3786)。([#1190](https://github.com/matrix-org/matrix-spec/issues/1190), [#1201](https://github.com/matrix-org/matrix-spec/issues/1201)) +- 向媒体仓库添加 `Cross-Origin-Resource-Policy` (CORP) 响应头,详见 [MSC3828](https://github.com/matrix-org/matrix-spec-proposals/pull/3828)。([#1197](https://github.com/matrix-org/matrix-spec/issues/1197)) +- 房间升级时复制房间的 `type`,详见 [MSC3818](https://github.com/matrix-org/matrix-spec-proposals/pull/3818)。([#1198](https://github.com/matrix-org/matrix-spec/issues/1198)) +- 在 `/publicRooms` 端点新增 `room_types` 过滤参数和 `room_type` 响应字段,详见 [MSC3827](https://github.com/matrix-org/matrix-spec-proposals/pull/3827)。([#1199](https://github.com/matrix-org/matrix-spec/issues/1199)) +- 新增 `m.replace` 关联(事件编辑),详见 [MSC2676](https://github.com/matrix-org/matrix-spec-proposals/pull/2676)。([#1211](https://github.com/matrix-org/matrix-spec/issues/1211)) +- 新增 `m.read.private` 已读回执,详见 [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285)。([#1216](https://github.com/matrix-org/matrix-spec/issues/1216)) +- 在 `/read_markers` 端点中将 `m.fully_read` 设置为可选,详见 [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285)。([#1216](https://github.com/matrix-org/matrix-spec/issues/1216)) +- 允许通过 `/receipts` 设置 `m.fully_read` 标记,详见 [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285)。([#1216](https://github.com/matrix-org/matrix-spec/issues/1216)) +- 通过 `m.thread` 关联新增线程支持,详见 [MSC3440](https://github.com/matrix-org/matrix-spec-proposals/pull/3440)、[MSC3816](https://github.com/matrix-org/matrix-spec-proposals/pull/3816)、[MSC3856](https://github.com/matrix-org/matrix-spec-proposals/pull/3856)、[MSC3715](https://github.com/matrix-org/matrix-spec-proposals/pull/3715)。([#1254](https://github.com/matrix-org/matrix-spec/issues/1254)) +- 新增线程级别的通知与已读回执,详见 [MSC3771](https://github.com/matrix-org/matrix-spec-proposals/pull/3771) 和 [MSC3773](https://github.com/matrix-org/matrix-spec-proposals/pull/3773)。([#1255](https://github.com/matrix-org/matrix-spec/issues/1255)) +- 在 `/receipt` 端点中新增 `thread_id` 字段,详见 [MSC3771](https://github.com/matrix-org/matrix-spec-proposals/pull/3771)。([#1261](https://github.com/matrix-org/matrix-spec/issues/1261)) + +规范澄清 + +- 说明 `/rooms/{roomId}/invite` 端点在用户已被邀请时会返回 200 响应码。([#1084](https://github.com/matrix-org/matrix-spec/issues/1084)) +- 修正规范内的各种拼写错误。([#1135](https://github.com/matrix-org/matrix-spec/issues/1135), [#1161](https://github.com/matrix-org/matrix-spec/issues/1161), [#1164](https://github.com/matrix-org/matrix-spec/issues/1164), [#1170](https://github.com/matrix-org/matrix-spec/issues/1170), [#1180](https://github.com/matrix-org/matrix-spec/issues/1180), [#1215](https://github.com/matrix-org/matrix-spec/issues/1215), [#1238](https://github.com/matrix-org/matrix-spec/issues/1238), [#1243](https://github.com/matrix-org/matrix-spec/issues/1243), [#1263](https://github.com/matrix-org/matrix-spec/issues/1263)) +- 说明账户数据端点的返回码,并阐明房间级数据不会继承全局数据。([#1155](https://github.com/matrix-org/matrix-spec/issues/1155)) +- 澄清策略规则通配符与 ACL 通配符工作方式一致。由 Nico 贡献。([#1165](https://github.com/matrix-org/matrix-spec/issues/1165)) +- 澄清端到端加密模块中部分结构体的格式。([#1166](https://github.com/matrix-org/matrix-spec/issues/1166)) +- 为规范中对象定义添加 HTML 锚点。([#1174](https://github.com/matrix-org/matrix-spec/issues/1174)) +- 调整由 OpenAPI 定义渲染的表格中 `` 代码片段的样式。([#1179](https://github.com/matrix-org/matrix-spec/issues/1179)) +- 更新“API 标准”章节,澄清 JSON 的使用方式。([#1185](https://github.com/matrix-org/matrix-spec/issues/1185)) +- 澄清 `POST /_matrix/client/v3/login` 响应体中 "device_id"、"user_id" 和 "access_token" 字段为必需项。([#1210](https://github.com/matrix-org/matrix-spec/issues/1210)) +- 强化刷新访问令牌与事务 ID 的关系。([#1236](https://github.com/matrix-org/matrix-spec/issues/1236)) +- 通过用逗号分隔可能值的方式,澄清枚举值定义。([#1240](https://github.com/matrix-org/matrix-spec/issues/1240)) + +## 服务器-服务器 API + +向后兼容的变更 + +- 新增线程级别的通知与已读回执,详见 [MSC3771](https://github.com/matrix-org/matrix-spec-proposals/pull/3771) 和 [MSC3773](https://github.com/matrix-org/matrix-spec-proposals/pull/3773)。([#1255](https://github.com/matrix-org/matrix-spec/issues/1255)) + +规范澄清 + +- 为规范中对象定义添加 HTML 锚点。([#1174](https://github.com/matrix-org/matrix-spec/issues/1174)) +- 调整由 OpenAPI 定义渲染的表格中 `` 代码片段的样式。([#1179](https://github.com/matrix-org/matrix-spec/issues/1179)) +- 更新“API 标准”章节,澄清 JSON 的使用方式。([#1185](https://github.com/matrix-org/matrix-spec/issues/1185)) + +## 应用服务 API + +重大变更 + +- 主服务器授权方式变更为通过 `Authorization` 请求头完成,而不再使用 `access_token`,详见 [MSC2832](https://github.com/matrix-org/matrix-spec-proposals/pull/2832)。([#1200](https://github.com/matrix-org/matrix-spec/issues/1200)) + +规范澄清 + +- 为规范中对象定义添加 HTML 锚点。([#1174](https://github.com/matrix-org/matrix-spec/issues/1174)) + +## 身份服务 API + +规范澄清 + +- 为规范中对象定义添加 HTML 锚点。([#1174](https://github.com/matrix-org/matrix-spec/issues/1174)) +- 更新“API 标准”章节,澄清 JSON 的使用方式。([#1185](https://github.com/matrix-org/matrix-spec/issues/1185)) + +## 推送网关 API + +规范澄清 + +- 为规范中对象定义添加 HTML 锚点。([#1174](https://github.com/matrix-org/matrix-spec/issues/1174)) + +## 房间版本 + +规范澄清 + +- 对于房间版本 1 至 10,明确规定含有被拒绝 `auth_events` 的事件必须被拒绝。([#1137](https://github.com/matrix-org/matrix-spec/issues/1137)) +- 对于房间版本 2-10:修正对状态解析算法的错误澄清说明。([#1158](https://github.com/matrix-org/matrix-spec/issues/1158)) +- 对于房间版本 7 至 10:明确指出 `invite->knock` 实际上是一个合法的状态转换。([#1175](https://github.com/matrix-org/matrix-spec/issues/1175)) + +## 附录 + +无重大变更。 + +## 内部变更/工具 + +向后兼容的变更 + +- 新增内部变更更新日志章节。([#1194](https://github.com/matrix-org/matrix-spec/issues/1194)) + +规范澄清 + +- 渲染对象定义表格时输出 HTML 锚点。([#1191](https://github.com/matrix-org/matrix-spec/issues/1191)) +- 为渲染数据区域添加背景色和内边距。([#1195](https://github.com/matrix-org/matrix-spec/issues/1195)) +- 修复客户端-服务器 API 中 shortcodes 的渲染问题。([#1205](https://github.com/matrix-org/matrix-spec/issues/1205)) +- 修复由 OpenAPI 规范生成的映射类型的空白问题。([#1230](https://github.com/matrix-org/matrix-spec/issues/1230)) diff --git a/locales/zh-Hans/changelog/v1.5.md b/locales/zh-Hans/changelog/v1.5.md new file mode 100644 index 00000000..c794dd96 --- /dev/null +++ b/locales/zh-Hans/changelog/v1.5.md @@ -0,0 +1,91 @@ +--- +title: v1.5 变更日志 +linkTitle: v1.5 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2022-11-17 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +向后兼容的变更 + +- 按照 [MSC3267](https://github.com/matrix-org/matrix-spec-proposals/pull/3267) 添加 `m.reference` 关系。([#1206](https://github.com/matrix-org/matrix-spec/issues/1206)) +- 为房间内验证补充缺失的 `m.key.verification.request` 消息类型文档。([#1271](https://github.com/matrix-org/matrix-spec/issues/1271)) + +规范澄清 + +- 修正规范中的各种拼写错误。([#1260](https://github.com/matrix-org/matrix-spec/issues/1260), [#1265](https://github.com/matrix-org/matrix-spec/issues/1265), [#1276](https://github.com/matrix-org/matrix-spec/issues/1276)) +- 修正 `/sync` 中 `device_one_time_keys_count` 的命名。([#1266](https://github.com/matrix-org/matrix-spec/issues/1266)) +- 改进事件子类型的显示。([#1283](https://github.com/matrix-org/matrix-spec/issues/1283)) +- 改进对临时事件的文档说明。([#1284](https://github.com/matrix-org/matrix-spec/issues/1284)) +- 明确 `/_matrix/client/v3/directory/rooms/{roomAlias}` 中 400 响应的定义。([#1286](https://github.com/matrix-org/matrix-spec/issues/1286)) +- 对端到端加密部分的内容进行了澄清。([#1294](https://github.com/matrix-org/matrix-spec/issues/1294), [#1345](https://github.com/matrix-org/matrix-spec/issues/1345)) +- 规范中多处进行了澄清。([#1306](https://github.com/matrix-org/matrix-spec/issues/1306)) +- 用 `set_tweak` 替换了推送规则动作 `set_sound`。([#1318](https://github.com/matrix-org/matrix-spec/issues/1318)) +- 明确 `PUT /_matrix/client/v3/pushrules/{scope}/{kind}/{ruleId}` 的行为。([#1319](https://github.com/matrix-org/matrix-spec/issues/1319)) +- 明确 `.m.rule.master` 优先级高于任何推送规则。([#1320](https://github.com/matrix-org/matrix-spec/issues/1320)) +- 在 `POST /_matrix/client/v3/refresh` 端点要求请求字段 `refresh_token`。([#1323](https://github.com/matrix-org/matrix-spec/issues/1323)) +- 修复规范中多处失效链接。([#1330](https://github.com/matrix-org/matrix-spec/issues/1330)) +- 在 `GET /_matrix/client/v3/sync` 响应示例中加入已读回执的示例。([#1341](https://github.com/matrix-org/matrix-spec/issues/1341)) + +## 服务器-服务器 API + +规范澄清 + +- 修复规范中多处失效链接。([#1330](https://github.com/matrix-org/matrix-spec/issues/1330)) + +## 应用服务 API + +规范澄清 + +- 按照 [MSC3905](https://github.com/matrix-org/matrix-spec-proposals/issues/3905) 澄清应用服务只能对本地用户注册关注。([#1305](https://github.com/matrix-org/matrix-spec/issues/1305)) + +## 身份服务 API + +规范澄清 + +- 修复规范中多处失效链接。([#1330](https://github.com/matrix-org/matrix-spec/issues/1330)) + +## 推送网关 API + +无重大变更。 + +## 房间版本 + +规范澄清 + +- 调整事件认证规则文本,明确用户无法降权电平相同的其他用户。([#1269](https://github.com/matrix-org/matrix-spec/issues/1269)) +- 对事件授权规则文本进行了多处澄清。([#1270](https://github.com/matrix-org/matrix-spec/issues/1270)) +- 修复规范中多处失效链接。([#1330](https://github.com/matrix-org/matrix-spec/issues/1330)) + +## 附录 + +无重大变更。 + +## 内部更改/工具 + +向后兼容的变更 + +- 更新 docsy 主题至 v0.5.0,并应用 matrix.org 的修改 (https://github.com/matrix-org/docsy/commit/a0032f8db919a6c67ba6cdef2c455f105b6272a2)。([#1295](https://github.com/matrix-org/matrix-spec/issues/1295)) + +规范澄清 + +- 改进 `resolve-additional-types` 模板输出的错误信息。([#1303](https://github.com/matrix-org/matrix-spec/issues/1303)) +- 修复 API 查看器的链接。([#1308](https://github.com/matrix-org/matrix-spec/issues/1308)) +- 停止将客户端-服务器 API 和房间版本规范的子部分渲染为独立页面。([#1317](https://github.com/matrix-org/matrix-spec/issues/1317)) +- 使用链接检查器确保文档无失效链接。([#1329](https://github.com/matrix-org/matrix-spec/issues/1329), [#1338](https://github.com/matrix-org/matrix-spec/issues/1338)) +- 更新 Swagger 定义预览说明。([#1331](https://github.com/matrix-org/matrix-spec/issues/1331)) +- 使锚点定义更具唯一性。([#1339](https://github.com/matrix-org/matrix-spec/issues/1339)) +- 用 towncrier 生成不稳定的变更日志,实现一致性。([#1340](https://github.com/matrix-org/matrix-spec/issues/1340)) +- 更新 CONTRIBUTING.md,指出本仓库的非内容更改需加注明“internal”类型的变更日志。([#1342](https://github.com/matrix-org/matrix-spec/issues/1342)) +- 在模块汇总表中补充新模块:事件替换、线程与引用关系。([#1344](https://github.com/matrix-org/matrix-spec/issues/1344)) +- 禁用规范的 RSS 生成。([#1346](https://github.com/matrix-org/matrix-spec/issues/1346)) diff --git a/locales/zh-Hans/changelog/v1.6.md b/locales/zh-Hans/changelog/v1.6.md new file mode 100644 index 00000000..2119d0cf --- /dev/null +++ b/locales/zh-Hans/changelog/v1.6.md @@ -0,0 +1,102 @@ +--- +title: v1.6 更新日志 +linkTitle: v1.6 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2023-02-14 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +向后兼容的更改 + +- 根据 [MSC3743](https://github.com/matrix-org/matrix-spec-proposals/pull/3743) 添加了针对未知端点/方法的标准错误响应信息。([#1347](https://github.com/matrix-org/matrix-spec/issues/1347)) +- 根据 [MSC3030](https://github.com/matrix-org/matrix-spec-proposals/pull/3030) 添加了 `/rooms//timestamp_to_event` 端点。([#1366](https://github.com/matrix-org/matrix-spec/issues/1366)) +- 根据 [MSC3783](https://github.com/matrix-org/matrix-spec-proposals/pull/3783) 定义了 SAS 验证的 `hkdf-hmac-sha256.v2` MAC 方法。([#1412](https://github.com/matrix-org/matrix-spec/issues/1412)) + +规范澄清 + +- 澄清了权限等级的整数范围。([#1169](https://github.com/matrix-org/matrix-spec/issues/1169), [#1355](https://github.com/matrix-org/matrix-spec/issues/1355)) +- 澄清了 `/context` 即使 `limit` 为零也始终返回 `event`。由 @sumnerevans 于 @beeper 贡献。([#1239](https://github.com/matrix-org/matrix-spec/issues/1239)) +- 澄清了删除推送器(pusher)时哪些字段是必需的。([#1321](https://github.com/matrix-org/matrix-spec/issues/1321)) +- 改进了推送规则类型和动作的呈现方式。([#1348](https://github.com/matrix-org/matrix-spec/issues/1348)) +- 为 m.call.answer 模式添加了缺失的描述。([#1353](https://github.com/matrix-org/matrix-spec/issues/1353)) +- 修复了规范中的各种拼写错误。([#1363](https://github.com/matrix-org/matrix-spec/issues/1363)) +- 澄清了端到端加密部分的内容。([#1381](https://github.com/matrix-org/matrix-spec/issues/1381)) +- 将登录 API 定义移动至正确的标题下。由 @HarHarLinks 贡献。([#1382](https://github.com/matrix-org/matrix-spec/issues/1382)) +- 澄清哪些事件会被包含在 Stripped State 中。由 @andybalaam 贡献。([#1409](https://github.com/matrix-org/matrix-spec/issues/1409)) +- 针对三方标识(3PID)`medium` 的定义添加了规范链接。([#1417](https://github.com/matrix-org/matrix-spec/issues/1417)) +- 更正了规范中默认覆盖推送规则顺序的描述。([#1421](https://github.com/matrix-org/matrix-spec/issues/1421)) +- 改进了富文本部分中标签与它们属性的区分。由 Nico 贡献。([#1433](https://github.com/matrix-org/matrix-spec/issues/1433)) + +## 服务器-服务器 API + +不兼容更改 + +- 根据 [MSC3938](https://github.com/matrix-org/matrix-spec-proposals/pull/3938) 从服务器 `/keys` 端点中移除了 `keyId`。([#1350](https://github.com/matrix-org/matrix-spec/issues/1350)) + +向后兼容的更改 + +- 根据 [MSC3743](https://github.com/matrix-org/matrix-spec-proposals/pull/3743) 添加了针对未知端点/方法的标准错误响应信息。([#1347](https://github.com/matrix-org/matrix-spec/issues/1347)) +- 根据 [MSC3030](https://github.com/matrix-org/matrix-spec-proposals/pull/3030) 添加了 `/timestamp_to_event/` 端点。([#1366](https://github.com/matrix-org/matrix-spec/issues/1366)) +- 扩展了 `/_matrix/federation/v2/send_join`,允许省略成员事件。参见 [MSC3706](https://github.com/matrix-org/matrix-doc/pull/3706)。([#1393](https://github.com/matrix-org/matrix-spec/issues/1393), [#1398](https://github.com/matrix-org/matrix-spec/issues/1398)) +- 根据 [MSC3943](https://github.com/matrix-org/matrix-doc/pull/3943) 说明 `/_matrix/federation/v2/send_join` 即便允许省略成员事件,也应为无名称房间包含 heroes。([#1425](https://github.com/matrix-org/matrix-spec/issues/1425)) + +规范澄清 + +- 在邀请端点定义中直接内嵌示例,而不再使用引用。([#1349](https://github.com/matrix-org/matrix-spec/issues/1349)) +- 修正了 `POST _matrix/federation/v1/user/keys/claim` 响应模式。([#1351](https://github.com/matrix-org/matrix-spec/issues/1351)) +- 更正了“收到 PDU 时执行的检查”小节中默认邀请等级的定义。([#1371](https://github.com/matrix-org/matrix-spec/issues/1371)) +- 澄清了服务器名称可以使用 CNAME 记录。([#1376](https://github.com/matrix-org/matrix-spec/issues/1376)) +- 修正了 EDU 示例中的 `edu_type`。([#1383](https://github.com/matrix-org/matrix-spec/issues/1383)) + +## 应用服务 API + +向后兼容的更改 + +- 根据 [MSC3743](https://github.com/matrix-org/matrix-spec-proposals/pull/3743) 添加了针对未知端点/方法的标准错误响应信息。([#1347](https://github.com/matrix-org/matrix-spec/issues/1347)) + +## 身份服务 API + +向后兼容的更改 + +- 根据 [MSC3743](https://github.com/matrix-org/matrix-spec-proposals/pull/3743) 添加了针对未知端点/方法的标准错误响应信息。([#1347](https://github.com/matrix-org/matrix-spec/issues/1347)) + +## 推送网关 API + +向后兼容的更改 + +- 根据 [MSC3743](https://github.com/matrix-org/matrix-spec-proposals/pull/3743) 添加了针对未知端点/方法的标准错误响应信息。([#1347](https://github.com/matrix-org/matrix-spec/issues/1347)) + +## 房间版本 + +向后兼容的更改 + +- 根据 [MSC3904](https://github.com/matrix-org/matrix-spec-proposals/pull/3904) 更新了默认房间版本至 10。([#1397](https://github.com/matrix-org/matrix-spec/issues/1397)) + +规范澄清 + +- 澄清了房间版本的语法。([#1422](https://github.com/matrix-org/matrix-spec/issues/1422)) +- 修复了规范中的各种拼写错误。([#1423](https://github.com/matrix-org/matrix-spec/issues/1423)) + +## 附录 + +无重大更改。 + +## 内部变更/工具 + +规范澄清 + +- 向 README 添加了不稳定规范的链接。([#1357](https://github.com/matrix-org/matrix-spec/issues/1357)) +- 改进了提案检索脚本在失败情况下的安全性。([#1368](https://github.com/matrix-org/matrix-spec/issues/1368)) +- 在内容上传的 OpenAPI 文件中,将 `` 重命名为 `content`。([#1370](https://github.com/matrix-org/matrix-spec/issues/1370)) +- 在已有示例的情况下,停止自动生成示例。([#1384](https://github.com/matrix-org/matrix-spec/issues/1384)) +- 改进了推送通知部分定义的格式。([#1415](https://github.com/matrix-org/matrix-spec/issues/1415)) diff --git a/locales/zh-Hans/changelog/v1.7.md b/locales/zh-Hans/changelog/v1.7.md new file mode 100644 index 00000000..99f7ef4d --- /dev/null +++ b/locales/zh-Hans/changelog/v1.7.md @@ -0,0 +1,114 @@ +--- +title: v1.7 更新日志 +linkTitle: v1.7 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2023-05-25 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +新增端点 + +- [`POST /_matrix/media/v1/create`](/client-server-api/#post_matrixmediav1create) ([#1499](https://github.com/matrix-org/matrix-spec/issues/1499)) +- [`PUT /_matrix/media/v3/upload/{serverName}/{mediaId}`](/client-server-api/#put_matrixmediav3uploadservernamemediaid) ([#1499](https://github.com/matrix-org/matrix-spec/issues/1499)) +- [`POST /_matrix/client/v1/login/get_token`](/client-server-api/#post_matrixclientv1loginget_token) ([#1530](https://github.com/matrix-org/matrix-spec/issues/1530)) + +向后兼容性变更 + +- 按照 [MSC3925](https://github.com/matrix-org/matrix-spec-proposals/pull/3925) 修改了服务端对 `m.replace`(编辑)事件的聚合方式。([#1440](https://github.com/matrix-org/matrix-spec/issues/1440), [#1525](https://github.com/matrix-org/matrix-spec/issues/1525)) +- 添加新的推送规则条件 `event_property_is` 及 `event_property_contains`,详见 [MSC3758](https://github.com/matrix-org/matrix-spec-proposals/pull/3758) 及 [MSC3966](https://github.com/matrix-org/matrix-spec-proposals/pull/3966)。([#1464](https://github.com/matrix-org/matrix-spec/issues/1464)) +- 添加 `m.annotation` 关系(表情反应),详见 [MSC2677](https://github.com/matrix-org/matrix-spec-proposals/pull/2677)。([#1475](https://github.com/matrix-org/matrix-spec/issues/1475), [#1531](https://github.com/matrix-org/matrix-spec/issues/1531)) +- 支持异步媒体上传,详见 [MSC2246](https://github.com/matrix-org/matrix-spec-proposals/pull/2246)。([#1499](https://github.com/matrix-org/matrix-spec/issues/1499), [#1510](https://github.com/matrix-org/matrix-spec/issues/1510)) +- 文档化 `m.mentions` 属性;`.m.rule.is_user_mention` 及 `.m.rule.is_room_mention` 推送规则;和其他通知行为,详见 [MSC3952](https://github.com/matrix-org/matrix-spec-proposals/pull/3952)。([#1508](https://github.com/matrix-org/matrix-spec/issues/1508)) +- 改进 VoIP 信令,详见 [MSC2746](https://github.com/matrix-org/matrix-spec-proposals/pull/2746)。([#1511](https://github.com/matrix-org/matrix-spec/issues/1511), [#1540](https://github.com/matrix-org/matrix-spec/issues/1540)) +- 按照 [MSC3970](https://github.com/matrix-org/matrix-spec-proposals/pull/3970) 更新事务 ID 的适用范围。([#1526](https://github.com/matrix-org/matrix-spec/issues/1526)) +- 增加媒体下载重定向能力,详见 [MSC3860](https://github.com/matrix-org/matrix-spec-proposals/pull/3860)。([#1529](https://github.com/matrix-org/matrix-spec/issues/1529)) +- 增加利用现有会话在其他设备登录的能力,详见 [MSC3882](https://github.com/matrix-org/matrix-spec-proposals/pull/3882)。([#1530](https://github.com/matrix-org/matrix-spec/issues/1530)) + +规范澄清 + +- 澄清规范中关于子事件聚合的部分。([#1424](https://github.com/matrix-org/matrix-spec/issues/1424)) +- 修正了规范中的各种拼写错误。([#1432](https://github.com/matrix-org/matrix-spec/issues/1432), [#1442](https://github.com/matrix-org/matrix-spec/issues/1442), [#1447](https://github.com/matrix-org/matrix-spec/issues/1447), [#1455](https://github.com/matrix-org/matrix-spec/issues/1455), [#1465](https://github.com/matrix-org/matrix-spec/issues/1465), [#1500](https://github.com/matrix-org/matrix-spec/issues/1500), [#1509](https://github.com/matrix-org/matrix-spec/issues/1509)) +- 澄清线程的回复链回退可能不存在。([#1439](https://github.com/matrix-org/matrix-spec/issues/1439)) +- 澄清内容相关推送规则匹配的事件属性。([#1441](https://github.com/matrix-org/matrix-spec/issues/1441)) +- 澄清哪些语义使得请求具备幂等性。([#1449](https://github.com/matrix-org/matrix-spec/issues/1449)) +- 改进客户端如何使用推送规则的文档说明。([#1461](https://github.com/matrix-org/matrix-spec/issues/1461)) +- 澄清服务器应在未指定时强制应用过滤器的默认 `limit`。([#1463](https://github.com/matrix-org/matrix-spec/issues/1463)) +- 按照 [MSC3873](https://github.com/matrix-org/matrix-spec-proposals/pull/3873) 和 [MSC3980](https://github.com/matrix-org/matrix-spec-proposals/pull/3980),澄清推送规则处理中带点的属性名的使用方式。([#1464](https://github.com/matrix-org/matrix-spec/issues/1464)) +- 修正注册端点说明的措辞与排版。由 @HarHarLinks 贡献。([#1474](https://github.com/matrix-org/matrix-spec/issues/1474)) +- 删除关于房间中无 `m.room.power_levels` 事件时 `state_default` 为 0 的过时说明。([#1479](https://github.com/matrix-org/matrix-spec/issues/1479)) +- 移除 `/keys/query` 端点上虚构的 `token` 参数。([#1485](https://github.com/matrix-org/matrix-spec/issues/1485)) +- 修正具备类型列表的属性渲染展示。([#1487](https://github.com/matrix-org/matrix-spec/issues/1487)) +- 澄清跨签名签名上传请求的部分细节。([#1495](https://github.com/matrix-org/matrix-spec/issues/1495)) +- 按照 [MSC3987](https://github.com/matrix-org/matrix-spec-proposals/pull/3987),移除 `dont_notify` 和 `coalesce` 推送规则动作。([#1501](https://github.com/matrix-org/matrix-spec/issues/1501)) +- 通过部分还原 [f1f32d3](https://github.com/matrix-org/matrix-spec/commit/f1f32d3a15c325ee8aa9d2c6bafd96c38069bb53) 澄清 `m.location` 协议。由 @HarHarLinks 贡献。([#1507](https://github.com/matrix-org/matrix-spec/issues/1507)) +- 在 `m.room.join_rules` schema 中添加缺失的 `knock_restricted` 加入规则。([#1535](https://github.com/matrix-org/matrix-spec/issues/1535)) + +## 服务器-服务器 API + +规范澄清 + +- 修正规范中的各种拼写错误。([#1431](https://github.com/matrix-org/matrix-spec/issues/1431), [#1447](https://github.com/matrix-org/matrix-spec/issues/1447), [#1466](https://github.com/matrix-org/matrix-spec/issues/1466), [#1518](https://github.com/matrix-org/matrix-spec/issues/1518)) +- 通过移除对 `examples/minimal_pdu.json` 的无效 OpenAPI 引用,修正 PDU 示例。([#1454](https://github.com/matrix-org/matrix-spec/issues/1454)) +- 从 `/_matrix/key/v2/server/` 移除遗留的 `{key_id}`。([#1473](https://github.com/matrix-org/matrix-spec/issues/1473)) +- 从参考哈希计算部分移除多余的 `age_ts` 字段。([#1536](https://github.com/matrix-org/matrix-spec/issues/1536)) + +## 应用服务 API + +新增端点 + +- [`POST /_matrix/app/v1/ping`](/application-service-api/#post_matrixappv1ping) ([#1516](https://github.com/matrix-org/matrix-spec/issues/1516)) +- [`POST /_matrix/client/v1/appservice/{appserviceId}/ping`](/application-service-api/#post_matrixclientv1appserviceappserviceidping) ([#1516](https://github.com/matrix-org/matrix-spec/issues/1516)) + +向后兼容性变更 + +- 按照 [MSC2659](https://github.com/matrix-org/matrix-spec-proposals/pull/2659) 添加 homeserver->appservice ping 机制,由 @tulir(@beeper)贡献。([#1516](https://github.com/matrix-org/matrix-spec/issues/1516), [#1541](https://github.com/matrix-org/matrix-spec/issues/1541)) + +规范澄清 + +- 修正规范中的各种拼写错误。([#1447](https://github.com/matrix-org/matrix-spec/issues/1447)) + +## 身份服务 API + +规范澄清 + +- 修正了 `/_matrix/identity/v2/store-invite` 的响应格式。([#1486](https://github.com/matrix-org/matrix-spec/issues/1486)) + +## 推送网关 API + +无重大变更。 + +## 房间版本 + +规范澄清 + +- 澄清早期房间版本中事件 ID 格式。([#1484](https://github.com/matrix-org/matrix-spec/issues/1484)) + +## 附录 + +规范澄清 + +- 说明“规范化 JSON (Canonical JSON)” 是 Matrix 规范中的特定术语。([#1468](https://github.com/matrix-org/matrix-spec/issues/1468)) +- 移除与群组相关的内容。([#1483](https://github.com/matrix-org/matrix-spec/issues/1483)) +- 澄清早期房间版本中事件 ID 格式。([#1484](https://github.com/matrix-org/matrix-spec/issues/1484)) + +## 内部变更/工具 + +规范澄清 + +- 更新对 Inter 字体的引用。([#1444](https://github.com/matrix-org/matrix-spec/issues/1444)) +- 端点披露内容现在仅显示 URL。([#1446](https://github.com/matrix-org/matrix-spec/issues/1446)) +- 在存在其他属性时将 $ref 包装在 allOf 中,以提升对 OpenAPI 的兼容性。([#1457](https://github.com/matrix-org/matrix-spec/issues/1457)) +- 对 GitHub Actions 工作流进行小幅优化。([#1476](https://github.com/matrix-org/matrix-spec/issues/1476)) +- 修正附加属性的锚点生成。([#1488](https://github.com/matrix-org/matrix-spec/issues/1488)) +- 修正规范中的各种拼写错误。([#1534](https://github.com/matrix-org/matrix-spec/issues/1534)) +- 补充更多规范发布时间线/流程的文档。([#1538](https://github.com/matrix-org/matrix-spec/issues/1538)) diff --git a/locales/zh-Hans/changelog/v1.8.md b/locales/zh-Hans/changelog/v1.8.md new file mode 100644 index 00000000..14781dac --- /dev/null +++ b/locales/zh-Hans/changelog/v1.8.md @@ -0,0 +1,118 @@ +--- +title: v1.8 更新日志 +linkTitle: v1.8 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2023-08-23 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +**向后兼容的变更** + +- 按照 [MSC2249](https://github.com/matrix-org/matrix-spec-proposals/pull/2249) 要求,调用者必须已加入房间才能举报其事件。([#1517](https://github.com/matrix-org/matrix-spec/issues/1517)) + +**规范澄清** + +- 修复 `m.reaction` 事件的 JSON schema 定义中缺失的 `type` 属性。贡献者:@chebureki。([#1552](https://github.com/matrix-org/matrix-spec/issues/1552)) +- 确保示例类型与定义中的 schema 匹配。([#1563](https://github.com/matrix-org/matrix-spec/issues/1563)) +- 允许在 `POST /publicRooms` 端点 schema 的 `room_types` 中为 `null`。([#1564](https://github.com/matrix-org/matrix-spec/issues/1564)) +- 修复损坏的标题格式。贡献者:@midnightveil。([#1578](https://github.com/matrix-org/matrix-spec/issues/1578)) +- 渲染二进制请求和响应体。([#1579](https://github.com/matrix-org/matrix-spec/issues/1579)) +- 修正 SAS 验证中 MAC 计算的描述。([#1590](https://github.com/matrix-org/matrix-spec/issues/1590)) +- 更新 SAS emoji 定义数据的链接。([#1593](https://github.com/matrix-org/matrix-spec/issues/1593)) +- 修复规范文档中的各种拼写错误。([#1597](https://github.com/matrix-org/matrix-spec/issues/1597)) + + +## 服务器-服务器 API + +**弃用** + +- 按照 [MSC4040](https://github.com/matrix-org/matrix-spec-proposals/pull/4040) ,弃用服务器发现中的 `matrix` SRV 查询步骤。([#1624](https://github.com/matrix-org/matrix-spec/issues/1624)) + +**向后兼容的变更** + +- 按照 [MSC4040](https://github.com/matrix-org/matrix-spec-proposals/pull/4040) ,在服务器发现中添加 `matrix-fed` SRV 查询步骤。([#1624](https://github.com/matrix-org/matrix-spec/issues/1624)) + +**规范澄清** + +- 记录 `/state_ids` 返回 404 的原因。([#1521](https://github.com/matrix-org/matrix-spec/issues/1521)) +- 修正 `POST /_matrix/federation/v1/user/keys/claim` 的响应定义。([#1559](https://github.com/matrix-org/matrix-spec/issues/1559)) +- 修正服务端密钥定义中的示例。([#1560](https://github.com/matrix-org/matrix-spec/issues/1560)) +- 确保示例类型与定义中的 schema 匹配。([#1563](https://github.com/matrix-org/matrix-spec/issues/1563)) +- 允许在 `POST /publicRooms` 端点 schema 的 `room_types` 中为 `null`。([#1564](https://github.com/matrix-org/matrix-spec/issues/1564)) +- 修复损坏的标题格式。贡献者:@midnightveil。([#1578](https://github.com/matrix-org/matrix-spec/issues/1578)) +- 删除关于 SRV 记录查询时“默认端口”的多余内容。([#1615](https://github.com/matrix-org/matrix-spec/issues/1615)) +- 服务器名称解析步骤改为有序列表。([#1623](https://github.com/matrix-org/matrix-spec/issues/1623)) + + +## 应用服务 API + +**规范澄清** + +- 修正第三方查找查询中自定义 `fields` 的类型。([#1584](https://github.com/matrix-org/matrix-spec/issues/1584)) + + +## 身份服务 API + +**规范澄清** + +- 确保示例类型与定义中的 schema 匹配。([#1563](https://github.com/matrix-org/matrix-spec/issues/1563)) + + +## 推送网关 API + +无重大变更。 + + +## 房间版本 + +**向后兼容的变更** + +- 按照 [MSC3820](https://github.com/matrix-org/matrix-spec-proposals/pull/3820) 添加房间版本 11。([#1604](https://github.com/matrix-org/matrix-spec/issues/1604)) +- 按照 [MSC2174](https://github.com/matrix-org/matrix-spec-proposals/pull/2174) ,在房间版本 11 中将 `redacts` 从顶层移至 `m.room.redaction` 事件的 `content`。([#1604](https://github.com/matrix-org/matrix-spec/issues/1604)) +- 按照 [MSC2175](https://github.com/matrix-org/matrix-spec-proposals/pull/2175) ,在房间版本 11 中从 `m.room.creator` 事件中移除 `creator`。([#1604](https://github.com/matrix-org/matrix-spec/issues/1604)) +- 按照 [MSC3989](https://github.com/matrix-org/matrix-spec-proposals/pull/3989) ,在房间版本 11 中移除事件中剩余的 `origin` 用法。([#1604](https://github.com/matrix-org/matrix-spec/issues/1604)) +- 按照 [MSC2176](https://github.com/matrix-org/matrix-spec-proposals/pull/2176) 和 [MSC3821](https://github.com/matrix-org/matrix-spec-proposals/pull/3821) ,更新房间版本 11 的撤回规则。([#1604](https://github.com/matrix-org/matrix-spec/issues/1604)) + + +## 附录 + +**向后兼容的变更** + +- 按照 [MSC4009](https://github.com/matrix-org/matrix-spec-proposals/pull/4009) ,允许在 Matrix ID 中使用 `+`。([#1583](https://github.com/matrix-org/matrix-spec/issues/1583)) + +**规范澄清** + +- 澄清规范中关于 canonical JSON 如何处理负零;同时,给出负零和一个大十次幂的例子。([#1573](https://github.com/matrix-org/matrix-spec/issues/1573)) + + +## 内部变更/工具链 + +**向后兼容的变更** + +- 将 Swagger 数据升级到 OpenAPI 3.1。([#1310](https://github.com/matrix-org/matrix-spec/issues/1310)) +- 创建 `@matrix-org/spec` npm 包,用于发布 SAS Emoji 数据定义与翻译。([#1620](https://github.com/matrix-org/matrix-spec/issues/1620)) + +**规范澄清** + +- 更新 CI 以校验更新日志条目的文件扩展名。([#1542](https://github.com/matrix-org/matrix-spec/issues/1542)) +- 披露部分在折叠时只显示标题。([#1549](https://github.com/matrix-org/matrix-spec/issues/1549)) +- 修复新版 Hugo 下的侧边栏显示问题。([#1551](https://github.com/matrix-org/matrix-spec/issues/1551)) +- 升级 jsonschema,用于依据 Draft 2020-12 校验 JSON Schemas。([#1556](https://github.com/matrix-org/matrix-spec/issues/1556)) +- 使用 Redocly CLI 校验 OpenAPI 定义。([#1558](https://github.com/matrix-org/matrix-spec/issues/1558)) +- 使用标签名作为 OpenAPI 定义的版本。([#1561](https://github.com/matrix-org/matrix-spec/issues/1561)) +- 确认 `x-changedInMatrixVersion` 的版本为字符串类型。([#1562](https://github.com/matrix-org/matrix-spec/issues/1562)) +- 澄清文档风格指南中语法 ABNF 的使用。([#1582](https://github.com/matrix-org/matrix-spec/issues/1582)) +- 移除 JSON schemas 中不必要的 `oneOf`。([#1585](https://github.com/matrix-org/matrix-spec/issues/1585)) +- 更新用于渲染规范的 Hugo 版本至 v0.113.0。([#1591](https://github.com/matrix-org/matrix-spec/issues/1591)) +- 修复新版本 towncrier 导致的更新日志渲染问题。([#1598](https://github.com/matrix-org/matrix-spec/issues/1598)) +- 改进桌面端显示下表格的布局。贡献者:Martin Fischer。([#1601](https://github.com/matrix-org/matrix-spec/issues/1601)) diff --git a/locales/zh-Hans/changelog/v1.9.md b/locales/zh-Hans/changelog/v1.9.md new file mode 100644 index 00000000..a7eea0a4 --- /dev/null +++ b/locales/zh-Hans/changelog/v1.9.md @@ -0,0 +1,89 @@ +--- +title: v1.9 变更日志 +linkTitle: v1.9 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2023-11-29 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +## 客户端-服务器 API + +**向后兼容的更改** + +- 根据 [MSC3958](https://github.com/matrix-org/matrix-spec-proposals/pull/3958) 添加了 `m.rule.suppress_edits` 默认推送规则。([#1617](https://github.com/matrix-org/matrix-spec/issues/1617)) + +**规范澄清** + +- 修正了 `m.call.negotiate` 的 schema 和示例。([#1546](https://github.com/matrix-org/matrix-spec/issues/1546)) +- 根据 [MSC1772](https://github.com/matrix-org/matrix-spec-proposals/pull/1772) 澄清了 `m.space.parent` 和 `m.space.child` 必须包含 `via` 属性。由 @PaarthShah 贡献。([#1618](https://github.com/matrix-org/matrix-spec/issues/1618)) +- 在 `/publicRooms` API 中新增说明,表明服务器名称区分大小写。([#1638](https://github.com/matrix-org/matrix-spec/issues/1638)) +- 澄清了缺失 `name` 字段的 `m.room.name` 事件并非预期行为。([#1639](https://github.com/matrix-org/matrix-spec/issues/1639)) +- 修正了 `GET /initialSync` 中用于账户数据和在线状态事件的 schema。([#1647](https://github.com/matrix-org/matrix-spec/issues/1647)) +- 修正了规范中的多处拼写错误。([#1658](https://github.com/matrix-org/matrix-spec/issues/1658), [#1661](https://github.com/matrix-org/matrix-spec/issues/1661), [#1665](https://github.com/matrix-org/matrix-spec/issues/1665)) +- 修复了 `.m.rule.suppress_notices` 推送规则不是有效 JSON 的问题。([#1671](https://github.com/matrix-org/matrix-spec/issues/1671)) +- 为 `PushConditions` 对象补充了 `event_property_is` 和 `event_property_contains` 推送条件所缺失的属性。([#1673](https://github.com/matrix-org/matrix-spec/issues/1673)) +- 指明了后备密钥应包含 `fallback` 属性并设置为 `true`。([#1676](https://github.com/matrix-org/matrix-spec/issues/1676)) +- 澄清了主题根消息不被视为主题内消息。([#1677](https://github.com/matrix-org/matrix-spec/issues/1677)) + + +## 服务器-服务器 API + +**规范澄清** + +- 修正了 `m.receipt` EDU 的 schema。([#1636](https://github.com/matrix-org/matrix-spec/issues/1636)) +- 修正了规范中的多处拼写错误。([#1661](https://github.com/matrix-org/matrix-spec/issues/1661)) +- 澄清了针对非本地用户的联邦请求为无效请求。([#1672](https://github.com/matrix-org/matrix-spec/issues/1672)) + + +## 应用服务 API + +无重大更改。 + + +## 身份服务 API + +无重大更改。 + + +## 推送网关 API + +无重大更改。 + + +## 房间版本 + +无重大更改。 + + +## 附录 + +**规范澄清** + +- 澄清了时间戳规范关于闰秒的说明。([#1627](https://github.com/matrix-org/matrix-spec/issues/1627)) +- 修正了规范中的多处拼写错误。([#1652](https://github.com/matrix-org/matrix-spec/issues/1652)) + + +## 内部变更/工具链 + +**向后兼容的更改** + +- 为 OpenAPI 定义和 JSON Schemas 增加了更多 CI 检查。([#1656](https://github.com/matrix-org/matrix-spec/issues/1656)) +- 生成了服务器-服务器 OpenAPI 定义。([#1657](https://github.com/matrix-org/matrix-spec/issues/1657)) + +**规范澄清** + +- 将所有 Swagger 的表述替换为 OpenAPI。([#1633](https://github.com/matrix-org/matrix-spec/issues/1633)) +- 修正了 JSON schema 中的枚举类型。([#1634](https://github.com/matrix-org/matrix-spec/issues/1634)) +- 修正了 `m.mentions` 对象的 schema。([#1635](https://github.com/matrix-org/matrix-spec/issues/1635)) +- 修正了客户端-服务器 API 中 `m.receipt` 事件的渲染问题。([#1637](https://github.com/matrix-org/matrix-spec/issues/1637)) +- 移除了 appservice 协议定义中必需的 `fieldname` 字段。([#1646](https://github.com/matrix-org/matrix-spec/issues/1646)) +- 修正了负责发布 @matrix-org/spec 包的 GitHub Action 工作流。([#1648](https://github.com/matrix-org/matrix-spec/issues/1648)) +- 升级了 GitHub actions。([#1660](https://github.com/matrix-org/matrix-spec/issues/1660)) diff --git a/locales/zh-Hans/client-server-api/_index.md b/locales/zh-Hans/client-server-api/_index.md new file mode 100644 index 00000000..17d2ea88 --- /dev/null +++ b/locales/zh-Hans/client-server-api/_index.md @@ -0,0 +1,2009 @@ +--- +title: "客户端-服务器 API" +weight: 10 +type: docs +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +客户端-服务器 API 允许客户端发送消息、控制房间以及同步会话历史。该 API 既支持不存储状态、按需从服务器延迟加载数据的轻量级客户端,也支持维护完整本地持久状态副本的重量级客户端。 + +## API 标准 + +Matrix 中客户端与服务器通信的强制性基线是通过 HTTP API 交换 JSON 对象。未来可以指定更高效的传输方式,作为可选扩展。 + +建议使用 HTTPS 进行通信。除测试环境外,不推荐使用明文 HTTP。 + +客户端通过不透明的 `access_token` 字符串进行认证(详见 [客户端认证](#客户端认证))。 + +除下述例外,所有 `POST` 和 `PUT` 端点均要求客户端在请求体中提供(可能为空的)JSON 对象。对于所有带有 JSON 请求体的请求,客户端应在请求头中带上 `Content-Type: application/json`,但这不是强制要求。 + +例外包括: + +- [`POST /_matrix/media/v3/upload`](#post_matrixmediav3upload) 与 [`PUT /_matrix/media/v3/upload/{serverName}/{mediaId}`](#put_matrixmediav3uploadservernamemediaid),两者的请求体为上传的媒体内容。 +- [`POST /_matrix/client/v3/logout`](#post_matrixclientv3logout) 以及 [`POST /_matrix/client/v3/logout/all`](#post_matrixclientv3logoutall),请求体为空。 + +同理,所有端点都要求服务器返回一个 JSON 对象,除非对 [内容仓库模块](#content-repository) 中媒体下载端点返回的 200 响应。服务器必须为所有 JSON 响应添加 `Content-Type: application/json` 响应头。 + +所有请求和响应中的 JSON 数据必须使用 UTF-8 编码。 + +参见附录中的 [Matrix API 规范约定](/appendices#conventions-for-matrix-apis) 以及下文 [Web 浏览器客户端](#web-浏览器客户端) 对服务器响应的附加要求。 + +### 标准错误响应 + +Matrix API 层发生的任何错误**必须**返回“标准错误响应”。格式如下: + +```json +{ + "errcode": "", + "error": "" +} +``` + +`error` 字符串为易读的错误消息,通常是一句简要说明出错原因的语句。 + +`errcode` 是唯一字符串,可用于处理错误信息,例如 `M_FORBIDDEN`。错误码的命名空间应全部大写,后接一个下划线 `_`。例如自定义命名空间 `com.mydomain.here` 和代码 `FORBIDDEN`,错误码应为 `COM.MYDOMAIN.HERE_FORBIDDEN`。本规范定义的错误码以 `M_` 开头。 + +某些 `errcode` 定义了附加的键应在错误响应对象中出现,但 `error` 和 `errcode` 键**必须**始终存在。 + +一般建议通过错误码而不是 HTTP 状态码来表达错误。当遇到 `M_UNKNOWN` 错误码时,客户端应优先参考 HTTP 状态码,作为更可靠的问题指示。例如,若客户端收到 `M_NOT_FOUND` 错误码但请求返回 400 Bad Request,则应按资源未找到处理该错误。然而,若客户端收到 `M_UNKNOWN` 错误码和 400 Bad Request,应认为请求无效。 + +#### 常见错误码 + +这些错误码可以被任意 API 端点返回: + +`M_FORBIDDEN` +禁止访问,例如无权限加入房间、登录失败。 + +`M_UNKNOWN_TOKEN` +指定的访问令牌或刷新令牌未被识别。 + +若 HTTP 401 响应返回时包含额外参数 `soft_logout`,详见 [软登出说明](#软登出)。 + +`M_MISSING_TOKEN` +请求未指定访问令牌。 + +`M_USER_LOCKED` +账户已被[锁定](#账户锁定),暂时无法使用。 + +`M_USER_SUSPENDED` +账户已被[停用](#账户停用),目前仅可执行有限操作。 + +`M_BAD_JSON` +请求包含合法的 JSON,但某种方式上格式不正确,例如缺少必需键、键值无效等。 + +`M_NOT_JSON` +请求未包含有效的 JSON。 + +`M_NOT_FOUND` +请求未找到资源。 + +`M_LIMIT_EXCEEDED` +短时间内请求过多。请等待一段时间后重试。参见 [速率限制](#速率限制)。 + +`M_UNRECOGNIZED` +服务器无法理解请求。若端点未实现,建议返回 404;端点已实现但使用了错误 HTTP 方法,应返回 405。 + +`M_UNKNOWN` +发生未知错误。 + +#### 其他错误码 + +下列错误码专用于特定端点。 + + + +`M_UNAUTHORIZED` +请求未正确验证,通常由于登录失败。 + +`M_USER_DEACTIVATED` +请求关联的用户 ID 已停用。通常见于验证身份的端点,诸如 [`/login`](#get_matrixclientv3login)。 + +`M_USER_IN_USE` +尝试注册已被占用的用户 ID 时遇到。 + +`M_INVALID_USERNAME` +尝试注册非法用户 ID 时遇到。 + +`M_ROOM_IN_USE` +`createRoom` API 提供的房间别名已被占用时返回。 + +`M_INVALID_ROOM_STATE` +`createRoom` API 提供的初始状态无效时返回。 + +`M_THREEPID_IN_USE` +API 提供的 threepid 已被另一账号使用,无法再次使用。 + +`M_THREEPID_NOT_FOUND` +API 提供的 threepid 未找到记录,无法使用。 + +`M_THREEPID_AUTH_FAILED` +无法对第三方标识符执行认证。 + +`M_THREEPID_DENIED` +服务器不允许使用该第三方标识符。例如服务器只允许特定域名的邮箱。 + +`M_SERVER_NOT_TRUSTED` +客户端请求用到的第三方服务器(如身份服务器)不被当前服务器信任。 + +`M_UNSUPPORTED_ROOM_VERSION` +客户端请求创建房间时使用了服务器不支持的房间版本。 + +`M_INCOMPATIBLE_ROOM_VERSION` +客户端尝试加入服务器不支持版本的房间。请检查错误响应中的 `room_version` 属性以获取房间版本。 + +`M_BAD_STATE` +无法执行请求的状态变更,例如尝试解禁未被禁言的用户。 + +`M_GUEST_ACCESS_FORBIDDEN` +房间或资源不允许访客访问。 + +`M_CAPTCHA_NEEDED` +完成请求需要验证码。 + +`M_CAPTCHA_INVALID` +提供的验证码与预期不符。 + +`M_MISSING_PARAM` +请求缺少必需参数。 + +`M_INVALID_PARAM` +请求参数值类型错误。例如,服务器期望整数却收到字符串。 + +`M_TOO_LARGE` +请求或实体体积过大。 + +`M_EXCLUSIVE` +请求的资源被应用服务保留,或发起请求的应用服务未创建该资源。 + +`M_RESOURCE_LIMIT_EXCEEDED` +由于主服务器资源限制,无法完成请求。例如,在共享主机环境的主服务器使用了过多内存或磁盘空间。错误必须包含 `admin_contact` 字段为用户提供联系方式。通常该错误会出现在尝试修改状态的路由(如发送消息、账户数据)而不是只读路由上(如 [`/sync`](#get_matrixclientv3sync),[`/user/{userId}/account_data/{type}`](#get_matrixclientv3useruseridaccount_datatype) 等)。 + +`M_CANNOT_LEAVE_SERVER_NOTICE_ROOM` +用户无法拒绝加入服务器通知房间的邀请。详见 [服务器通知](#server-notices) 模块。 + +`M_THREEPID_MEDIUM_NOT_SUPPORTED` +主服务器不支持添加指定 medium 的第三方标识符。 + +`M_THREEPID_IN_USE` +客户端指定的第三方标识符不可接受,因为已被使用。 + +#### 速率限制 + +主服务器**应当**实现速率限制以降低被过载风险。当请求因速率限制被拒绝时,应返回标准错误响应格式如下: + +```json +{ + "errcode": "M_LIMIT_EXCEEDED", + "error": "string", + "retry_after_ms": integer (可选,已弃用) +} +``` + +主服务器**应**为所有 429 状态码的响应包含 [`Retry-After`](https://www.rfc-editor.org/rfc/rfc9110#field.retry-after) 响应头。 + +`retry_after_ms` 属性可告知客户端需等待多少毫秒后再试。该属性已弃用,应优先采用 `Retry-After` 响应头。 + +{{% changed-in v="1.10" %}}:`retry_after_ms` 属性已弃用,请使用 `Retry-After` 响应头。 + +### 事务标识符 + +客户端-服务器 API 通常使用 `HTTP PUT`,在 HTTP 路径中带上传递由客户端生成的事务标识符(Transaction ID)。 + +事务 ID 的目的在于帮助主服务器区分新请求与前次请求的重发,实现请求幂等性。 + +事务 ID **仅**用于此目的。 + +请求完成后,客户端应更换下一次请求的 `{txnId}`。具体生成方式由实现自定,推荐使用 version 4 UUID 或当前时间戳与单调递增整数的拼接。 + +主服务器应当认定若事务 ID 与以前请求一致且 HTTP 请求路径一致,则为重发。 + +识别为重发时,主服务器应返回与原始请求相同的 HTTP 响应码和内容。例如 [`PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}`](#put_matrixclientv3roomsroomidsendeventtypetxnid) 会以 200 OK 和原始请求响应体中的 `event_id` 返回。 + +事务 ID 的作用范围仅限于单一[设备](../index.html#devices)和单一 HTTP 端点。换言之,同一设备可以用相同的事务 ID 向 [`PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}`](#put_matrixclientv3roomsroomidsendeventtypetxnid) 和 [`PUT /_matrix/client/v3/sendToDevice/{eventType}/{txnId}`](#put_matrixclientv3sendtodeviceeventtypetxnid) 请求,两者被视为互不相关端点。同样地,客户端在两次登录之间,用相同的事务 ID 进行两次请求也算不同请求(除非登录时指定了已存在的 `device_id`)。但如果在[刷新](#刷新访问令牌)访问令牌后,对同一端点重复使用事务 ID,则视为重复请求并予以忽略。参见 [访问令牌与设备的关系](#访问令牌与设备的关系)。 + +部分 API 端点允许或要求使用无需事务 ID 的 `POST` 请求。可选情况下,强烈建议使用 `PUT`。 + +{{% boxes/rationale %}} +`v1.7` 之前,事务 ID 的作用范围为“客户端会话”,而非设备。 +{{% /boxes/rationale %}} + +## Web 浏览器客户端 + +实际情况会有部分客户端以 web 浏览器或类似环境运行。此时主服务器应当响应预检请求,并在所有请求上提供跨域资源共享(CORS)头部。 + +服务器**必须**预期客户端将向其发送 `OPTIONS` 请求,以便客户端获取 CORS 头。本规范中的所有端点均支持 `OPTIONS` 方法,但服务器收到 `OPTIONS` 请求时**不得**执行端点定义的任何业务逻辑。 + +当客户端访问服务器发起请求,服务器应返回该路由的 CORS 头。推荐所有请求返回的 CORS 头为: + + Access-Control-Allow-Origin: * + Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS + Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization + +{{% boxes/note %}} +{{% added-in v="1.13" %}} `Access-Control-Allow-Methods` 响应头的推荐值仅覆盖规范现有端点。服务器如支持额外端点或方法,应相应添加。 + +此章节将在端点新增方法时同步更新。未来可能支持的如 `PATCH` 和 `HEAD`。 +{{% /boxes/note %}} + +## 服务器发现 + +为便于用户无需明确指定主服务器 URL 或其它参数即可连接到 Matrix 服务器,客户端**应**在登录时通过自动发现机制根据用户的 Matrix ID 确定服务器 URL。 + +本节下列术语含义如下: + +`PROMPT` +以适合当前客户端用户体验的方式从用户获取特定信息(客户端如有合适交互能力),如无法良好交互则可选择放弃。 + +`IGNORE` +停止当前自动发现机制。如无可用自动发现机制,则客户端可用其它方式获取所需参数(如提示用户或使用默认值)。 + +`FAIL_PROMPT` +提示用户自动发现因数据无效/为空而失败,并要求提供相应参数。 + +`FAIL_ERROR` +通知用户自动发现未返回可用 URL,当前登录流程终止,此时已获取合法数据但无服务器可用,不应再尝试其他可能性,用户需自主决定下一步。 + +### Well-known URI + +{{% boxes/note %}} +托管 `.well-known` JSON 文件的服务器**应**提供 CORS 头,参见 [CORS](#web-浏览器客户端)。 +{{% /boxes/note %}} + +`.well-known` 方法指在预定位置提供 JSON 文件以指定参数值。流程如下: + +1. 按 [服务器名](/appendices/#server-name) 规则,从用户 Matrix ID 截取第一个冒号后片段。 +2. 按 [语法](/appendices/#server-name) 从服务器名提取主机名。 +3. 以 GET 请求 `https://hostname/.well-known/matrix/client`。 + 1. 返回状态码 404 时处理为 `IGNORE`。 + 2. 状态码非 200 或响应体为空,处理为 `FAIL_PROMPT`。 + 3. 解析响应体为 JSON 对象,如失败则 `FAIL_PROMPT`。 + 4. 从 `m.homeserver` 属性提取 `base_url`,该值作为主服务器基础 URL。未提供则 `FAIL_PROMPT`。 + 5. 验证主服务器基础 URL: + 1. 按 URL 解析,如错误则 `FAIL_ERROR`。 + 2. 客户端**应**连接 [`/_matrix/client/versions`](/client-server-api/#get_matrixclientversions) 端点,确保无错误并验证响应符合预期格式。如任一步失败,处理为 `FAIL_ERROR`。这步仅用于排除配置错误,确认地址有效。 + 3. 注意 `base_url` 可能带 `/` 结尾,调用方需兼容两种。 + 6. 若存在 `m.identity_server`,从中提取 `base_url` 用作身份服务器基础 URL。其验证与上面主服务器 URL 验证一致,连接端点为 `/_matrix/identity/v2`。如果 `m.identity_server` 存在但无 `base_url`,则 `FAIL_PROMPT`。 + +{{% http-api spec="client-server" api="wellknown" %}} + +{{% http-api spec="client-server" api="versions" %}} + +{{% http-api spec="client-server" api="support" %}} + +## 客户端认证 + +多数 API 端点要求用户通过访问令牌(access token)认证身份。访问令牌通常通过 [登录](#登录) 或 [注册](#账户注册与管理) 流程获得,令牌可能失效;可用刷新令牌重新生成。 + +{{% boxes/note %}} +本规范不强制规定访问令牌格式。客户端应将其视为不透明字节序列。服务器可自由选择合适的格式。服务器实现者可参考[macaroons](http://research.google.com/pubs/pub41892.html)。 +{{% /boxes/note %}} + +### 使用访问令牌 + +可通过请求头及 Authentication Bearer 方案提供访问令牌:`Authorization: Bearer TheTokenHere`。 + +也可通过查询字符串参数 `access_token=TheTokenHere` 提供,但因易被日志泄露,已弃用,客户端**不应**使用。 + +主服务器**必须**同时支持两种方式。 + +{{% boxes/note %}} +{{% changed-in v="1.11" %}} +以查询字符串方式传递访问令牌现已弃用。 +{{% /boxes/note %}} + +如缺少或非法凭据,请求返回 401 状态及错误码,分别为 `M_MISSING_TOKEN` 或 `M_UNKNOWN_TOKEN`。注意,`M_UNKNOWN_TOKEN` 可能有以下四种情况: + +1. 访问令牌从未有效; +2. 访问令牌已注销; +3. 访问令牌已[软登出](#软登出); +4. {{% added-in v="1.3" %}} 访问令牌需要[刷新](#刷新访问令牌)。 + +当客户端收到 `M_UNKNOWN_TOKEN` 错误码,应: + +- 如有刷新令牌,尝试[刷新令牌](#刷新访问令牌); +- 若响应中 `soft_logout` 为 `true`,可提示用户重新登录并保留客户端已持久化的信息; +- 否则,视为用户已登出。 + +### 访问令牌与设备关系 + +客户端[设备](../index.html#devices)与访问令牌及刷新令牌密切相关。Matrix 服务器应记录每个访问令牌与刷新令牌所绑定设备,以保证请求正确处理。用刷新令牌生成新访问/刷新令牌时,新一对令牌归属于原刷新令牌关联设备。 + +默认情况下,[登录](#登录)与[注册](#账户注册与管理)流程会自动生成新 `device_id`。客户端也可自定义 `device_id` 或(用户不变时)复用设备,并在请求体中带上 `device_id`;若客户端传入 `device_id`,服务器会使该设备此前的访问及刷新令牌失效。 + +### 刷新访问令牌 + +{{% added-in v="1.3" %}} + +访问令牌可能在一定时限后过期。使用过期令牌发起 HTTP 调用会返回 `M_UNKNOWN_TOKEN` 错误码,且建议带有 `soft_logout: true`。客户端收到此错误且持有刷新令牌应调用 [`/refresh`](#post_matrixclientv3refresh) 刷新令牌。即使尚未过期也可主动刷新。刷新成功后应使用新令牌发起后续请求,并可用新令牌重试先前失败请求。返回新刷新令牌时,旧刷新令牌即失效,后续刷新需用新令牌。 + +旧刷新令牌在新访问/刷新令牌使用前仍有效,之后即被吊销,确保客户端若未取到或保存新令牌还能重复刷新。 + +若令牌刷新失败且错误响应带有 `soft_logout: true`,可视为[软登出](#软登出),尝试重新登录获取新访问令牌。否则,客户端应视为用户已登出。 + +不支持刷新令牌的客户端行为由主服务器决定;客户端通过在 [`/login`](#post_matrixclientv3login) 与 [`/register`](#post_matrixclientv3register) 请求体声明 `refresh_token: true` 表明支持刷新令牌。例如主服务器可允许使用永不过期的访问令牌,或依赖客户端软登出行为。 + +### 软登出 + +若服务器要求重新认证但不希望立即失效当前客户端会话,可通过在 `M_UNKNOWN_TOKEN` 错误响应中包含 `soft_logout: true` 标志进行软登出;`soft_logout` 默认为 `false`。若 `soft_logout` 被省略或为 `false`,则服务器已销毁会话,客户端不得重复利用;任何客户端持久信息如加密密钥和设备信息等须丢弃。若 `soft_logout` 为 `true`,客户端可复用持久状态。 + +{{% changed-in v="1.3" %}} 客户端收到软登出可优先[刷新访问令牌](#刷新访问令牌)(如有刷新令牌)。如无刷新令牌或刷新失败且为软登出,可借登录 API 指定已有设备 ID 获取新访问令牌。 + +{{% changed-in v="1.12" %}} 若响应同时携带 `M_USER_LOCKED` 错误码,则直到账户解锁前无法获取新的访问令牌。 + +### 用户交互式认证 API + +#### 总览 + +部分 API 端点需互动式认证(User-Interactive Authentication)。主服务器可提供多种认证方式,如用户名密码、单点登录(SSO)等。本规范不限制主服务器背后授权方式,仅定义标准接口以使任意客户端可登录任何主服务器。 + +认证过程由一系列“阶段”组成,每个阶段客户端向服务器提交一组认证数据并等待响应,响应可能为最终成功或要求下一阶段,交互继续至最终成功。 + +服务器为端点提供一种或多种“流”供客户端完成认证,每种流由一组有序阶段组成。客户端可自由选择认证流,但阶段必须依次完成。未按规定流程完成应返回 401。如所有阶段完成,认证即告完成,API 调用正常返回。 + +#### REST API 中的用户交互式认证 + +如本文档所述 REST API,认证流程由客户端与服务器之间交换 JSON 字典实现。服务器通过 401 响应体说明所需认证数据,客户端将其置于请求参数 `auth` 中提交。 + +客户端首次请求勿带 `auth` 参数。主服务器返回 401 状态码及如下 JSON 体: + +``` +HTTP/1.1 401 Unauthorized +Content-Type: application/json +``` + +```json +{ + "flows": [ + { + "stages": [ "example.type.foo", "example.type.bar" ] + }, + { + "stages": [ "example.type.foo", "example.type.baz" ] + } + ], + "params": { + "example.type.baz": { + "example_key": "foobar" + } + }, + "session": "xxxxxx" +} +``` + +`flows` 外,该对象包含: + +* `params`: 提供客户端使用所列认证类型所需补充信息。例如某认证类型作为键存储于此字典。举例 OAuth 客户端 ID 可放此信息。 +* `session`: 服务器颁发的会话标识符,客户后续认证时需返回。 + +客户端选定流并尝试完成首个阶段。向服务器重复发送原请求,新增 `auth` 字段,内容为类型名(type),会话标识符(session),以及类型相关的其它认证信息。例如阶段类型为 `example.type.foo` 时: + +``` +POST /_matrix/client/v3/endpoint HTTP/1.1 +Content-Type: application/json +``` + +```json +{ + "a_request_parameter": "something", + "another_request_parameter": "something else", + "auth": { + "type": "example.type.foo", + "session": "xxxxxx", + "example_credential": "verypoorsharedsecret" + } +} +``` + +如服务器认证成功但仍需更多阶段,则返回 401、响应结构与首次 401 相同,另加 `completed` 列表指示已完成的认证类型: + +``` +HTTP/1.1 401 Unauthorized +Content-Type: application/json +``` + +```json +{ + "completed": [ "example.type.foo" ], + "flows": [ + { + "stages": [ "example.type.foo", "example.type.bar" ] + }, + { + "stages": [ "example.type.foo", "example.type.baz" ] + } + ], + "params": { + "example.type.baz": { + "example_key": "foobar" + } + }, + "session": "xxxxxx" +} +``` + +如某阶段需多次请求才能完成,则响应同未认证,仅追加认证类型自定义内容。 + +若服务器认为当前阶段尝试失败,并允许重试,则返回同上,只是多了标准错误字段 `errcode` 和 `error`。例如: + +``` +HTTP/1.1 401 Unauthorized +Content-Type: application/json +``` + +```json +{ + "errcode": "M_FORBIDDEN", + "error": "Invalid password", + "completed": [ "example.type.foo" ], + "flows": [ + { + "stages": [ "example.type.foo", "example.type.bar" ] + }, + { + "stages": [ "example.type.foo", "example.type.baz" ] + } + ], + "params": { + "example.type.baz": { + "example_key": "foobar" + } + }, + "session": "xxxxxx" +} +``` + +如请求失败原因为认证以外的其他原因,则依标准格式返回错误消息。例如: + +``` +HTTP/1.1 400 Bad request +Content-Type: application/json +``` + +```json +{ + "errcode": "M_EXAMPLE_ERROR", + "error": "Something was wrong" +} +``` + +如已完成某流程全部阶段,主服务器执行业务正常返回。已完成的阶段无法重试,服务器必须返回 401 响应及已完成阶段,或如阶段都已完成则返回业务结果。 + +某些认证类型可由 Matrix 客户端以外方式完成,例如邮箱确认可通过点击邮件链接。此时,客户端带 session 会话重试,服务器响应与正常认证一致,依类型是否在‘completed’数组确定阶段是否完成。 + +{{% boxes/note %}} +使用交互式认证的端点,任何无认证数据的请求均不会成功。服务器如允许无认证完成请求应提供仅含 `m.login.dummy` 的阶段,但必须对无认证请求返回 401。 +{{% /boxes/note %}} + +#### 示例 + +一个包含三阶段认证流的 API 调用流程如下: + +``` + _______________________ + | Stage 0 | + | No auth | + | ___________________ | + | |_Request_1_________| | <-- 返回“session”键以供后续认证。 + |_______________________| + | + | + _________V_____________ + | Stage 1 | + | type: "" | + | ___________________ | + | |_Request_1_________| | + |_______________________| + | + | + _________V_____________ + | Stage 2 | + | type: "" | + | ___________________ | + | |_Request_1_________| | + | ___________________ | + | |_Request_2_________| | + | ___________________ | + | |_Request_3_________| | + |_______________________| + | + | + _________V_____________ + | Stage 3 | + | type: "" | + | ___________________ | + | |_Request_1_________| | <-- 正常返回 API 结果 + |_______________________| +``` + +#### 认证类型 + +本规范定义以下认证类型: +- `m.login.password` +- `m.login.recaptcha` +- `m.login.sso` +- `m.login.email.identity` +- `m.login.msisdn` +- `m.login.dummy` +- `m.login.registration_token` + +##### 基于密码 + +| 类型 | 描述 | +|----------------------|----------------------------------------| +| `m.login.password` | 客户端提交标识符和明文密码。 | + +用此方式时,`auth` 内容如下: + +``` +{ + "type": "m.login.password", + "identifier": { + ... + }, + "password": "", + "session": "" +} +``` + +`identifier` 属性为用户标识对象,详见 [标识符类型](#标识符类型)。 + +如用 Matrix ID 登录: + +```json +{ + "type": "m.login.password", + "identifier": { + "type": "m.id.user", + "user": "" + }, + "password": "", + "session": "" +} +``` + +也可用 [`/account/3pid`](#get_matrixclientv3account3pid) 绑定的 3PID 替代 `user`: + +```json +{ + "type": "m.login.password", + "identifier": { + "type": "m.id.thirdparty", + "medium": "<第三方标识符 medium>", + "address": "<用户 third-party 地址>" + }, + "password": "", + "session": "" +} +``` + +如主服务器不识别所提供的 3PID,应响应 403 Forbidden。 + +##### Google ReCaptcha + +| 类型 | 描述 | +|------------------------|----------------------------------------| +| `m.login.recaptcha` | 用户完成 Google ReCaptcha 2.0 验证。 | + +用法如下: + +```json +{ + "type": "m.login.recaptcha", + "response": "", + "session": "" +} +``` + +##### 单点登录(SSO) + +| 类型 | 描述 | +|------------------|------------------------------------------------------------------------| +| `m.login.sso` | 通过外部单点登录提供商认证。 | + +客户端用 SSO 完成认证时应采用 [Fallback](#fallback) 机制,详见[交互式认证中的 SSO](#sso-交互式认证-期间)。 + +##### 基于邮箱(身份/主服务器) + +| 类型 | 描述 | +|-----------------------------|---------------------------------------------------------------------------------------| +| `m.login.email.identity` | 通过身份服务器(或支持的主服务器)认证邮箱。 | + +用前需在身份服务器(或主服务器)完成邮箱认证。认证后需将 session 信息提交给主服务器。 + +示例: + +```json +{ + "type": "m.login.email.identity", + "threepid_creds": { + "sid": "<身份服务器 session id>", + "client_secret": "<身份服务器客户端密钥>", + "id_server": "<认证身份服务器地址,例如 'matrix.org:8090'>", + "id_access_token": "<以前注册身份服务器的 access token>" + }, + "session": "" +} +``` + +如 [`/requestToken`](#post_matrixclientv3registeremailrequesttoken) 时未包含 `id_server` 等,可省略该字段。 + +##### 基于手机号/MSISDN(身份/主服务器) + +| 类型 | 描述 | +|------------------------|--------------------------------------------------------------------------| +| `m.login.msisdn` | 通过身份服务器(或主服务器)认证手机号。 | + +用前需在身份服务器(或主服务器)完成手机号认证,后续将 session 信息提交主服务器。 + +示例: + +```json +{ + "type": "m.login.msisdn", + "threepid_creds": { + "sid": "<身份服务器 session id>", + "client_secret": "<身份服务器客户端密钥>", + "id_server": "<认证身份服务器地址,例如 'matrix.org:8090'>", + "id_access_token": "<以前注册身份服务器的 access token>" + }, + "session": "" +} +``` + +如 [`/requestToken`](#post_matrixclientv3registermsisdnrequesttoken) 无 `id_server`,可省略该字段。 + +##### Dummy 认证 + +| 类型 | 描述 | +|-----------------|---------------------------------------------| +| `m.login.dummy` | Dummy 认证始终成功且无需额外参数。 | + +Dummy 认证允许服务器无需任何用户交互即可完成请求,也可区分流程(例如存在子集包含关系的两个认证流,可用 Dummy 区分)。用时仅需传 type、session: + +```json +{ + "type": "m.login.dummy", + "session": "" +} +``` + +##### 令牌注册 + +{{% added-in v="1.2" %}} + +| 类型 | 描述 | +|-----------------------------|------------------------------------------------------| +| `m.login.registration_token`| 用预共享令牌认证注册账号。 | + +{{% boxes/note %}} +`m.login.registration_token` 仅适用于 [`/register`](#post_matrixclientv3register) 端点。 +{{% /boxes/note %}} + +此类型允许主服务器仅向有限用户开放注册(非完全开放/关闭),需带最大长度 64 的不透明标识符(参见 [Opaque Identifier](/appendices#opaque-identifiers))。服务器可任意定义令牌数量与有效期,如:限定 100 次、2 小时等,过期作废。 + +用法如下: + +```json +{ + "type": "m.login.registration_token", + "token": "fBVFdqVE", + "session": "" +} +``` + +如需确认令牌有效性可用下面的 `/validity` API,但此 API 不保障使用时令牌一定有效。 + +{{% http-api spec="client-server" api="registration_tokens" %}} + +##### 注册时服务条款 + +{{% added-in v="1.11" %}} + +| 类型 | 描述 | +|---------------------|----------------------------------------------------------| +| `m.login.terms` | 用户需接受服务条款、隐私政策等政策性文档。 | + +{{% boxes/note %}} +`m.login.terms` 仅适用于 [`/register`](#post_matrixclientv3register) 端点。 +{{% /boxes/note %}} + +主服务器要求新用户接受服务条款等政策性文件。文档可能有多类型、多版本、多语言。 + +服务器需通过 `/register` 返回 401,并在 `flows` 中包含 `m.login.terms`,`params` 内有结构见[下文](#definition-mloginterms-params)。 + +客户端遇到无效参数应终止注册并提示用户错误。 + +客户端应为每个政策提供勾选框及跳转链接,用户接受后提交仅含 type、session 的 `auth` 字段: + +```json +{ + "type": "m.login.terms", + "session": "" +} +``` + +服务器应记录注册过程展现的文档版本。 + +**示例** + +1. 客户端注册请求为: + + ``` + POST /_matrix/client/v3/register + ``` + ```json + { + "username": "cheeky_monkey", + "password": "ilovebananas" + } + ``` + +2. 服务器要求接受条款,返回: + + ``` + HTTP/1.1 401 Unauthorized + Content-Type: application/json + ``` + ```json + { + "flows": [ + { "stages": [ "m.login.terms" ] } + ], + "params": { + "m.login.terms": { + "policies": { + "terms_of_service": { + "version": "1.2", + "en": { + "name": "Terms of Service", + "url": "https://example.org/somewhere/terms-1.2-en.html" + }, + "fr": { + "name": "Conditions d'utilisation", + "url": "https://example.org/somewhere/terms-1.2-fr.html" + } + } + } + } + }, + "session": "kasgjaelkgj" + } + ``` + +3. 客户端将文档列表展现给用户并提示接受。 + +4. 用户确认全部接受后,客户端重复注册请求: + + ``` + POST /_matrix/client/v3/register + ``` + ```json + { + "username": "cheeky_monkey", + "password": "ilovebananas", + "auth": { + "type": "m.login.terms", + "session": "kasgjaelkgj" + } + } + ``` + +5. 所有认证步骤均已完成,请求成功: + + ``` + HTTP/1.1 200 OK + Content-Type: application/json + ``` + ```json + { + "access_token": "abc123", + "device_id": "GHTYAJCE", + "user_id": "@cheeky_monkey:matrix.org" + } + ``` + +{{% definition path="api/client-server/definitions/m.login.terms_params" %}} + +#### Fallback + +客户端无法预期支持所有认证类型。如遇不识别的认证类型可引导用户于浏览器打开备用页面,完成此阶段。URL 格式: + + /_matrix/client/v3/auth//fallback/web?session= + +其中 `auth type` 为类型名,`session ID` 为会话标识。 + +回调页面**必须**返回 HTML,可以完成该认证并用如下 JS 通知客户端: + +```js +if (window.onAuthDone) { + window.onAuthDone(); +} else if (window.opener && window.opener.postMessage) { + window.opener.postMessage("authDone", "*"); +} +``` + +这样客户端可在内嵌浏览器用 `onAuthDone` 回调,或用 HTML5 [跨文档消息](https://www.w3.org/TR/webmessaging/#web-messaging) API。 + +收到通知后客户端应以仅含 session ID 的 `auth` 字段重发请求: + +```json +{ + "session": "" +} +``` + +##### 示例 + +网页客户端可用如下 JS 打开处理未知认证类型的弹窗: + +```js +/** + * 参数: + * homeserverUrl: 主服务器基础地址 (如 "https://matrix.org") + * apiEndpoint: 正在使用的 API 端点 (如 "/_matrix/client/v3/account/password") + * loginType: 正在认证的类型 (如 "m.login.recaptcha") + * sessionID: 主服务器颁发的会话标识符 + * onComplete: 认证完成的回调,参数为请求响应内容 + */ +function unknownLoginType(homeserverUrl, apiEndpoint, loginType, sessionID, onComplete) { + var popupWindow; + + var eventListener = function(ev) { + // 检查消息和来源 + if (ev.data !== "authDone" || ev.origin !== homeserverUrl) { + return; + } + + // 关闭弹窗 + popupWindow.close(); + window.removeEventListener("message", eventListener); + + // 重发请求 + var requestBody = { + auth: { + session: sessionID, + }, + }; + + request({ + method:'POST', url:apiEndpoint, json:requestBody, + }, onComplete); + }; + + window.addEventListener("message", eventListener); + + var url = homeserverUrl + + "/_matrix/client/v3/auth/" + + encodeURIComponent(loginType) + + "/fallback/web?session=" + + encodeURIComponent(sessionID); + + popupWindow = window.open(url); +} +``` + +#### 标识符类型 + +部分认证方式通过用户标识符对象(identifier)标识用户。用户标识对象含 `type` 字段指明类型,根据类型含有不同的必需字段。 + +本规范定义如下标识符类型: +- `m.id.user` +- `m.id.thirdparty` +- `m.id.phone` + +##### Matrix 用户 ID + +| 类型 | 描述 | +|-------------|-----------------------------| +| `m.id.user` | 以 Matrix ID 标识用户。 | + +通过 Matrix ID 标识用户,既可以是全限定 ID,也可以是本地用户名。 + +```json +"identifier": { + "type": "m.id.user", + "user": "" +} +``` + +##### 第三方 ID + +| 类型 | 描述 | +|--------------------|-------------------------------------------------| +| `m.id.thirdparty` | 以规范化第三方标识符标识用户。 | + +通过 3PID 标识用户,3PID 绑定见 [`/account/3pid`](#get_matrixclientv3account3pid),medium 列表见 [3PID 类型](/appendices#3pid-types)。 + +```json +"identifier": { + "type": "m.id.thirdparty", + "medium": "<第三方标识符类型>", + "address": "<用户第三方标识符地址>" +} +``` + +##### 手机号 + +| 类型 | 描述 | +|---------------|-------------------------------| +| `m.id.phone` | 以手机号标识用户。 | + +以绑定手机号标识用户,手机号可由用户原样输入,由主服务器规范化。如需客户端自规范,可用 `m.id.thirdparty` 类型并设置 `medium: msisdn`。 + +```json +"identifier": { + "type": "m.id.phone", + "country": "<手机号归属国家>", + "phone": "<手机号>" +} +``` + +`country` 是两位大写 ISO-3166-1 alpha-2 国家码,`phone` 按该区域拨号规范解析。 + +### 登录 + +客户端可用 [`/login`](#post_matrixclientv3login) API 获取访问令牌。 + +该端点 当前不 使用 [用户交互式认证 API](#用户交互式认证-api)。 + +用户名/密码登录示例: + +```json +{ + "type": "m.login.password", + "identifier": { + "type": "m.id.user", + "user": "" + }, + "password": "" +} +``` + +也可用 [`/account/3pid`](#get_matrixclientv3account3pid) 绑定的 3PID: + +```json +{ + "type": "m.login.password", + "identifier": { + "medium": "<第三方标识符类型>", + "address": "<用户规范化的第三方标识符地址>" + }, + "password": "" +} +``` + +主服务器不识别 3PID 时返回 403 Forbidden。 + +用登录令牌登录的方法如下: + +```json +{ + "type": "m.login.token", + "token": "" +} +``` + +`token` 必须编码用户 ID(因请求中无其它身份信息)。如令牌无效,则返回 403 Forbidden 和错误码 `M_FORBIDDEN`。 + +若主服务器声明支持 `m.login.sso` 流,且客户端支持,客户端应重定向用户至 [通过 SSO 客户端登录](#client-login-via-sso) 的 `/redirect` 端点。认证完成后,需要匹配 `m.login.token` 类型发送 `/login` 请求。 + +{{% added-in v="1.7" %}} 已认证客户端如主服务器支持可通过 [`POST /login/get_token`](/client-server-api/#post_matrixclientv1loginget_token) 为自己账户生成一次性登录令牌。 + +{{% http-api spec="client-server" api="login" %}} + +{{% http-api spec="client-server" api="login_token" %}} + +{{% http-api spec="client-server" api="refresh" %}} + +{{% http-api spec="client-server" api="logout" %}} + +#### 应用服务登录 + +{{% added-in v="1.2" %}} + +应用服务可通过提供有效的应用服务令牌及其命名空间下的用户进行登录。 + +{{% boxes/note %}} +应用服务不一定需要以单独用户身份登录,可通过 [身份断言](/application-service-api#identity-assertion) 用应用服务令牌操作。但如需针对用户的令牌,可用下面 API。 +{{% /boxes/note %}} + +该请求需通过[应用服务 as_token](/application-service-api#registration)认证(详见[客户端认证](#客户端认证)令牌用法)。 + +使用方式如下: + +```json +{ + "type": "m.login.application_service", + "identifier": { + "type": "m.id.user", + "user": "" + } +} +``` + +如访问令牌无效、不属于应用服务,或该用户未注册,则主服务器返回错误码 `M_FORBIDDEN`。 + +如 token 属于应用服务但用户 ID 不在其命名空间,返回错误码 `M_EXCLUSIVE`。 + +#### 登录 Fallback + +客户端若无法识别登录流程,可用以下 fallback 登录 API: + + GET /_matrix/static/client/login/ + +该端点返回含 JS 的 HTML 页面,可完整执行登录流程。登录成功后页面会调用 `window.matrixLogin.onLogin(response)`,参数为 [`POST /_matrix/client/v3/login`](#post_matrixclientv3login) 的 JSON 响应体解析所得的 JS 对象。 + +{{% added-in v="1.1" %}} 可将非认证参数作为查询字符串提供至本端点,会在登录流程转发至实际登录 API。例如: + + GET /_matrix/static/client/login/?device_id=GHTYAJCE + +### 账户注册与管理 + +{{% http-api spec="client-server" api="registration" %}} + +#### 密码管理注意事项 + +{{% boxes/warning %}} +客户端**应**强制密码的足够复杂性,建议至少包含小写字母、大写字母、数字和符号,最少 8 位。服务器可拒绝弱密码,并返回 `M_WEAK_PASSWORD` 错误码。 +{{% /boxes/warning %}} + +#### 账户锁定 + +{{% added-in v="1.12" %}} + +服务器管理员可对帐号加锁(如出于安全原因),锁定行为非破坏性,可后续解锁。下述定义了客户端与服务器的行为,具体加锁/解锁方式为实现细节。 + +账户锁定时,服务器必须对除下列 API 外的所有客户端-服务器 API 返回 401 错误、错误码 `M_USER_LOCKED` 并设置 [`soft_logout`](#soft-logout): + +- [`POST /logout`](#post_matrixclientv3logout) +- [`POST /logout/all`](#post_matrixclientv3logoutall) + +服务器可在 `error` 字段告知锁定原因。 + +``` +HTTP/1.1 401 Unauthorized +Content-Type: application/json +``` + +```json +{ + "errcode": "M_USER_LOCKED", + "error": "本账户已被锁定", + "soft_logout": true +} +``` + +服务器**不应**在账户锁定时立即吊销访问令牌,除非客户端主动调用上述登出端点。这样可以确保账户解锁后用户无需重新登录。 + +收到 `M_USER_LOCKED` 错误时,客户端应保留会话加密等信息,并提示用户帐户已被锁定。锁定期间应隐藏正常 UI 禁止使用账户,但**应**以限流方式持续轮询 [`/sync`](#get_matrixclientv3sync) 等接口以检测解锁。 + +如需申诉可使用[服务器联系方式发现](#getwell-knownmatrixsupport)。 + +#### 账户停用 + +{{% added-in v="1.13" %}} + +服务器管理员可停用用户账户以防止进一步操作。其效果类似[锁定](#账户锁定),但不会导致客户端丢失会话状态。停用可逆,不同于注销账号。 + +可用操作范围为服务器实现细节,但建议至少允许: + +* 登录、新建会话(即使也处于停用态) +* 查看和接收消息,特别是通过 [`/sync`](#get_matrixclientv3sync) 与 [`/messages`](#get_matrixclientv3roomsroomidmessages) +* [验证其它设备](#device-verification)与写交叉签名数据 +* [上传密钥备份](#server-side-key-backups) +* [离开房间与拒绝邀请](#post_matrixclientv3roomsroomidleave) +* [撤回](#redactions)自己发送的消息 +* [注销](#post_matrixclientv3logout)或[删除](#delete_matrixclientv3devicesdeviceid)自己任意设备 +* [停用账户](#post_matrixclientv3accountdeactivate),可设置延时防止频繁新注册 +* 添加或更改[管理员联系信息](#adding-account-administrative-contact-information),但不允许移除(建议服务器记录变更日志) + +一般请求如 [`/send/{eventType}`](#put_matrixclientv3roomsroomidsendeventtypetxnid) 可根据请求参数决定是否允许,如允许发送撤回事件但不允许普通消息。 + +如房间用作管理员与被停用用户沟通通道,建议允许用户在该房间中发言。不想让其接收通知的管理员可考虑[锁定账户](#账户锁定)。 + +其它被禁止的建议操作: + +* 加入或敲门进入房间 +* 接受或发送邀请 +* 向房间发送消息 +* 修改资料 +* 撤回他人消息(如房间权限允许) + +如客户端试图在停用时操作,服务器必须以 403 Forbidden、错误码 `M_USER_SUSPENDED` 响应: + +``` +HTTP/1.1 403 Forbidden +Content-Type: application/json +``` + +```json +{ + "errcode": "M_USER_SUSPENDED", + "error": "您在账号停用期间无法执行此操作。" +} +``` + +有关停用/取消停用 API 暂未纳入本规范,属实现细节。 + +### 添加账户管理员联系信息 + +主服务器可独立保存一些用于管理的联系信息。此信息独立于身份服务器,可以绑定至身份服务器。 + +{{% boxes/note %}} +本节涉及“添加”“绑定”概念。添加(或移除)指未绑定至身份服务器的标识符;绑定(或解绑)指服务端绑定于身份服务器。取决于上下文,标识符可同时添加和绑定。 +{{% /boxes/note %}} + +{{% http-api spec="client-server" api="administrative_contact" %}} + +### 当前账户信息 + +{{% http-api spec="client-server" api="whoami" %}} + +#### 关于身份服务器的说明 + +Matrix 身份服务器存储用户第三方标识符(如邮箱、手机)与用户 ID 的绑定。用户确定身份服务器后,所有客户端都应使用该身份服务器。 + +客户端可通过账户数据事件 `m.identity_server` 得知用户所选身份服务器(见本章下文)。客户端**应**在检测到该数据(已/未出现)前**不要**请求身份服务器,如有 `base_url` 字段则使用该身份服务器,否则用默认值,且**不应**在为用户设置身份服务器前将默认值写入账户数据。 + +客户端应监听 `m.identity_server` 事件变更,并同步其使用的身份服务器。 + +如客户端允许用户设置身份服务器,必须更新 `m.identity_server`。`base_url` 为 `null` 时应视为不希望启用身份服务器,相关功能禁用。 + +客户端**不应**为缺少该事件的用户迁移补默认身份服务器,除非用户主动设置。即,用户未设置相关数据时,客户端不应主动写入默认身份服务器。 + +{{% event event="m.identity_server" %}} + +## 能力协商 + +主服务器可能不支持部分功能,客户端需有查询主服务器能力的机制。例如主服务器采用外部认证,无法支持密码变更。 + +通过此机制声明的能力旨在描述 API 内可选功能,或与用户/服务器状态相关功能。不用于实验性功能,实验性或不稳定功能应由 [`/versions`](#get_matrixclientversions) 公布。 + +合理能力如: + +- 是否支持用户在线状态 +- 是否支持可选功能如用户目录或房间目录 +- 服务器对客户端速率限制、文件类型限制 + +不应声明为能力的有: + +- 是否支持规范中处于 `unstable` 状态的功能 +- 媒体文件大小(已由 [`/config`](#get_matrixmediav3config) API 管理) +- 可选编码/传输方式 + +能力以 `m.` 为前缀为 Matrix 规范保留,其它命名建议采用 Java 包命名风格。具体支持能力见下。 + +{{% http-api spec="client-server" api="capabilities" %}} + +### `m.change_password` 能力 + +本能力含 `enabled` 字段,表示用户能否调用 [`/account/password`](#post_matrixclientv3accountpassword) API 修改密码。不出现时默认允许修改密码。出现且 `enabled` 为假时,客户端应提示用户无法修改密码。 + +示例: + +```json +{ + "capabilities": { + "m.change_password": { + "enabled": false + } + } +} +``` + +### `m.room_versions` 能力 + +描述服务器支持的默认及可用房间版本与稳定性级别。客户端可用以判定房间是否需升级。 + +示例: + +```json +{ + "capabilities": { + "m.room_versions": { + "default": "1", + "available": { + "1": "stable", + "2": "stable", + "3": "unstable", + "custom-version": "unstable" + } + } + } +} +``` + +本能力参考[房间版本](/rooms)。未被 `available` 标为 `stable` 的统统视为 `unstable`。例如 `future-stable` 也算 `unstable`。 + +`default` 为服务器新建房间采用的版本。客户端应引导有权限用户将`unstable`房间升级为 `default` 版本。 + +如无本能力,客户端应以 `"1"` 作为默认和唯一可用稳定房间版本。 + +### `m.set_displayname` 能力 + +本能力含 `enabled` 字段,标识用户能否通过资料接口修改昵称。若禁用,常为目录服务(如 LDAP)映射帐号。 + +此能力常与 `m.set_avatar_url` 成对出现。 + +如不出现,默认允许修改昵称。 + +示例: + +```json +{ + "capabilities": { + "m.set_displayname": { + "enabled": false + } + } +} +``` + +### `m.set_avatar_url` 能力 + +本能力唯一 `enabled` 字段,标识用户可否通过资料接口修改头像。典型禁用场景为外部服务(如 LDAP)账号同步。 + +与 `m.set_displayname` 能力常成对。 + +缺省时默认可修改头像。 + +示例: + +```json +{ + "capabilities": { + "m.set_avatar_url": { + "enabled": false + } + } +} +``` + +### `m.3pid_changes` 能力 + +本能力唯一字段 `enabled`,标识用户是否能添加、删除或修改自己的三方账号。注意仅作用于[管理员联系信息](#adding-account-administrative-contact-information)接口,不影响身份服务端点。禁用通常为目录服务类(如 LDAP)账号的自动同步。 + +缺省时默认允许修改。 + +示例: + +```json +{ + "capabilities": { + "m.3pid_changes": { + "enabled": false + } + } +} +``` + +### `m.get_login_token` 能力 + +本能力唯一字段 `enabled`,标识用户是否可通过 [`POST /login/get_token`](/client-server-api/#post_matrixclientv1loginget_token) 生成一次性登陆令牌,用于免认证客户端登陆。 + +缺省时,客户端应认为用户不能生成此类令牌。 + +示例: + +```json +{ + "capabilities": { + "m.get_login_token": { + "enabled": false + } + } +} +``` + +## 过滤 + +过滤器可在服务器端创建,作为参数传递到支持事件返回的 API 里,这会影响 API 返回的数据内容。只有部分 API 支持过滤器。 + +### 房间成员延迟加载 + +成员事件数量巨大时占用资源较大。为节省资源,客户端可启用“延迟加载”,服务器仅发送与客户端相关的成员事件。 + +延迟加载作为优化不是绝对精确的,服务器可以为简化实现而多发部分事件,但应尽量减少冗余。 + +在过滤器层面,通过设定 +[`RoomEventFilter`](#post_matrixclientv3useruseridfilter_request_roomeventfilter) 的 `lazy_load_members` 开启延迟加载。启用后,支持该特性的端点仅返回事件发送方的成员事件。例如带延迟加载的 `/sync` 仅返回时间线内发生事件相关的发送者成员事件。 + +处理事件序列(如循环调用 [`/sync`](#get_matrixclientv3sync) 或分页 [`/messages`](#get_matrixclientv3roomsroomidmessages))时,事件块发送用户可能重叠。服务器可以假设客户端会保留已接收成员事件,对没变化的用户成员事件不必重发(称为“冗余成员事件”)。客户端如需总是收到全部冗余成员事件,可设 `include_redundant_members` 为 true。 + +推荐用法如下: + +- 客户端初次同步 `/sync` 启用延迟加载,仅获取当前事件的发送人成员事件。 +- 如需展示房间成员列表,可调用 `/members`,参数 `?at` 设为 `/sync` 的 from token。房间成员列表随后跟随增量 `/sync` 维护。 +- 不支持成员补全可通过查询房间状态或 [`/profile`](#get_matrixclientv3profileuserid) 按需获取。 + +支持延迟加载的端点有: + +- [`/sync`](/client-server-api/#get_matrixclientv3sync) +- [`/rooms//messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages) +- [`/rooms/{roomId}/context/{eventId}`](/client-server-api/#get_matrixclientv3roomsroomidcontexteventid) + +### API 端点 + +{{% http-api spec="client-server" api="filter" %}} + +## 事件 + +客户端-服务器 API 披露的会话历史为事件列表。服务器将最终一致的事件图(event graph)线性化为事件流(event stream): + + [E0]->[E1]->[E2]->[E3]->[E4]->[E5] + +### 房间事件类型 + +房间事件分为两类: + +* **状态事件**:更新房间元数据(如话题、成员等),状态由事件 `type` 与 `state_key` 组成唯一键,重复键的状态会被覆盖。 +* **消息事件**:描述房间内临时性操作,如发送消息、设置 VoIP 通话等。 + +规范定义了若干 `m.` 前缀事件(详见 [Room Events](#room-events))。应用可自定义事件类型,建议采用 Java 包命名规范如 `com.example.myapp.event`。 + +{{% boxes/note %}} +事件类型不限于本规范定义,可随意采用 Java 包命名进行自定义,只要客户端可访问所用命名空间。例如 `com.example.game.score`。 +{{% /boxes/note %}} + +### 房间事件格式 + +“联邦”层事件格式依房间使用的[房间版本](/rooms)而定,详见 [版本1](/rooms/v1#event-format) 与 [版本3](/rooms/v3#event-format)。 + +但一般客户端不会直接遇到此格式,主服务器会将事件转换为如下便于客户端解析的格式。 + +{{% boxes/warning %}} +事件体属于不可信数据。所有 Matrix 应用须确保事件体结构/架构符合预期后再用其内容。 + +**任何时候都不能假定事件体字段齐全且类型正确。** + +原因详见 [MSC2801](https://github.com/matrix-org/matrix-spec-proposals/pull/2801)。 +{{% /boxes/warning %}} + +{{% definition path="api/client-server/definitions/client_event" %}} + +### 精简(Stripped)状态 + +精简状态为房间的简化状态视图,助用户了解房间基本信息,仅含部分精简后的状态事件。 + +精简状态事件仅有 `sender`、`type`、`state_key`、`content`。 + +使用场景:邀请、敲门及用户*可能*有加入权利的房间(如 [`restricted` 房间](#restricted-rooms))。 + +客户端仅于无房间实际状态时应使用精简状态,有数据后弃用。如客户端带房间存档而收到房间精简状态(如被踢后看到新邀请),应以精简状态为准,直到重新进房获取最新状态。 + +精简状态一般包含下列事件,尽量以精简状态形式呈现: + +* [`m.room.create`](#mroomcreate) +* [`m.room.name`](#mroomname) +* [`m.room.avatar`](#mroomavatar) +* [`m.room.topic`](#mroomtopic) +* [`m.room.join_rules`](#mroomjoin_rules) +* [`m.room.canonical_alias`](#mroomcanonical_alias) +* [`m.room.encryption`](#mroomencryption) + +{{% boxes/note %}} +客户端应遍历精简状态,不要假设某事件必然存在。服务器亦可包含文档未列出的事件。 +{{% /boxes/note %}} + +{{% boxes/rationale %}} +房间名、头像、话题、别名便于用户做出加入与否。 +加入规则提醒客户端为何具备加入权限,比如不同图标辅助解释。 +创建事件可判定房间类型(如是否为空间等),客户端可据此在 UI 不同区域展示。 +加密信息则用于图标或相关解释。 +{{% /boxes/rationale %}} + +{{% boxes/warning %}} +尽管精简状态由服务器生成与下发,但接收方亦可能不准确。精简状态事件未签名,有被篡改或因延迟变更未达等可能。 +{{% /boxes/warning %}} + +{{% event-fields event_type="stripped_state" %}} + +### 大小限制 + +事件经[联邦层格式](#房间事件格式)、[规范化 JSON](/appendices#canonical-json) 编码后,整体不得超过 65536 字节。 + +字段单独限制如下: + +- `sender` 不得超过[用户 ID](/appendices/#user-identifiers) 最大长度。 +- `room_id` 不得超过[房间ID](/appendices/#room-ids)最大长度。 +- `state_key` 最多255字节。 +- `type` 最多255字节。 +- `event_id` 不得超过[事件ID](/appendices/#event-ids)最大长度。 + +部分事件类型还有其他约束,详见各事件说明。其余键仅受全局 64KiB 限制。 + +### 房间事件 + +{{% boxes/note %}} +本节内容尚在完善中。 +{{% /boxes/note %}} + +规范现有标准事件均以 `m.` 开头。 + +{{% event event="m.room.canonical_alias" %}} + +{{% event event="m.room.create" %}} + +{{% event event="m.room.join_rules" %}} + +{{% event event="m.room.member" %}} + +{{% event event="m.room.power_levels" %}} + +#### 历史性事件 + +部分 `m.` 命名空间下的事件或见于房间,但本规范暂无业务含义,如: + +- `m.room.aliases` + +早期版本有详细定义。 + +### 同步 + +读取事件的推荐流程为:客户端首次调用 [`/sync`](/client-server-api/#get_matrixclientv3sync)(无 `since` 参数),获取每间房最新消息及房间在返回时间线开头时的状态。响应含 `next_batch` 字段,后续以此为 `since` 参数获取新消息。每房间附带 `prev_batch` 字段,可用作 [`/rooms//messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages) 的 start 参数查询更早记录。 + +举例,`/sync` 返回房间事件 E2~E5,略去 E0/E1: + +``` + [E0]->[E1]->[E2]->[E3]->[E4]->[E5] + ^ ^ + | | + prev_batch: '1-2-3' next_batch: 'a-b-c' +``` + +客户端后续带 `next_batch` 做 `timeout` 长轮询。服务器会保持连接,及时有新事件随时返回,仅 `/sync`(及已弃用的 `/events`)支持该机制。 + +假如下一次同步返回增量事件 E6: + +``` + [E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6] + ^ ^ + | | + | next_batch: 'x-y-z' + prev_batch: 'a-b-c' +``` + +通常全部新事件都会返回。若某段时间事件过多,则大部分事件会省略,仅返回最新事件,同时返回起止区间状态差量(delta),方便客户端补全,防断层。客户端如想回补,可按返回 `prev_batch` 查询丢失区间事件。 + +例,跟进一次 `/sync` 带 `since=x-y-z`,服务器发现新事件 E7~E10,但只返回 E8~E10 及前置状态差量: + +``` + | gap | + | <-> | + [E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9]->[E10] + ^ ^ ^ + | | | + since: 'x-y-z' | | + prev_batch: 'd-e-f' next_batch: 'u-v-w' +``` + +客户端据此以 `from=x-y-z`、`to=d-e-f` 查询 [`/rooms//messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages) 补历史。 + +{{% boxes/warning %}} +此 API 按事件到达主服务器时间排序,部分旧 API 按事件图偏序排序,二者可能出现同事件多次返回。客户端需基于事件 ID 去重。 +{{% /boxes/warning %}} + +{{% boxes/note %}} +`/sync` 返回 `state` 列表与 `timeline` 分离。全量同步 `state` 为时间线开始时刻完整状态(如新房间状态只占满时间线 `state` 或为零)。增量同步 `state` 为自 `since` 以来至时间线起点的变更(如时间线 `limited` 时)。注意 `state` 不一定为时间线前一刻状态,客户端不应对时间线混排该列表。 +{{% /boxes/note %}} + +{{% boxes/rationale %}} +本规范早期让 `state` 表示时间线**末端**状态,不理想:一是事件重复,二是客户端难以还原。例如返回时间线 \[M0, S1, M2\],M0/M2 同一用户发,S1 为其改昵称事件;若 `state` 表示末端,客户端需手动倒回 S1 状态计算 M0。 +{{% /boxes/rationale %}} + +{{% http-api spec="client-server" api="sync" %}} + +{{% http-api spec="client-server" api="old_sync" %}} + +### 获取房间事件 + +房间事件读取相关 API 如下: + +{{% http-api spec="client-server" api="rooms" %}} + +{{% http-api spec="client-server" api="message_pagination" %}} + +{{% http-api spec="client-server" api="room_event_by_timestamp" %}} + +{{% http-api spec="client-server" api="room_initial_sync" %}} + +### 向房间发送事件 + +{{% boxes/note %}} +{{% added-in v="1.3" %}} + +如事件 [关联](#形成事件关系) 其它事件,服务器可能做后处理。关联类型(`rel_type`)决定了可用性(如用户对同一目标事件只能发送一次)。 +{{% /boxes/note %}} + +{{% http-api spec="client-server" api="room_state" %}} + +**示例** + +合法写法: + +``` +PUT /rooms/!roomid:domain/state/m.example.event +{ "key" : "without a state key" } +``` +``` +PUT /rooms/!roomid:domain/state/m.another.example.event/foo +{ "key" : "with 'foo' as the state key" } +``` + +非法请求: + +``` +POST /rooms/!roomid:domain/state/m.example.event/ +{ "key" : "cannot use POST here" } +``` +``` +PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11 +{ "key" : "txnIds are not supported" } +``` + +注意区分 `state key` 与 `txnId`: + +``` +PUT /rooms/!roomid:domain/state/m.another.example.event/11 +{ "key" : "with '11' as the state key, but was probably intended to be a txnId" } +``` + +可按用户 ID 作为 `state_key` 存储用户相关状态: + +``` +PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Aexample.org +{ "animal" : "cat", "reason": "fluffy" } +``` + +也可无 `state_key`: + +``` +PUT /rooms/!roomid:domain/state/m.room.bgd.color +{ "color": "red", "hex": "#ff0000" } +``` + +{{% http-api spec="client-server" api="room_send" %}} + +### 撤回(Reductions) + +因事件可扩展,恶意用户/服务器或添违法内容。部分事件无法直接删除(如成员事件),因此采用撤回手段,将事件只保留协议必需字段。撤回后的事件在客户端/服务器侧皆只返回精简内容。客户端访问已被撤回事件可在 unsigned 红包 `redacted_because` 带原撤回事件。 + +具体算法见[房间版本说明](/rooms)。事件撤回后不可恢复。远程主服务器撤回有效性判据同理。 + +客户端接收到 `m.room.redaction` 事件时,须同步调整被撤回事件内容。 + +{{% boxes/note %}} +撤回事件仍能影响房间状态。撤回后,状态事件表现为属性未指定(除撤回算法保护外)。如撤回的 join 事件,用户仍为已加入;如撤回话题,则话题移除而非回滚至先前。 +{{% /boxes/note %}} + +#### 事件 + +{{% event event="m.room.redaction" %}} + +#### 客户端行为 + +{{% http-api spec="client-server" api="redaction" %}} + +### 形成事件关系 + +{{% changed-in v="1.3" %}} + +部分场景需将一个事件逻辑关联至另一个,如回复消息、编辑、提供上下文等。 + +关联为父子结构,任意事件可为父。父不显式列子关系,由子通过 `content` 内 `m.relates_to`(见下)描述。可相互嵌套形成树。 + +{{% boxes/note %}} +子事件可指向其他子事件,形成链甚至树型结构。 +{{% /boxes/note %}} + +为便于服务器聚合查找,`m.relates_to` 必须出现在加密事件的明文部分,不能仅内嵌在密文负载中。 + +{{% boxes/warning %}} +加密事件内 `payload` 的 `m.relates_to` 应被忽略,只以明文副本为准(包括无副本时)。以确保客户端与服务器关于关系的处理一致。 +{{% /boxes/warning %}} + +不规范、非法、跨房间等关联均忽略。客户端应平等显示无效也无关联事件,可加以错误提示。 + +`m.relates_to` 格式定义如下: + +{{% definition path="api/client-server/definitions/m.relates_to" %}} + +#### 关联类型 + +本规范描述如下关联类型: + +* [富回复](#rich-replies)(注:未用 `rel_type`) +* [事件替换](#event-replacements) +* [事件标注(注释、reaction)](#event-annotations-and-reactions) +* [线程](#threading) +* [引用](#reference-relations) + +#### 子事件聚合 + +{{% added-in v="1.3" %}} + +部分关系可由服务器按 `rel_type` 聚合,让客户端无需单独获取所有子事件。例如可统计有多少用户用某 reaction key。 + +聚合详情因关联类型而异。 + +下述端点提供聚合: + +* [`GET /rooms/{roomId}/messages`](#get_matrixclientv3roomsroomidmessages) +* [`GET /rooms/{roomId}/context/{eventId}`](#get_matrixclientv3roomsroomidcontexteventid) +* [`GET /rooms/{roomId}/event/{eventId}`](#get_matrixclientv3roomsroomideventeventid) +* [`GET /rooms/{roomId}/relations/{eventId}`](#get_matrixclientv1roomsroomidrelationseventid) +* [`GET /rooms/{roomId}/relations/{eventId}/{relType}`](#get_matrixclientv1roomsroomidrelationseventidreltype) +* [`GET /rooms/{roomId}/relations/{eventId}/{relType}/{eventType}`](#get_matrixclientv1roomsroomidrelationseventidreltypeeventtype) +* [`GET /sync`](#get_matrixclientv3sync) 限流区间 +* [`POST /search`](#post_matrixclientv3search) 匹配 room_events +* {{% added-in v="1.4" %}} [`GET /rooms/{roomId}/threads`](#get_matrixclientv1roomsroomidthreads) + +{{% boxes/warning %}} +当前状态事件不支持聚合。欢迎补充相关 MSC 以提升支持。 +{{% /boxes/warning %}} + +客户端应本地追加聚合。例如收到新 reaction,更新计数。若事件本地未能找到或发生变化,需自行整合。 + +被撤回的父事件,其子事件(如 reaction)依然存在,但被撤回的子事件与父失去关联,需要解除聚合关系。客户端本地聚合同理。 + +建议客户端对聚合实现本地回显,如优化用户体验。但需注意不可二次聚合。建议为尚未获取事件 ID 的发出事件也能维护聚合信息,可用事务 ID 临时识别。 + +{{% boxes/warning %}} +若历史可见性受限,部分事件不可见,聚合也缺失。关键信息(如投票)应充分考虑可见性。 + +服务器如有历史断层,聚合也会不准确。 +{{% /boxes/warning %}} + +#### 关系 API + +{{% added-in v="1.3" %}} + +客户端可通过下述端点取父事件的子事件,如需递归聚合则需自行处理。 + +通过 `event_type` 或 `rel_type` 过滤条件,服务器仅返回匹配的直接/间接关联事件,所有非匹配类型的间接关联将被排除,如想获取完整线程建议客户端本地遍历而不是用 rel_type。 + +{{% boxes/note %}} +由于回复未使用 `rel_type`,无法通过本 API 访问。 +{{% /boxes/note %}} + +{{% http-api spec="client-server" api="relations" %}} + +## 房间 + +### 类型 + +{{% added-in v="1.2" %}} + +房间可选带类型,区分功能。无类型的房间一般为会话用途。 + +类型有助于客户端区分功能(会话/数据型),房间类型记录于 [`m.room.create`](#mroomcreate) 的 `type` 字段,建房时以 `creation_content` 提供。 + +当前规范房间类型有: + +* [`m.space`](#spaces) + +类型可扩展,依 [命名空间标识符](/appendices/#common-namespaced-identifier-grammar)。 + +### 创建 + +主服务器建房时会生成 `m.room.create` 事件,作为事件树根;并自动设置权限等其它事件,如: + +- `m.room.power_levels` :设置用户及动作权限等 +- `m.room.join_rules` :设置加入规则 + +详细参见 [Room Events](#room-events)。创建房间接口如下。 + +{{% http-api spec="client-server" api="create_room" %}} + +### 房间别名 + +服务器可托管人类友好的房间别名(如 `#name:server.name`)。 + +别名以主服务器域名作用域为限,服务器一般拒绝跨域维护,因此协议不提供给外部服务器发送更新的机制。但服务器**必须**处理其它服务器的别名解析请求。 + +房间不存储自身的全部别名,权限用户可通过 `m.room.canonical_alias` 公布别名。别名实践中常发生漂移,请客户端校验别名链接的实际房间 ID,再做分享或使用。 + +{{% http-api spec="client-server" api="directory" %}} + +### 权限 + +{{% boxes/note %}} +本节尚在完善中。 +{{% /boxes/note %}} + +房间权限通过 Power Level 实现。任一操作需满足所需 power level。`m.room.power_levels` 以状态事件记录房间内用户、各操作所需权限,默认用户 0,房主 100。用户可提升他人 power level,但不得超过自身。权限设定跨房间,有些操作如踢人、封禁、发送状态事件都需对应值。详情见 [m.room.power_levels](#room-events)。 + +建议 power level 对应含义如下: +- 0 普通用户 +- 50 协管 +- 100 管理员 + +### 成员关系 + +必须为成员才能发送、接收事件。房间成员状态: + +- 无关:不可发送接收 +- 敲门:请求加入,等待批准 +- 邀请:已被邀请,尚未参与 +- 已加入:可正常操作 +- 被封禁:不可加入 + +例外情形: + +- 拒绝邀请:发送 `m.room.member` 带 `leave` 内容,前提已被邀请 +- 敲门加入:`m.room.member` 带 `knock` 内容,表示意图加入 +- 撤销敲门:发送 `leave` 相当于拒绝邀请 + +部分房间需先邀请才可加入,由 `m.room.join_rules` 控制: + +`public` +自由加入 + +`invite` +需邀请 + +`knock` +要先敲门,若允许可由房间成员打招呼,请求准许 + +{{% added-in v="1.2" %}} `restricted` +满足指定房间成员条件或受邀请 + +{{% added-in v="1.3" %}} `knock_restricted` +结合 `restricted` 与 `knock`,即既可凭邀请/房间条件直接加入,也可敲门 + +状态转换流程: + +{{% diagram name="membership" alt="成员状态机示意图" %}} + +{{% http-api spec="client-server" api="list_joined_rooms" %}} + +#### 加入房间 + +{{% http-api spec="client-server" api="inviting" %}} + +{{% http-api spec="client-server" api="joining" %}} + +##### 敲门进入房间 + +{{% added-in v="1.1" %}} +{{% changed-in v="1.3" %}} + +{{% boxes/note %}} +自 `v1.3` 支持敲门进入 [restricted](#restricted-rooms) 房间。 +{{% /boxes/note %}} + +如加入规则允许,外部用户可 `/knock` 敲门,成员可邀请([`/invite`](#post_matrixclientv3roomsroomidinvite))或拒绝([`/kick`](#post_matrixclientv3roomsroomidkick)、[`/ban`](#post_matrixclientv3roomsroomidban)、设置 `leave`)。用户已在房间、已邀请、被封禁不可敲门。 + +同意敲门需有邀请权限,拒绝需有踢/封禁权限。 + +主服务器收到邀请即视为敲门被接受,无需关联至原敲门事件。服务器可自动接受邀请。 + +{{% http-api spec="client-server" api="knocking" %}} + +##### 限制型房间 + +{{% added-in v="1.2" %}} +{{% changed-in v="1.3" %}} + +{{% boxes/note %}} +`v1.3` 起,`knock_restricted` 房可敲门,同理需房间支持。 +{{% /boxes/note %}} + +限制型房间 (`restricted`) 在加入规则中指定 "allow conditions"。若已被邀请,规则不影响其;否则服务器判断用户是否满足任一 condition。 + +目前唯一可用 condition 是 `m.room_membership`:满足情况即已加入指定 room_id 的成员。例如: + +```json +{ + "join_rule": "restricted", + "allow": [ + { + "room_id": "!other:example.org", + "type": "m.room_membership" + } + ] +} +``` + +#### 离开房间 + +成员可离开房间(含拒绝邀请、撤回敲门),操作完成后对应房间将不会再出现在 [`/sync`](#get_matrixclientv3sync) 返回中(除非用带 `include_leave` 的过滤器)。 + +如是 invite-only 房间,用户需被重新邀请才能再入。 + +用户也可“忘记房间”(forget),忘记后只有重新加入/被邀请才可恢复。 + +可被踢出(kick),需要操作者有足够权限。被踢视同主动离开,且只有非 invite-only 房才能再次加入。 + +{{% http-api spec="client-server" api="leaving" %}} + +{{% http-api spec="client-server" api="kicking" %}} + +##### 房间封禁 + +可封禁成员,操作是将 member 调为 `ban`,禁止加入、收发事件,踢出本房。必须有足够 power level,接口如下: + +```json +{ + "user_id": "<待封禁成员ID>", + "reason": "string: 封禁原因" +} +``` + +或直接设置 membership: + +```json +{ + "membership": "ban" +} +``` + +解封需显式发送 [`/rooms//unban`](/client-server-api/#post_matrixclientv3roomsroomidunban)。 + +{{% http-api spec="client-server" api="banning" %}} + +### 列出房间 + +{{% http-api spec="client-server" api="list_public_rooms" %}} + +## 用户数据 + +### 用户目录 + +{{% http-api spec="client-server" api="users" %}} + +### 用户资料 + +{{% http-api spec="client-server" api="profile" %}} + +#### 服务器行为 + +主服务器**必须**接受以下情况下的用户资料查询: + +- 与请求方共享房间的用户 +- 公开房间的成员(主服务器已知) + +其它情况主服务器**可**直接拒绝(403 + `M_FORBIDDEN`)。 + +远程用户资料查询成功时主服务器**应**向远端请求。远端可拒绝联邦查询。 + +不存在的用户,主服务器可选返回 403 或 404,建议 403。 + +##### 资料变更通知 + +因 display name 和 avatar 处处用到,信息修改时会自动广播变更: + +- 发送 join 状态 `m.room.member` 事件至其所在所有房间更新 displayname / avatar_url +- 发送 `m.presence` 含新 displayname / avatar_url / presence + +主服务器应自动完成上述通知。 + +此外,主服务器自有用户房间成员事件应含 displayname、avatar_url 以便客户端直接展示。 + +## 模块 + +模块是客户端-服务器 API 的组成部分,但并非适用于所有端点。模块定义严格区分于实验扩展或可选特性。合规服务器**必须**支持全部模块及相关规范(如仅面向特定客户端类型,可仅支持所需模块)。合规模块的客户端**必须**支持其目标特性的所有模块及规范,[详见特性配置文件](#feature-profiles)。 + +### 特性配置文件 + +Matrix 支持多种客户端形态:嵌入式 IoT 至桌面客户端。并非所有设备都能实现全部功能(如无屏幕)。客户端可归入如下类型,每类包含一组**必须**实现的功能。必须整体实现整类配置文件所含特性。 + +#### 简要表 + +| 模块 / 配置文件 | 网页端 | 移动端 | 桌面端 | 命令行 | 嵌入式 | +|-------------------------------------------------------|---------|---------|--------|--------|--------| +| [内容仓库](#content-repository) | 必须 | 必须 | 必须 | 可选 | 可选 | +| [直接消息](#direct-messaging) | 必须 | 必须 | 必须 | 必须 | 可选 | +| [忽略用户](#ignoring-users) | 必须 | 必须 | 必须 | 可选 | 可选 | +| [即时消息](#instant-messaging) | 必须 | 必须 | 必须 | 必须 | 可选 | +| [在线状态](#presence) | 必须 | 必须 | 必须 | 必须 | 可选 | +| [推送通知](#push-notifications) | 可选 | 必须 | 可选 | 可选 | 可选 | +| [消息回执](#receipts) | 必须 | 必须 | 必须 | 必须 | 可选 | +| [房间历史可见性](#room-history-visibility) | 必须 | 必须 | 必须 | 必须 | 可选 | +| [房间升级](#room-upgrades) | 必须 | 必须 | 必须 | 必须 | 可选 | +| [第三方邀请](#third-party-invites) | 可选 | 必须 | 可选 | 可选 | 可选 | +| [输入状态通知](#typing-notifications) | 必须 | 必须 | 必须 | 必须 | 可选 | +| [用户与房间提醒](#user-and-room-mentions) | 必须 | 必须 | 必须 | 可选 | 可选 | +| [VoIP](#voice-over-ip) | 必须 | 必须 | 必须 | 可选 | 可选 | +| [客户端配置](#client-config) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [设备管理](#device-management) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [端到端加密](#end-to-end-encryption) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [事件注释与回应](#event-annotations-and-reactions) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [事件上下文](#event-context) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [事件替换](#event-replacements) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [已读未读标记](#read-and-unread-markers) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [访客接入](#guest-access) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [内容管理策略列表](#moderation-policy-lists) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [OpenID](#openid) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [引用关系](#reference-relations) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [内容举报](#reporting-content) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [富回复](#rich-replies) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [房间预览](#room-previews) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [标签功能](#room-tagging) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [SSO 客户端登录/认证](#sso-client-loginauthentication)| 可选 | 可选 | 可选 | 可选 | 可选 | +| [Secrets](#secrets) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [点对点消息](#send-to-device-messaging) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [服务器访问控制列表](#server-access-control-lists-acls-for-rooms) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [服务器管理](#server-administration) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [服务器通知](#server-notices) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [服务器端搜索](#server-side-search) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [空间](#spaces) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [贴纸消息](#sticker-messages) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [第三方网络](#third-party-networks) | 可选 | 可选 | 可选 | 可选 | 可选 | +| [线程](#threading) | 可选 | 可选 | 可选 | 可选 | 可选 | + +*各模块具体需实现内容详见相应章节。* + +#### 客户端种类 + +##### 独立网页端(Web) + +即以 Matrix 为主的 Web App,SPA、MPA 等。 + +##### 移动端(Mobile) + +专门为移动设备开发的 Matrix 客户端,通常为 App。 + +##### 桌面端(Desktop) + +原生桌面 GUI 客户端。 + +##### 命令行(CLI) + +文本终端使用的客户端。 + +##### 嵌入式(Embedded) + +嵌入至其他网站(如 iframe)或嵌入设备,如家用电器、汽车等,仅做少量操作,无需完整通信功能。 + +###### Application + +指嵌入网页,供特定网站专用的 Matrix 客户端,通常为单一用途。 + +###### Device + +指嵌入设备(如水壶、冰箱、汽车)的小型客户端,仅执行部分操作,环境受限。 + +{{% cs-module name="instant_messaging" %}} +{{% cs-module name="rich_replies" %}} +{{% cs-module name="voip_events" %}} +{{% cs-module name="typing_notifications" %}} +{{% cs-module name="receipts" %}} +{{% cs-module name="read_markers" %}} +{{% cs-module name="presence" %}} +{{% cs-module name="content_repo" %}} +{{% cs-module name="send_to_device" %}} +{{% cs-module name="device_management" %}} +{{% cs-module name="end_to_end_encryption" %}} +{{% cs-module name="secrets" %}} +{{% cs-module name="history_visibility" %}} +{{% cs-module name="push" %}} +{{% cs-module name="third_party_invites" %}} +{{% cs-module name="search" %}} +{{% cs-module name="guest_access" %}} +{{% cs-module name="room_previews" %}} +{{% cs-module name="tags" %}} +{{% cs-module name="account_data" %}} +{{% cs-module name="admin" %}} +{{% cs-module name="event_context" %}} +{{% cs-module name="sso_login" %}} +{{% cs-module name="dm" %}} +{{% cs-module name="ignore_users" %}} +{{% cs-module name="stickers" %}} +{{% cs-module name="report_content" %}} +{{% cs-module name="third_party_networks" %}} +{{% cs-module name="openid" %}} +{{% cs-module name="server_acls" %}} +{{% cs-module name="mentions" %}} +{{% cs-module name="room_upgrades" %}} +{{% cs-module name="server_notices" %}} +{{% cs-module name="moderation_policies" %}} +{{% cs-module name="spaces" %}} +{{% cs-module name="event_replacements" %}} +{{% cs-module name="event_annotations" %}} +{{% cs-module name="threading" %}} +{{% cs-module name="reference_relations" %}} diff --git a/locales/zh-Hans/client-server-api/modules/account_data.md b/locales/zh-Hans/client-server-api/modules/account_data.md new file mode 100644 index 00000000..d06acc5a --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/account_data.md @@ -0,0 +1,27 @@ +### 客户端配置 + +客户端可以在他们的主服务器上为其账户存储自定义配置数据。这些账户数据将在不同设备间同步,并且能够在特定设备上的多次安装之间保持持久性。用户只能查看其自己账户的账户数据。 + +账户数据可以是全局的,也可以限定在特定房间内。这里没有继承机制:如果某个 `type` 类型的数据在房间的账户数据中缺失,不会自动回退到同类型的全局账户数据。 + +#### 事件 + +客户端通过 [`/sync`](#get_matrixclientv3sync) 响应中的 `account_data` 部分接收账户数据事件。 + +这些事件也可以在 [`/events`](#get_matrixclientv3events) 响应中接收,或者作为房间 `/sync` 响应中的 `account_data` 部分收到。出现在 `/events` 中的 `m.tag` 事件会带有所对应房间的 `room_id`。 + +#### 客户端行为 + +{{% http-api spec="client-server" api="account-data" %}} + +#### 服务器行为 + +服务器必须拒绝设置服务器自身管理的事件类型的账户数据,并返回 405 错误响应。 +目前,仅包括 [`m.fully_read`](#mfully_read) +和 [`m.push_rules`](#push-rules-events) 事件类型。这一规定同样适用于全局和按房间划分的账户数据。 + +{{% boxes/note %}} +{{% changed-in v="1.10" %}} `m.push_rules` 被添加到了拒绝列表中。 +{{% /boxes/note %}} + +服务器必须允许客户端正常读取上述事件类型的数据。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/admin.md b/locales/zh-Hans/client-server-api/modules/admin.md new file mode 100644 index 00000000..6a24d653 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/admin.md @@ -0,0 +1,7 @@ +### 服务器管理 + +该模块为服务器管理员增加了检查服务器状态和数据的能力。 + +#### 客户端行为 + +{{% http-api spec="client-server" api="admin" %}} \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/content_repo.md b/locales/zh-Hans/client-server-api/modules/content_repo.md new file mode 100644 index 00000000..19e5b06e --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/content_repo.md @@ -0,0 +1,125 @@ +### 内容库 + +内容库(或称“媒体库”)允许用户将文件上传到其本地通信服务器(homeserver)以供日后使用。例如,用户想要发送到房间的文件会上传至此,用户想要使用的头像也同样如此。 + +上传文件时,客户端会向用户本地通信服务器的特定资源发送 POST 请求,该资源会返回一个 `mxc://` URI,供日后通过 GET 请求进行下载。内容的下载则是从接收方的本地通信服务器完成,如果内容不是本地的,必须先通过同样的 API 从源通信服务器转存内容(除非源通信服务器和目的通信服务器为同一台服务器)。 + +在提供内容服务时,服务器应当提供 `Content-Security-Policy` 头。推荐的安全策略为: +`sandbox; default-src 'none'; script-src 'none'; plugin-types application/pdf; style-src 'unsafe-inline'; object-src 'self';`。 + +{{% added-in v="1.4" %}} 当服务器向客户端提供内容时,还应当额外提供 `Cross-Origin-Resource-Policy: cross-origin` 头,以便(Web)客户端能够访问如 `SharedArrayBuffer` 等受限 API,在与媒体库进行交互时使用。 + +{{% changed-in v="1.11" %}} 未认证的下载端点已被弃用,建议使用新的、需要认证的端点。此更改包括将所有媒体端点的路径从 `/_matrix/media/*` 更新为 `/_matrix/client/{version}/media/*`,但 `/upload` 和 `/create` 端点除外。这两个上传/创建端点预计将在之后的版本中进行类似的迁移。 + +#### Matrix 内容(`mxc://`)URI + +内容的位置以 Matrix 内容(`mxc://`)URI 形式表示。格式如下: + +``` +mxc:/// + + :内容最初上传所在的通信服务器名称,例如 matrix.org + :用以标识内容的不透明 ID。 +``` + +#### 客户端行为 {id="content-repo-client-behaviour"} + +客户端可通过以下端点访问内容库。 + +{{% changed-in v="1.11" %}} `/ _matrix/media` 层级下的多个端点已弃用并被新的、需要认证的端点取代。已弃用端点在下文中有注明。 + +{{% boxes/warning %}} +在 Matrix 1.12 版本,服务器应当“冻结”已弃用的非认证端点,以防止新上传的媒体被下载。这意味着冻结前上传的媒体仍可通过已弃用端点访问,而冻结后(或期间)上传的媒体应当只能通过新的认证端点访问。对于远程媒体,“新上传”由缓存填充时间决定。这意味着媒体本身可能早于冻结,但因服务器需重新下载,所以被视为“新媒体”。 + +客户端应当在服务器冻结非认证访问之前,更新以支持已认证的端点。 + +服务器在冻结前应充分考虑其本地生态影响。例如,确保用户常用客户端支持新端点,或者更新桥接程序以使用媒体代理等。 + +此外,[用于 `m.login.sso` 流程的 IdP 图标](/client-server-api/#definition-mloginsso-flow-schema) 应从冻结中排除。详情请参阅 `m.login.sso` 流程的架构说明。 + +服务器*示例*时间表如下: + +* Matrix 1.11 发行:客户端开始支持认证媒体访问。 +* Matrix 1.12 发行:服务器冻结非认证媒体访问。 + * 此前上传的媒体仍可通过弃用端点访问。 + * 新上传(或缓存)的媒体*仅*能通过认证端点访问。 + +预计 Matrix 1.12 将于 2024 年 7~9 月正式发布。 +{{% /boxes/warning %}} + +{{% http-api spec="client-server" api="authed-content-repo" %}} + +{{% http-api spec="client-server" api="content-repo" %}} + +##### 缩略图 + +通信服务器应能够为上传的图片和视频生成缩略图。当前尚未规定支持生成缩略图的确切文件类型,详见 [Issue #1938](https://github.com/matrix-org/matrix-doc/issues/1938)。 + +缩略图方法分为“裁剪(crop)”和“缩放(scale)”。“scale”方法会返回宽度或高度小于请求尺寸的图片。客户端若需适配特定矩形尺寸,则需进一步缩放和留白补齐。“crop”方法则尽量返回与请求尺寸相近、并且保持请求尺寸宽高比的图片。客户端如需适配,也应进一步缩放图片以适配目标矩形。 + +传给缩略图 API 的尺寸为客户端期望的最小尺寸。服务器不得返回比客户端请求尺寸更小的缩略图,除非原始内容本身尺寸就小于请求尺寸。若原始内容尺寸较小,服务器应直接返回原始内容,而非额外生成缩略图。 + +服务器应生成以下尺寸、方法的缩略图: + +- 32x32,裁剪 +- 96x96,裁剪 +- 320x240,缩放 +- 640x480,缩放 +- 800x600,缩放 + +简要总结: +- “缩放”会保持原始图片的宽高比 +- “裁剪”会输出与请求尺寸宽高比一致的图片 +- 服务器会尽量返回尺寸大于等于请求值的图片 + +服务器在任何情况下都不得对缩略图进行放大。除非原始内容尺寸不足,否则服务器也不得返回小于请求尺寸的缩略图。 + +#### 安全性考量 + +HTTP GET 端点无需认证。只要知道内容的 URL,无论实体是否在房间内都可获取内容。 + +`mxc://` URI 易遭目录遍历攻击,如 `mxc://127.0.0.1/../../../some_service/etc/passwd`。这可能导致目标通信服务器试图访问并返回该文件。因此,通信服务器必须对 `mxc://` URI 做合法性检查,仅允许在 `server-name` 和 `media-id` 中出现字母(A-Za-z)、数字(0-9)、下划线 `_` 和短横线 `-`。该白名单字符集兼容 RFC 4648 规范的 URL 安全 base64 编码。采用白名单优于黑名单(如黑名单排除 . 和 /),因为黑名单可能被漏洞(如百分号编码、UTF-8 编码遍历等)绕过。 + +通信服务器的内容服务还有额外的内容安全注意事项: + +- 客户端可能上传超大型文件。通信服务器应拒绝保存过大的文件,并返回 HTTP 413 且错误码为 `M_TOO_LARGE`。 +- 客户端可能上传超大图片。通信服务器应拒绝为超大图片生成缩略图,返回 HTTP 413 并附带 `M_TOO_LARGE`。 +- 远程通信服务器可能托管超大文件或图片。通信服务器应拒绝中转或生成超大远程文件/图片的缩略图,返回 HTTP 502 并附带 `M_TOO_LARGE`。 +- 客户端可能尝试上传过多文件。通信服务器应限制单个客户端上传的文件数量与总大小,超过限制时返回 HTTP 403 并附带 `M_FORBIDDEN`。 +- 客户端可能通过通信服务器访问大量远程文件。通信服务器应限制缓存的远程媒体的数量与总大小。 +- 客户端或远程通信服务器可能上传包含针对通信服务器缩略图机制或客户端解码器漏洞的恶意文件。 + +##### 内联内容服务 + +若客户端配置不安全,在以 `Content-Disposition: inline` 方式分发媒体时,可能会受到跨站脚本攻击。为降低大部分风险,客户端应避免与通信服务器的媒体端点部署在同一域名下。服务器应当在内联内容服务时,将 `Content-Type` 限定为以下值之一: + +* `text/css` +* `text/plain` +* `text/csv` +* `application/json` +* `application/ld+json` +* `image/jpeg` +* `image/gif` +* `image/png` +* `image/apng` +* `image/webp` +* `image/avif` +* `video/mp4` +* `video/webm` +* `video/ogg` +* `video/quicktime` +* `audio/mp4` +* `audio/webm` +* `audio/aac` +* `audio/mpeg` +* `audio/ogg` +* `audio/wave` +* `audio/wav` +* `audio/x-wav` +* `audio/x-pn-wav` +* `audio/flac` +* `audio/x-flac` + +在指定 `Content-Type` 时,上述类型不太可能引发跨站脚本风险,因为客户端只会按此类型渲染数据。例如上传 HTML 文件但指定类型为 `image/png` 时,客户端只会认为图片损坏,并不会作为 HTML 页面渲染。因此,只要 `Content-Disposition` 根据该类型正确计算,服务器即可信任用户定义的内容类型。 + +客户端不应依赖于服务器必定在 [`/download`](#get_matrixclientv1mediadownloadservernamemediaid) 接口返回 `inline` 而非 `attachment`。服务器实现可能出于安全考量将所有下载均返回 `attachment`,无论内容类型为何——客户端不应对此举感到意外。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/device_management.md b/locales/zh-Hans/client-server-api/modules/device_management.md new file mode 100644 index 00000000..c66824f0 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/device_management.md @@ -0,0 +1,15 @@ +### 设备管理 + +本模块为用户提供了管理其[设备](/#devices)的方式。 + +#### 客户端行为 + +实现此模块的客户端应为用户提供已注册设备的列表,并允许用户更新设备的显示名称。客户端还应允许用户删除不再使用的设备。 + +{{% http-api spec="client-server" api="device_management" %}} + +#### 安全性注意事项 + +删除设备具有安全风险:该操作会使分配给该设备的 access_token 失效,因此攻击者可能利用这一点注销真实用户(并且每当真实用户尝试重新登录时,攻击者都可以重复进行此操作,从而阻止用户登录)。服务器在删除设备时应要求超出 access_token 的额外身份验证措施(例如,要求用户重新输入密码)。 + +设备的显示名称为公开可见内容。客户端应考虑提醒用户这一点。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/dm.md b/locales/zh-Hans/client-server-api/modules/dm.md new file mode 100644 index 00000000..fab9f5fd --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/dm.md @@ -0,0 +1,21 @@ +### 私信 + +Matrix 中的所有通信都发生在房间内。有时,用户希望能够直接与某一个特定的人交流。本模块定义了一种方法,可以将某些房间标记为与指定对象的“私聊”。这并不意味着聊天只能局限于两个人之间,因为这会排除自动“机器人”用户,或者“个人助手”等替用户在其不在时回复私信的功能。 + +一个房间未必会被房间内所有成员视为“私聊”,但存在一种信号机制,用于向被邀请人传递聊天是否为“私聊”的信息。 + +#### 事件 + +{{% event event="m.direct" %}} + +#### 客户端行为 + +要与其他用户发起私聊,邀请方的客户端应在 [`/createRoom`](/client-server-api/#post_matrixclientv3createroom) 时设置 `is_direct` 标志。当用户操作的流程意图是与某人直接交流,而不是邀请该人加入一个公共房间时,客户端都应设置该标志。例如,用户在某个人的头像旁点击“开始聊天”时,意味着应设置 `is_direct` 标志。 + +被邀请方的客户端可以利用 [m.room.member](#mroommember) 事件中的 `is_direct` 标志自动将该房间标记为私聊,但这不是强制要求:客户端也可以弹窗提示用户,或完全忽略该标志。 + +邀请人和被邀请人的客户端都应通过在账户数据中存储一个 `m.direct` 事件,将该房间记为私聊,接口为 [`/user//account_data/`](/client-server-api/#put_matrixclientv3useruseridaccount_datatype)。 + +#### 服务端行为 + +当 [`/createRoom`](/client-server-api/#post_matrixclientv3createroom) 接口中提供了 `is_direct` 标志时,所属服务器必须在 [`/createRoom`](/client-server-api/#post_matrixclientv3createroom) 调用所邀请成员的邀请事件中设置 `is_direct` 标志。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/end_to_end_encryption.md b/locales/zh-Hans/client-server-api/modules/end_to_end_encryption.md new file mode 100644 index 00000000..0d05995e --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/end_to_end_encryption.md @@ -0,0 +1,1044 @@ +### 端到端加密 + +Matrix 可选支持端到端加密,允许创建房间,其对话内容无法被任何参与的主服务器解密或截获。 + +#### 密钥分发 + +Matrix 中的加密与身份验证基于公钥密码学。Matrix 协议提供了一个基础的公钥交换机制,但需要通过带外渠道在用户之间交换指纹,以建立信任网络。 + +##### 概述 + +1)Bob 发布其设备的公钥和支持的算法。这可能包括长期身份密钥和/或一次性密钥。 + +``` + +----------+ +--------------+ + | Bob 的主服务器 | | Bob 的设备 | + +----------+ +--------------+ + | | + |<=============| + /keys/upload +``` + +2)Alice 请求 Bob 的公用身份密钥和支持的算法。 + +``` + +----------------+ +------------+ +----------+ + | Alice 的设备 | | Alice 的主服务器 | | Bob 的主服务器 | + +----------------+ +------------+ +----------+ + | | | + |=================>|==============>| + /keys/query +``` + +3)Alice 选择一种算法并领取所需的一次性密钥。 + +``` + +----------------+ +------------+ +----------+ + | Alice 的设备 | | Alice 的主服务器 | | Bob 的主服务器 | + +----------------+ +------------+ +----------+ + | | | + |=================>|==============>| + /keys/claim +``` + +##### 密钥算法 + +不同的密钥算法用于不同的用途。每种密钥算法通过名称标识,并有特定的表示方式。 + +名称 `ed25519` 对应于 [Ed25519](http://ed25519.cr.yp.to/) 签名算法。密钥为一个 32 字节的 Ed25519 公钥,使用 [unpadded Base64](/appendices/#unpadded-base64) 编码。例如: + + "SogYyrkTldLz0BXP+GYWs0qaYacUI0RleEqNT8J3riQ" + +名称 `curve25519` 对应于 [Curve25519](https://cr.yp.to/ecdh.html) ECDH 算法。密钥为一个 32 字节的 Curve25519 公钥,使用 [unpadded Base64](/appendices/#unpadded-base64) 编码。例如: + + "JGLn/yafz74HB2AbPLYJWIVGnKAtqECOBf11yyXac2Y" + +名称 `signed_curve25519` 也对应于 Curve25519 ECDH 算法,但该密钥经过签名,可以进行身份认证。使用此算法的密钥以包含以下属性的对象表示: + +`KeyObject` + +| 参数 | 类型 | 描述 | +|------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------| +| key | string | **必选。** 未填充的 Base64 编码的 32 字节 Curve25519 公钥。 | +| signatures | Signatures | **必选。** 密钥对象的签名。签名过程详见 [Signing JSON](/appendices/#signing-json)。 | +| fallback | boolean | 标记此密钥是否为 [备用密钥](#one-time-and-fallback-keys)。默认为 `false`。 | + +示例: + +```json +{ + "key":"06UzBknVHFMwgi7AVloY7ylC+xhOhEX4PkNge14Grl8", + "signatures": { + "@user:example.com": { + "ed25519:EGURVBUNJP": "YbJva03ihSj5mPk+CHMJKUKlCXCPFXjXOK6VqBnN9nA2evksQcTGn6hwQfrgRHIDDXO2le49x7jnWJHMJrJoBQ" + } + } +} +``` + +`ed25519` 和 `curve25519` 密钥用于 [设备密钥](#device-keys)。此外,`ed25519` 密钥也用于 [跨签名密钥](#cross-signing)。 + +`signed_curve25519` 密钥用于 [一次性及备用密钥](#one-time-and-fallback-keys)。 + +##### 设备密钥 + +每台设备应拥有一个 Ed25519 签名密钥。此密钥应通过设备上的加密安全源生成,且其私钥部分绝不可导出。其他客户端通过该密钥作为设备指纹,并由该密钥签署设备的其他密钥。 + +设备通常还需要生成若干附加密钥,具体取决于使用的消息算法。 + +在 Olm 1.0 版本中,每台设备还需有一个 Curve25519 身份密钥。 + +##### 一次性与备用密钥 + +除了设备密钥(属于长期密钥),某些加密算法还要求设备拥有多个一次性密钥,这些密钥仅使用一次,用后即弃。在 Olm 1.0 版本中,设备使用由设备 Ed25519 密钥签名的 `signed_curve25519` 一次性密钥。 + +设备会生成一次性密钥上传至服务器。其他用户之后会通过 [claim](#post_matrixclientv3keysclaim) 领取。服务器必须确保每个一次性密钥只被领取一次:主服务器在将该一次性密钥分配给其他用户后即应删除。 + +{{% added-in v="1.2" %}} 备用密钥与一次性密钥类似,但使用后不会被消耗。如果上传了备用密钥,当设备用尽一次性密钥、用户请求密钥时,服务器会返回备用密钥。备用密钥一旦被使用,应尽快用新密钥替换。 + +{{% boxes/warning %}} +备用密钥用于在设备离线或无法上传新密钥时防止一次性密钥耗尽。但使用备用密钥建立的会话可能易受重放攻击。 +{{% /boxes/warning %}} + +设备将通过 [`/sync`](#e2e-extensions-to-sync) 得知尚可被领取的一次性密钥数量,以及备用密钥是否已被使用。这样设备即可保障在线期间有充足一次性密钥,并在备用密钥被用后及时更换。 + +##### 密钥上传 + +设备通过 [`/keys/upload`](/client-server-api/#post_matrixclientv3keysupload) API 将身份密钥的公钥部分以签名 JSON 对象形式上传至主服务器。JSON 对象必须包含设备 Ed25519 密钥的公钥部分,且必须由该密钥签名,详见 [Signing JSON](/appendices/#signing-json)。 + +一次性密钥和备用密钥也通过 [`/keys/upload`](/client-server-api/#post_matrixclientv3keysupload) API 上传。如需上传新的一次性或备用密钥则再上传。备用密钥(格式为签名 JSON 对象的密钥算法)应包含名为 `fallback` 且值为 `true` 的属性。 + +设备必须保存他们上传的每个密钥的私钥部分。当收到使用该密钥加密的信息后,可以删除一次性密钥的私钥部分。但有可能主服务器发出的某个一次性密钥从未被用过,因此生成密钥的设备永远也不会知道可以删除该密钥。因此,设备最终可能需要保管过多私钥。若存储私钥过多,设备可以从最早的密钥开始丢弃。 + +{{% boxes/warning %}} +客户端不应无限期保存备用密钥的私钥,以免攻击者能解密此前用该备用密钥加密的消息。 + +客户端最多应该只保存 2 个备用密钥的私钥:当前未用的备用密钥及其前一个。一旦客户端确信所有用旧备用密钥加密的消息都已收到(如自第一条消息后经过一小时),应删除该备用密钥。 +{{% /boxes/warning %}} + +##### 跟踪用户的设备列表 + +在 Alice 向 Bob 发送加密消息之前,需要获得 Bob 每台设备及相关身份密钥的列表,以建立这些设备的加密会话。此列表可通过 [`/keys/query`](/client-server-api/#post_matrixclientv3keysquery) 并在 `device_keys` 参数中传入 Bob 用户 ID 获得。 + +Bob 可能会不时添加新设备,Alice 需要及时获知并在今后的加密消息中加上新的设备。最简单做法是每发一次消息都执行一次 [`/keys/query`](/client-server-api/#post_matrixclientv3keysquery),但用户数和设备数可能庞大,如此会极度低效。 + +因此,通常每个客户端会维护一些用户(实践中通常是与之共享加密房间的用户)的设备列表。该列表必须在客户端应用程序多次启动间持久化存储(以保留设备验证数据并在 Bob 突然添加新设备时警告 Alice)。 + +Alice 的客户端可按以下流程维护 Bob 的设备列表: + +1. 首先设置标记,记录现在正在跟踪 Bob 的设备列表,并有单独标记表示本地 Bob 设备列表已过期。两者都必须保存在客户端重启后依然存在的存储中。 +2. 向 [`/keys/query`](/client-server-api/#post_matrixclientv3keysquery) 发送请求,`device_keys` 参数传入 Bob 用户 ID。请求完成后,将获取到的设备列表持久化保存,并清除“已过期”标记。 +3. 正常处理 [`/sync`](/client-server-api/#get_matrixclientv3sync) 响应时,解析 [`device_lists`](#e2e-extensions-to-sync) 字段的 `changed` 属性。如果在跟踪于列出的用户之一的设备列表,则将该用户的设备列表标记为过期,并重发 [`/keys/query`](/client-server-api/#post_matrixclientv3keysquery) 请求。 +4. 定期将 [`/sync`](/client-server-api/#get_matrixclientv3sync) 结果中的 `next_batch` 字段保存持久化。如果 Alice 后续重启客户端,可通过 [`/keys/changes`](/client-server-api/#get_matrixclientv3keyschanges) 并将记录的 `next_batch` 字段作为 `from` 参数查询在离线期间哪些用户的设备列表已变更。如果在跟踪这些用户的设备列表,则将其标记为过期。将此列表与之前已标记过期的列表并集,然后对这些用户重新执行 [`/keys/query`](/client-server-api/#post_matrixclientv3keysquery)。 + +{{% boxes/warning %}} +Bob 可能在 Alice 的 `/keys/query` 请求仍在进行时更新设备。Alice 的客户端可能会在第一次请求未结束时,在 `/sync` 响应的 `device_lists` 字段中看到 Bob 的用户 ID,并发起第二次 `/keys/query` 请求。这可能导致两类相关问题。 + +第一个问题:当第一次请求响应时,客户端会清除记录的 Bob 设备已过期标记。如果第二次请求失败或在完成前客户端关闭,可能导致 Alice 继续使用已过期的 Bob 设备列表。 + +第二个问题:在某些条件下,第二次请求可能早于第一次请求完成。此时第一次请求的结果会覆盖第二次的结果。 + +客户端必须防范上述情况。例如,可以确保每个用户至多只有一个 `/keys/query` 请求在运行,对于新的请求排队等待第一个完成。或立即发起新请求,但确保忽略第一次请求的结果(例如通过取消第一次请求)。 +{{% /boxes/warning %}} + +{{% boxes/note %}} +当 Bob 和 Alice 共享房间并跟踪 Alice 设备时,Alice 离开房间后新增设备,Bob 不会知晓。当他们再次共享房间时,Bob 就有一个过时的 Alice 设备列表。为了解决该问题,Bob 的主服务器会把 Alice 的用户 ID 加入 `device_lists` 字段的 `changed` 属性中,因此 Bob 会按常规流程更新 Alice 的设备列表。另外,Bob 也可通过检查 `device_lists` 字段的 `left` 属性获知双方已不再共享任何房间,并相应地将 Alice 从跟踪列表移除。 +{{% /boxes/note %}} + +##### 发送加密附件 + +当房间启用加密时,文件应在上传到主服务器前进行加密。 + +操作方式为,客户端生成一个只用一次的 256 位 AES 密钥并使用 AES-CTR 模式加密该文件。计数器(Counter)应为 64 位,从 0 开始,且以随机 64 位初始化向量(IV)为前缀,两者一起组成 128 位唯一计数器块。 + +{{% boxes/warning %}} +IV 绝不可与同一密钥重复使用。这意味着如需加密同一消息中的多个文件(如图片和缩略图),绝不可共用密钥及 IV。 +{{% /boxes/warning %}} + +加密后,文件即可上传到主服务器。必须在房间事件中包含密钥和 IV 以及上传得到的 `mxc://`,以便接收方可以解密。由于承载这些密钥和 IV 的事件会用 Megolm 加密,服务器无法解密文件。 + +还必须包含密文的哈希值,以防主服务器篡改文件内容。 + +客户端应以加密后的 `m.room.message` 事件形式发送数据,`msgtype` 可用 `m.file`,或其他对应文件类型的 msgtype。密钥采用 [JSON Web Key](https://tools.ietf.org/html/rfc7517#appendix-A.3) 格式,带 [W3C 扩展](https://w3c.github.io/webcrypto/#iana-section-jwk)。 + +###### 对 `m.room.message` 的扩展 + +本模块为引用文件的 `m.room.message` 消息类型添加了 `file` 和 `thumbnail_file` 属性,类型为 `EncryptedFile`,用于替代 `url` 和 `thumbnail_url` 属性,如 [m.file](#mfile) 和 [m.image](#mimage) 等。 + +`EncryptedFile` + +| 参数 | 类型 | 描述 | +|-----------|----------------|----------------------------------------------------------------------------------| +| url | string | **必选。** 文件的 URL。 | +| key | JWK | **必选。** 一个 [JSON Web Key](https://tools.ietf.org/html/rfc7517#appendix-A.3) 对象。 | +| iv | string | **必选。** AES-CTR 使用的 128 位唯一计数块,未填充 base64 编码。 | +| hashes | {string: string} | **必选。** 算法名称与密文哈希的映射,未填充 base64 编码。客户端应至少支持 `sha256` 哈希。 | +| v | string | **必选。** 加密附件协议版本,必须为 `v2`。 | + +`JWK` + +| 参数 | 类型 | 描述 | +|--------|----------|----------------------------------------------------------------------------------------| +| kty | string | **必选。** 密钥类型,必须为 `oct`。 | +| key_ops| [string] | **必选。** 密钥操作。至少包含 `encrypt` 和 `decrypt`。 | +| alg | string | **必选。** 算法,必须为 `A256CTR`。 | +| k | string | **必选。** 密钥,以 urlsafe 未填充 base64 编码。 | +| ext | boolean | **必选。** 可提取性。必须为 `true`。此为 [W3C 扩展](https://w3c.github.io/webcrypto/#iana-section-jwk)。 | + +示例: + +```json +{ + "content": { + "body": "something-important.jpg", + "file": { + "url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe", + "v": "v2", + "key": { + "alg": "A256CTR", + "ext": true, + "k": "aWF6-32KGYaC3A_FEUCk1Bt0JA37zP0wrStgmdCaW-0", + "key_ops": ["encrypt","decrypt"], + "kty": "oct" + }, + "iv": "w+sE15fzSc0AAAAAAAAAAA", + "hashes": { + "sha256": "fdSLu/YkRx3Wyh3KQabP3rd6+SFiKg5lsJZQHtkSAYA" + } + }, + "info": { + "mimetype": "image/jpeg", + "h": 1536, + "size": 422018, + "thumbnail_file": { + "hashes": { + "sha256": "/NogKqW5bz/m8xHgFiH5haFGjCNVmUIPLzfvOhHdrxY" + }, + "iv": "U+k7PfwLr6UAAAAAAAAAAA", + "key": { + "alg": "A256CTR", + "ext": true, + "k": "RMyd6zhlbifsACM1DXkCbioZ2u0SywGljTH8JmGcylg", + "key_ops": ["encrypt", "decrypt"], + "kty": "oct" + }, + "url": "mxc://example.org/pmVJxyxGlmxHposwVSlOaEOv", + "v": "v2" + }, + "thumbnail_info": { + "h": 768, + "mimetype": "image/jpeg", + "size": 211009, + "w": 432 + }, + "w": 864 + }, + "msgtype": "m.image" + }, + "event_id": "$143273582443PhrSn:example.org", + "origin_server_ts": 1432735824653, + "room_id": "!jEsUZKDJdhlrceRyVU:example.org", + "sender": "@example:example.org", + "type": "m.room.message", + "unsigned": { + "age": 1234 + } +} +``` + +#### 设备验证 + +在 Alice 向 Bob 发送加密数据、或信任从 Bob 收到的数据之前,或许想先验证自己真正与 Bob 本人通信,而非与中间人。此验证过程需要带外渠道:仅依赖 Matrix 自身无法做到完全安全验证(否则就只能信任主服务器管理员了)。 + +在 Matrix 中,验证流程通常是 Alice 与 Bob 线下见面或通过其他可靠方式交流,采用下文中定义的任一种互动验证方式校验 Bob 的设备。Alice 和 Bob 也可以当面逐字读出各自的未填充 base64 编码 Ed25519 公钥(如 `/keys/query` 返回值)。 + +设备验证可能有多种结论。例如: + +- Alice 可以“接受”设备,表明她确信设备属于 Bob,今后可以为该设备加密敏感内容,并确认接收到的消息确实由该设备发出。 +- Alice 可以“拒绝”设备,如果她知道或怀疑该设备非 Bob 控制(如也不信任 Bob),则不会发送敏感内容、不再信任该设备发来的消息。 +- Alice 可以跳过设备验证流程。这种情况下虽然无法确信设备属于 Bob,但也没有证据怀疑,且加密协议依然能够防止被动窃听。 + +{{% boxes/note %}} +一旦签名密钥通过验证,就由加密协议去验证具体消息是否真由持有该 Ed25519 私钥的设备发出,或仅允许该设备解密。Olm 协议的具体文档见 。 +{{% /boxes/note %}} + +##### 密钥验证框架 + +人工比对 Ed25519 密钥并不友好,易出错。为降低错误概率、提升用户体验,本规范支持一些验证方式,并允许通过用户设备间互发消息辅助验证。这些方法共用一套验证协商框架。 + +验证消息可以发在由双方共享的房间(应为 [定向消息](#direct-messaging)),也可通过 [to-device](#send-to-device-messaging) 消息点对点直发两个设备。两种场景下报文结构类似,细微差别详见下文。验证不同用户应用房间消息,同一用户多个设备验证则用 to-device 消息。 + +一个密钥验证会话以首条消息中的 ID 标识。房间消息用初始 message 的 event ID,to-device 消息用首条消息的 `transaction_id` 字段,其余同会话消息继承。 + +一般来说,验证流程如下: + +- Alice 通过发送密钥验证请求事件,向 Bob 发起验证请求。如果在房间,事件类型为 [`m.room.message` 且 `msgtype: m.key.verification.request`](#mroommessagemkeyverificationrequest),如用 to-device 则类型为 [`m.key.verification.request`](#mkeyverificationrequest)。事件指明 Alice 客户端支持的验证方式。(注意“Alice”与“Bob”在自验证场景其实可以是同一用户)。 +- Bob 客户端弹窗提示 Bob 接受密钥验证。Bob 接受后,其客户端发送 [`m.key.verification.ready`](#mkeyverificationready) 事件,载明其支持的验证方式。 +- Alice 或 Bob 选择双方都支持的一个验证方式后,主设备发送 [`m.key.verification.start`](#mkeyverificationstart) 事件,标明所选验证方式。如果双方仅有唯一通用方式,则可自动选择。 +- Alice 和 Bob 按所选验证方式完成验证,可能涉及客户端间消息交互,双方在带外渠道核对信息,或与各自设备交互。 +- Alice 和 Bob 客户端各自发送 [`m.key.verification.done`](#mkeyverificationdone) 通知验证成功。 + +任一设备可随时通过发送 [`m.key.verification.cancel`](#mkeyverificationcancel) 事件取消验证,请求体里的 code 字段指明原因。 + +to-device 场景下,Alice 若无法确定要验证 Bob 的哪台设备或不想指定特定设备,可以向 Bob 所有设备发 `m.key.verification.request`,事务 ID 相同。当 Bob 某台设备接受或拒绝(发 `m.key.verification.ready` 或 `m.key.verification.cancel`)时,Alice 要向 Bob 其他设备发送 `m.key.verification.cancel`(若 Bob 接受则 code 为 `m.accepted`,拒绝则为 `m.user`)。假定 Alice、Bob 各有两台设备,Bob 第一台设备接受 Alice 第二台设备的请求,协议流程如下(注意,Alice 第一个设备未参与验证,消息次序 Bob、Alice 谁先发 `m.key.verification.start` 都可以;最终双方互发 done 通知): + +``` + +---------------+ +---------------+ +-------------+ +-------------+ + | AliceDevice1 | | AliceDevice2 | | BobDevice1 | | BobDevice2 | + +---------------+ +---------------+ +-------------+ +-------------+ + | | | | + | | m.key.verification.request | | + | |---------------------------------->| | + | | | | + | | m.key.verification.request | | + | |-------------------------------------------------->| + | | | | + | | m.key.verification.ready | | + | |<----------------------------------| | + | | | | + | | m.key.verification.cancel | | + | |-------------------------------------------------->| + | | | | + | | m.key.verification.start | | + | |<----------------------------------| | + | | | | + . + . (verification messages) + . + | | | | + | | m.key.verification.done | | + | |<----------------------------------| | + | | | | + | | m.key.verification.done | | + | |---------------------------------->| | + | | | | +``` + +房间消息下,Alice 只需向房间发送一次请求事件(类型为 `m.room.message` 且 `msgtype: m.key.verification.request`),而非向 Bob 各设备分别发送 `m.key.verification.request`。一旦 Bob 某设备发出 `m.key.verification.ready`,其他 Bob 设备即可知有设备已接受,自动忽略该请求,无须 Alice 主动通知。 + +房间加密模式下,验证流程不得因加密受阻。例如:若验证消息本身用加密,务必确保收件人所有未经验证的设备都能获得解密该消息的密钥(即使通常不会给他们解密密钥)。或者,也可将验证消息设为明文(但并不推荐)。 + +Bob 某设备收到 Alice 的 `m.key.verification.request` 且所有方法都不支持时,不应直接取消请求,以免其他设备支持。应提示 Bob 无支持方式,允许其手动拒绝。 + +提示 Bob 接受/拒绝 Alice 请求(或“不支持”提示)应在 `timestamp`(to-device)或 `origin_ts`(房间消息)后 10 分钟,或收到消息后 2 分钟(以先到者为准)自动消失,期间若收到 `m.key.verification.cancel` 则自动隐藏。 + +Bob 若拒绝请求,客户端需发送 code 为 `m.user` 的 `m.key.verification.cancel`,Alice 应知晓被拒绝,并若是 to-device 消息类型,还要通知 Bob 的所有设备该请求已被拒绝。 + +Alice/Bob 若同时发出 `m.key.verification.start` 且指定同一验证方式,用户 ID 字典序较大的设备消息被忽略,视为只有较小字典序一端发起。若用户 ID 相同(即自验证),则比对设备 ID。若指定验证方式不一致,则以 `code: m.unexpected_message` 取消。 + +to-device 验证也可无请求直接发 `m.key.verification.start`,该行为已废弃,建议新客户端不要这样做,但应能兼容老客户端。 + +具体验证方式可能会添加额外步骤、事件及消息字段。定义于本规范下的方法事件类型须以 `m.key.verification` 命名空间为前缀,其他自定义事件按 Java 包命名原则命名。 + +{{% event event="m.room.message$m.key.verification.request" title="`m.room.message` with `msgtype: m.key.verification.request`" %}} + +{{% event event="m.key.verification.request" %}} + +{{% event event="m.key.verification.ready" %}} + +{{% event event="m.key.verification.start" %}} + +{{% event event="m.key.verification.done" %}} + +{{% event event="m.key.verification.cancel" %}} + +##### 短认证字符串(SAS)验证 + +SAS 验证是一种基于上述通用框架的用户友好密钥验证流程。其高度交互化,使用户容易参与其中。 + +验证过程受 Phil Zimmermann 的 ZRTP 密钥协商启发。其关键在于哈希承诺(commitment):发起 Diffie-Hellman 的一方先发送自己部分的哈希,只有收到对方部分才发明文。这样,攻击者只会有一次机会破解 DH,实际上即便只校验 n 位也能保证高安全性:若认证 n 位,攻击者成功概率为 1/2ⁿ。如验证 40 位,攻击概率小于十万亿分之一,若失败,两端的短认证字符串会不一致,从而提醒用户遭遇攻击。 + +要支持该方式,客户端应在 `m.key.verification.request` 和 `m.key.verification.ready` 的 `methods` 字段中声明名称 `m.sas.v1`。 + +SAS 验证主要两步: + +1. 密钥协商(类似 [ZRTP 协商](https://tools.ietf.org/html/rfc6189#section-4.4.1))。 +2. 密钥认证(基于 HMAC)。 + +Alice 和 Bob 互验证流程如下: + +1. Alice 和 Bob 建立安全的带外连接,如线下、视频通话等。(“安全”即无可被冒充,而非完全机密。) +2. 双方启动密钥验证流程。 +3. Alice 设备向 Bob 设备发 `m.key.verification.start`,确保 Bob 的设备密钥已本地存储。 +4. Bob 设备收到后,选定双方均支持的密钥协商、哈希、MAC、SAS 算法。 +5. Bob 设备确保 Alice 设备密钥也齊。 +6. Bob 设备生成临时 Curve25519 密钥对 (*K_B^private*, *K_B^public*),计算公钥哈希。 +7. Bob 回复 `m.key.verification.accept`,传递承诺。 +8. Alice 保存承诺哈希备用。 +9. Alice 设备生成临时 Curve25519 密钥对 (*K_A^private*, *K_A^public*), 以 `m.key.verification.key` 只发送公钥。 +10. Bob 回复 `m.key.verification.key`,含其公钥。 +11. Alice 校验 Bob 设备发来的密钥哈希与早先的承诺及 Alice 启动消息内容一致。 +12. 双方用自己的私有临时密钥与对方的公钥做 ECDH,得共享密钥。 +13. 双方用选定算法从共享密钥派生 SAS(短认证字符串)。如有多种方式,客户端应允许用户选择。 +14. 两端人工比对 SAS,手动告知设备是否一致。 +15. 若认证一致,双方各自针对下述密钥做 MAC 认证: + + * 希望对方验证的所有密钥(通常是各自设备 ed25519 密钥及主跨签名密钥)。 + * 希望对方验证密钥的 key ID 列表。 + + MAC 算法见[下文](#mac-calculation)。 +16. 双方并行发送 `m.key.verification.mac`,各自附上密钥及 ID 的 MAC 值。 +17. 对端收到 `m.key.verification.mac` 后,本地核算 MAC 进行比对,一致则设备密钥通过认证。 +18. 双方各自发送 `m.key.verification.done` 完成验证。 + +Alice/Bob 设备间协议交互如下: + +``` + +-------------+ +-----------+ + | AliceDevice | | BobDevice | + +-------------+ +-----------+ + | | + | m.key.verification.start | + |-------------------------------->| + | | + | m.key.verification.accept | + |<--------------------------------| + | | + | m.key.verification.key | + |-------------------------------->| + | | + | m.key.verification.key | + |<--------------------------------| + | | + | m.key.verification.mac | + |-------------------------------->| + | | + | m.key.verification.mac | + |<--------------------------------| + | | +``` + +###### 错误与异常处理 + +过程中出现错误处理如下: + +- Alice 或 Bob 任何时刻都可取消验证。须发送 `m.key.verification.cancel`。 +- 超时。验证流程超时设为 10 分钟,事务 ID 长时间(10 分钟未收发)未用也需过期,用户应看到超时提示,同时通知对方取消。 +- 一台设备参与多次验证,接收端需取消与该设备的所有未完成尝试。 +- 若收到未知事务 ID,须给对方发送说明原因的 `m.key.verification.cancel`(首次收到 `m.key.verification.start` 或 `m.key.verification.cancel` 除外)。 +- 若双方无共同密钥、哈希、HMAC 或 SAS 算法,则发錯誤 `m.key.verification.cancel`。 +- 用户主观判定 SAS 不一致时,需发送 `m.key.verification.cancel`。 +- 若收到意外次序的消息,应通知对方并取消。 + +###### SAS 验证专用消息 + +通用验证框架基础上,SAS 用到如下事件。 + +`m.key.verification.cancel` 事件无需变更,但新增以下错误码: + +- `m.unknown_method`:双方无法协商出共同算法。 +- `m.mismatched_commitment`:哈希承诺校验失败。 +- `m.mismatched_sas`:SAS 不一致。 + +{{% event event="m.key.verification.start$m.sas.v1" title="`m.key.verification.start` with `method: m.sas.v1`" %}} + +{{% event event="m.key.verification.accept" %}} + +{{% event event="m.key.verification.key" %}} + +{{% event event="m.key.verification.mac" %}} + +###### MAC 计算 + +验证期间,会对密钥以及密钥 ID 列表生成 MAC。 + +采用的 MAC 算法由 [`m.key.verification.accept`](#mkeyverificationaccept) 的 `message_authentication_code` 字段决定。当前要求使用 `hkdf-hmac-sha256.v2`,实现如下: + +1. 用 HKDF([RFC5869](https://tools.ietf.org/html/rfc5869),哈希为 SHA-256)生成 HMAC 密钥。输入为共享密钥。无盐值,info 参数为下列组合: + + - 字符串 `MATRIX_KEY_VERIFICATION_MAC` + - 被 MAC 密钥所属用户的 Matrix ID + - 发送 MAC 的设备 ID + - 另一用户的 Matrix ID + - 接收 MAC 的设备 ID + - 正在使用中的 `transaction_id` + - 被 MAC 密钥的 Key ID,若为密钥列表则为字符串 `KEY_IDS` + +2. 用上述密钥和 SHA-256 按 [RFC2104](https://tools.ietf.org/html/rfc2104) 做 HMAC 得 MAC 值。 + + 若为密钥,则对密钥的公钥编码作 MAC,如 `ed25519` 算法下为未填充 base64 格式; + + 若为密钥 ID 列表,则须字典序排序、以逗号分隔(无额外空格),每个格式如 `{algorithm}:{keyId}`,如:`ed25519:Cross+Signing+Key,ed25519:DEVICEID`。此设计保证接收方比对 mac 字段名时即可还原全体 Key ID,无新增删漏。 + +3. MAC 最后以 base64 编码,并发送于 [`m.key.verification.mac`](#mkeyverificationmac) 事件。 + +{{% boxes/note %}} +曾用的 `hkdf-hmac-sha256` MAC 方法的 base64 编码错误,因 libolm 最初实现缺陷。新版本 `hkdf-hmac-sha256.v2` 与之算法相同,但采用标准 base64 编码。`hkdf-hmac-sha256` 已废弃,日后将移除。若双方都支持 `hkdf-hmac-sha256.v2`,则绝不可使用 `hkdf-hmac-sha256`。 +{{% /boxes/note %}} + +###### SAS HKDF 计算 + +所有 SAS 方法均按 [RFC5869](https://tools.ietf.org/html/rfc5869) HKDF 标准实现,哈希算法取决于之前协商,输入为协商得的共享密钥,无盐: + +当 `key_agreement_protocol` 为 `curve25519-hkdf-sha256` 时,info 参数为: + +- 字符串 `MATRIX_KEY_VERIFICATION_SAS|` +- 启动 `m.key.verification.start` 消息用户 Matrix ID,后跟 `|` +- 启动消息设备 ID,后跟 `|` +- 该设备发出的 `m.key.verification.key` 公钥,未填充 base64,后跟 `|` +- 接受 `m.key.verification.accept` 消息用户 Matrix ID,后跟 `|` +- 该设备 ID,后跟 `|` +- 该设备发出的 `m.key.verification.key` 公钥,未填充 base64,后跟 `|` +- 当前用的 `transaction_id` + +若为废弃的 `curve25519`,info 依次为: + +- 字符串 `MATRIX_KEY_VERIFICATION_SAS` +- 启动用户 Matrix ID +- 启动设备 ID +- 接受用户 Matrix ID +- 接受设备 ID +- `transaction_id` + +不建议新实现支持旧方法 `curve25519`。 + +{{% boxes/rationale %}} +HKDF 能让密钥协商更安全且易于处理。 +{{% /boxes/rationale %}} + +###### SAS 方法:`decimal` + +用 [HKDF](#sas-hkdf-calculation) 生成 5 字节,按 13 位一组转换成十进制数(范围 0~8191),各加 1000,得到 3 组认证码。 + +具体为: + +- 第一组:(*B₀*≪5|*B₁*≫3)+1000 +- 第二组:( (*B₁*&0x7)≪10|*B₂*≪2|*B₃*≫6 )+1000 +- 第三组:( (*B₃*&0x3F)≪7|*B₄*≫1 )+1000 + +用户两端显示时应加分隔符或分行。 + +###### SAS 方法:`emoji` + +用 [HKDF](#sas-hkdf-calculation) 生成 6 字节,将前 42 位分为 7 组(每组 6 位),参照 base64,每组 6 位得 0~63 数字,查下表转为表情: + +{{% sas-emojis %}} + +{{% boxes/note %}} +该表亦可由 JSON 下载: +{{% /boxes/note %}} + +{{% boxes/rationale %}} +上述 Emoji 选择标准: +- 无颜色即能辨识 +- 小图依然清晰 +- 各文化普遍识别 +- 互不相似,不易误认 +- 易用少量词描述 +- 无负面含义、平台表现一致性高 +{{% /boxes/rationale %}} + +客户端应以所表描述或译文显示 Emoji。各客户端宜协作维护多语言译文集。 + +{{% boxes/note %}} +已知译文在 ,在线翻译由 +{{% /boxes/note %}} + +##### 跨签名 + +跨签名功能,允许用户只需一次验证,就能信任对方今后新添加的设备(而无需依次手工验证对方全部设备)。每个用户有一套跨签名密钥:\ + +- 主密钥(MSK):作为跨签名身份密钥,为用户用户主身份,对其他密钥签名; +- 用户签名密钥(USK):仅本用户可见,用于为其他用户主密钥签名; +- 自签名密钥(SSK):用于为本用户所有设备密钥签名。 + +主密钥还可为备份密钥签名。主密钥本身可用各自设备密钥签名,便于从设备验证迁移(如 Alice 先前已验证过 Bob 设备,Bob 设备已签主密钥,Alice 的设备可信任主密钥,并可用自己 USK 签之)。 + +用户通过 [POST /\_matrix/client/v3/keys/device_signing/upload](/client-server-api/#post_matrixclientv3keysdevice_signingupload) API 上传跨签名密钥。Alice 若上传新密钥,其用户 ID 会自动出现在所有与她共享加密房间的用户 `/sync` 响应的 `device_lists` 字段的 `changed` 属性中。看到 Alice ID 后,Bob 应用 [POST /\_matrix/client/v3/keys/query](/client-server-api/#post_matrixclientv3keysquery) 查询 Alice 的设备密钥与跨签名密钥。 + +如果 Alice 想给 Bob 发加密消息,则只要满足: + +- Alice 设备正用主密钥且已签 USK, +- Alice USK 已签 Bob 主密钥, +- Bob 主密钥已签其 SSK, +- Bob 的 SSK 已签 Bob 的设备密钥, + +即可信任 Bob 的设备。下图展示密钥签名关系: + +``` + +------------------+ .................. +----------------+ + | +--------------+ | .................. : | +------------+ | + | | v v v : : v v v | | + | | +-----------+ : : +-----------+ | | + | | | Alice MSK | : : | Bob MSK | | | + | | +-----------+ : : +-----------+ | | + | | | : : : : | | | + | | +--+ :... : : ...: +--+ | | + | | v v : : v v | | + | | +-----------+ ............. : : ............. +-----------+ | | + | | | Alice SSK | : Alice USK : : : : Bob USK : | Bob SSK | | | + | | +-----------+ :...........: : : :...........: +-----------+ | | + | | | ... | : : : : | ... | | | + | | V V :........: :........: V V | | + | | +---------+ -+ +---------+ -+ | | + | | | Devices | ...| | Devices | ...| | | + | | +---------+ -+ +---------+ -+ | | + | | | ... | | ... | | | + | +------+ | | +----+ | + +----------------+ +--------------+ +``` + +其中,方框代表密钥,箭头指示签名方向,虚线代表仅用户本人可见的键或签名。 + +Alice 视角下隐藏她不可见的密钥/签名: + +``` + +------------------+ +----------------+ +----------------+ + | +--------------+ | | | | +------------+ | + | | v v | v v v | | + | | +-----------+ | +-----------+ | | + | | | Alice MSK | | | Bob MSK | | | + | | +-----------+ | +-----------+ | | + | | | | | | | | + | | +--+ +--+ | +--+ | | + | | v v | v | | + | | +-----------+ +-----------+ | +-----------+ | | + | | | Alice SSK | | Alice USK | | | Bob SSK | | | + | | +-----------+ +-----------+ | +-----------+ | | + | | | ... | | | | ... | | | + | | V V +--------+ V V | | + | | +---------+ -+ +---------+ -+ | | + | | | Devices | ...| | Devices | ...| | | + | | +---------+ -+ +---------+ -+ | | + | | | ... | | ... | | | + | +------+ | | +----+ | + +----------------+ +--------------+ +``` + +[验证方法](#device-verification) 也可直接用于验证主密钥:将其公钥(未填充 base64)做为“设备 ID”,按常规定义。例如,Alice 和 Bob 用 SAS 验证后,Alice 的 `m.key.verification.mac` 里可能有 `"ed25519:alices+master+public+key": "alices+master+public+key"`。因此服务器必须防止设备 ID 与跨签名公钥冲突。 + +私钥可借 [Secrets](#secrets) 模块储存在服务器或分发给其他设备。分别用 `m.cross_signing.master`, `m.cross_signing.user_signing`, `m.cross_signing.self_signing` 名称标识,采用 base64 编码后加密。 + +###### 密钥与签名安全 + +主密钥一旦泄露,攻击者即可冒充用户或让用户信任冒名顶替者。因此主密钥私钥必须严格安全储存。若客户端无安全存储能力(如无系统级密钥保护),严禁保存主密钥私钥。 + +看到其他用户更换主密钥,应提醒用户再决定是否继续通信。 + +由于设备 key ID (`ed25519:DEVICE_ID`) 与跨签名 key ID (`ed25519:PUBLIC_KEY`) 处于同一命名空间,客户端必须区分并用公钥实际内容定位验证目标。 + +服务器虽应禁止设备 ID 与跨签名密钥冲突,但仍须防范恶意服务器,所以客户端应注意: + +1. 在验证过程中用密钥公钥而不是仅用 key ID 识别密钥; +2. 验证一开始就锁定目标密钥,并确保其在过程中未被更换; +3. 如发现用户下设备 ID 与跨签名 key 相同,必须拒绝验证并弹警告。 + +用户签名与自签名密钥意在可被快速替换(如有泄露,仅需主密钥重签及适度重新验证)。但发现被攻破和重签都要耗用户精力,因此应优先安全存储私钥,否则干脆不存储,以权衡安全与便用。 + +为防社交网络泄露,服务器仅允许用户查阅: + +- 自己主密钥/自签/用户签名密钥的签名, +- 自己设备对自己主密钥的签名, +- 他人自签密钥对其设备的签名, +- 他人主密钥对其自签密钥的签名, +- 他人设备对其主密钥的签名。 + +用户无法看到其他人 user-signing key 的签名。 + +{{% http-api spec="client-server" api="cross_signing" %}} + +##### 二维码 + +{{% added-in v="1.1" %}} + +二维码验证适用于一方设备支持扫码,可快速验证。二维码内容编码双方主签名密钥及一组随机共享密钥供单次扫描双向验证。 + +若支持显示二维码,客户端在 `m.key.verification.request` 和 `m.key.verification.ready` 的 `methods` 字段中声明 `m.qr_code.show.v1` 和 `m.reciprocate.v1`。若支持扫码,则用 `m.qr_code.scan.v1` 和 `m.reciprocate.v1`。如果既支持显示又支持扫码,则全部声明。 + +Alice、Bob 互验证流程: + +1. Alice 和 Bob 面对面,欲验证钥匙。 +2. 启动验证流程。 +3. Alice 客户端显示二维码,若 Bob 客户端能扫码则 Bob 可选扫码;Bob 客户端也可以显示二维码或选择扫码。二维码格式见下文。其他验证方式如 SAS Emoji 可并列提供。 +5. Alice 扫描 Bob 的二维码。 +6. Alice 设备校验扫码内容是否为期望的公钥。如失败则报错同时发送 `m.key.verification.cancel` 给 Bob。 + + 否则 + - 此时 Alice 已信任 Bob 密钥, + - 并知道 Bob 拥有 Alice 的正确密钥。 + 接下来 Alice 需告知 Bob 验证结果以使其信任 Alice 密钥。 +7. Alice 设备显示验证成功;Bob 设备尚未通过验证(需等待 Alice 明确反馈),用户需人工看到 Alice 已同意。 +8. Alice 设备发送 `m.key.verification.start(method=m.reciprocate.v1)` 给 Bob,包含共享密钥。仅作信号用,无验证功效。 +9. Bob 收到上述消息,校验共享密钥。如不符则报错(这不影响 Alice 对 Bob 的验证);如一致,则请求 Bob 手动确认已经被验证。 +10. Bob 见 Alice 端确认密钥一致后,点按钮确认验证。 + + Bob 信任 Alice,依据于 Alice 现场告知已验证成功。恶意 Alice 欺骗只影响自己与 Bob 通信,Alice 没动力作假。因而只要通信媒介可靠(如真人言语),这一流程足以可信。 +11. 双方退回 `m.key.verification.done`。 + +###### 二维码格式 + +二维码必须兼容 [ISO/IEC 18004:2015](https://www.iso.org/standard/62021.html),仅使用字节模式单分段。 + +纠错级别由展示端自行选择。 + +二进制内容结构如下: + +- ASCII "MATRIX",各字节编码分别为 0x4D, 0x41, 0x54, 0x52, 0x49, 0x58 +- 1 字节,二维码版本(须为 0x02) +- 1 字节,二维码验证模式,值为: + - 0x00 验证其他用户(跨签名) + - 0x01 本端信任主密钥情况下自验证 + - 0x02 本端尚未信任主密钥的自验证 +- 关联验证事件的 event ID 或 transaction_id,方式为: + - 2 字节,网络字节序,长度 + - 实际 UTF-8 字符串编码的 ID +- 第一个 32 字节密钥,含义: + - 若 mode==0x00 或 0x01,则本用户主跨签名公钥 + - 若 mode==0x02,则本设备 Ed25519 签名密钥 +- 第二个 32 字节密钥,含义: + - 若 mode==0x00,则为他人主跨签名公钥 + - 若 mode==0x01,则为他人设备 Ed25519 公钥 + - 若 mode==0x02,为本用户主跨签名公钥 +- 一组随机共享密钥(推荐约 8 字节),为编码内容的剩余部分 + +实例:Alice 的二维码内容 + +``` + "MATRIX" |ver|mode| len | event ID + 4D 41 54 52 49 58 02 00 00 2D 21 41 42 43 44 ... +| 用户主密钥 | 对方主密钥 | 共享密钥 + 00 01 02 03 04 05 06 07 ... 10 11 12 13 14 15 16 17 ... 20 21 22 23 24 25 26 27 +``` + +代表 Alice 验证 Bob,在事件 "$ABCD..." 下自认主密钥为 `0001020304050607...` (base64: "AAECAwQFBg..."),她认为 Bob 的主密钥为 `1011121314151617...` (base64: "EBESExQVFh..."),共享密钥为 `2021222324252627` (base64: "ICEiIyQlJic")。 + +###### 二维码专用验证消息 + +{{% event event="m.key.verification.start$m.reciprocate.v1" title="`m.key.verification.start` with `method: m.reciprocate.v1`" %}} + +#### 设备间共享密钥 + +Bob 若在电脑端与 Alice 有加密对话,在手机端首次登入时,或希望能访问到历史消息。为此本协议支持若干跨设备密钥转移方式。 + +##### 密钥请求 + +如果设备缺失解密信息所需的密钥,可向其他设备发 [m.room_key_request](#mroom_key_request) to-device 消息,请求字段 `action` 设为 `request`。 + +其他设备同意分享密钥后,可通过加密的 [m.forwarded_room_key](#mforwarded_room_key) to-device 消息发送给请求设备。请求设备收到后,需向所有原发出请求的设备发 `request_cancellation` 的 [m.room_key_request](#mroom_key_request) 通知取消,接收端一旦收到 `request_cancellation` 就应忽视所有同一 `request_id` 和 `requesting_device_id` 的早前请求。 + +如设备决定不共享密钥,可以发 [m.room_key.withheld](#mroom_keywithheld) 以反馈拒绝加密密钥分享,详见[报告加密密钥被拒绝](#reporting-that-decryption-keys-are-withheld)。 + +{{% boxes/note %}} +密钥分享本身是攻击点,必须谨慎对待。客户端应只向受信任同一用户的设备请求/发密钥,并只接受来自受信任同一用户设备的转发密钥。 +{{% /boxes/note %}} + +##### 服务器端密钥备份 + +设备可将加密密钥上传服务器做加密备份。需解密某消息时,设备可向服务器请求该密钥并解密。备份为每用户维护,用户可重置覆盖已有备份。 + +相比[密钥请求](#key-requests),服务器备份无需在线设备即可获取密钥。但会话密钥在服务器以加密形式存储,客户端需有[解密密钥](#decryption-key) 方可解密备份。 + +创建备份时,客户端调用 [POST /\_matrix/client/v3/room_keys/version](#post_matrixclientv3room_keysversion),加密方式定义于 `auth_data`。其他客户端用 [GET /\_matrix/client/v3/room_keys/version](#get_matrixclientv3room_keysversion) 发现备份。密钥随后按备份的 `auth_data` 加密,并用 [PUT /\_matrix/client/v3/room_keys/keys](#put_matrixclientv3room_keyskeys) 或其相关变体上传,可用 [GET /\_matrix/client/v3/room_keys/keys](#get_matrixclientv3room_keyskeys) 或变体下载。一次仅能写入最新备份版本。也可用 [DELETE /\_matrix/client/v3/room_keys/version/{version}](#delete_matrixclientv3room_keysversionversion) 或 [DELETE /\_matrix/client/v3/room_keys/keys](#delete_matrixclientv3room_keyskeys) 等方式删除备份或部分密钥。 + +客户端上传密钥前,须确保 `auth_data` 已被信任。可通过: + +- 检查其是否由用户主跨签名密钥或受信设备签名 +- 或用私钥本地推导出并验证公钥是否一致。受信私钥获取方式包括用户自己输入、从[秘密存储](#secret-storage)读取,或经[秘密共享](#sharing)自本用户受信设备拉取密钥。 + +如果上传会话密钥已存在,服务器对比密钥元数据保留或覆盖,规则如下: + +- 若有 `is_verified` 字段,优先保留设为 `true` 的; +- 若两者都同等,则选择 `first_message_index` 更小者; +- 最后由 `forwarded_count` 更小者获保留。 + +###### 解密密钥 + +通常,解密钥匙(即密钥的私有部分)会以 [Secrets](#secrets) 模块方式存储服务器或发送给其他设备,采用 `m.megolm_backup.v1` 名称,且加密前为 base64 编码。 + +如用户直接复制密钥,则以[通用加密密钥表示法](/appendices/#cryptographic-key-representation)为字符串展示。 + +{{% boxes/note %}} +本规范早前使用“恢复密钥”一词,但各客户端 UI 通常用该词指[秘密存储](#storage)密钥,为避免歧义,现不再使用该说法。 +{{% /boxes/note %}} + +###### 备份算法:`m.megolm_backup.v1.curve25519-aes-sha2` + +若备份的 `algorithm` 为 `m.megolm_backup.v1.curve25519-aes-sha2`,则 `auth_data` 结构如下: + +{{% definition path="api/client-server/definitions/key_backup_auth_data" %}} + +备份的 `session_data` 字段生成步骤: + +1. 把要备份的会话密钥编码为 `BackedUpSessionData` 格式的 JSON 对象。 + +2. 生成临时 curve25519 密钥,并用它和备份公钥做 ECDH 得共享密钥。临时公钥(未填充 base64)存为 `ephemeral` 字段。 + +3. 以共享密钥做 HKDF(哈希算法为 SHA-256,盐为 32 字节全 0,info 为空字符串),得 80 字节。前 32 字节作 AES 密钥,下 32 字节作 MAC 密钥,后 16 字节作 AES 初始化向量。 + +4. JSON 序列化,加密方式为 AES-CBC-256/PKCS#7,密文未填充 base64 编码存于 `ciphertext`。 + +5. 用 MAC 密钥计算 HMAC-SHA-256(消息体为空),取前 8 字节转换为 base64 存为 `mac` 字段。 + +{{% boxes/warning %}} +第五步本意应对原始密文做 HMAC,但 libolm 实现失误导致实际传递空字符串。未来规范将修正此问题。参见 [MSC4048](https://github.com/matrix-org/matrix-spec-proposals/pull/4048)。 +{{% /boxes/warning %}} + +{{% definition path="api/client-server/definitions/key_backup_session_data" %}} + +{{% http-api spec="client-server" api="key_backup" %}} + +##### 密钥导出 + +密钥可手工导出成加密文件,经用户复制后导入另一设备。文件加密方式如下: + +1. 会话数据以 [Key export format](#key-export-format) JSON 对象格式编码。 + +2. 用户口令经 PBKDF2(HMAC-SHA-512, password, S, N, 512) 推导 512 位密钥。S 为 128 比特随机盐,N 迭代次数(至少 10 万)。K, K' 为前后 256 比特,K 为 AES-256 密钥,K' 供 HMAC-SHA-256。 + +3. JSON 字符串化后用 AES-CTR-256/K 加密,IV 预设为 128 比特安全随机数且 bit 63 为零(兼容实现差异)。 + +4. 按顺序拼接如下: + +| 长度(字节)| 描述 | +| ------------|-----------------------------------------------------------------------------------------| +| 1 | 导出格式版本,须为 `0x01`。 | +| 16 | 盐 S。 | +| 16 | 初始化向量 IV。 | +| 4 | N,32 位大端整数。 | +| 变长 | 加密 JSON。 | +| 32 | 以上所有数据用 K' 做 HMAC-SHA-256 后的结果。 | + +5. 整体 base64 编码。可适当换行。 + +6. 最终整体包裹于 `-----BEGIN MEGOLM SESSION DATA-----\n` 和 `\n-----END MEGOLM SESSION DATA-----\n`。 + +###### 密钥导出格式 + +导出会话为 `ExportedSessionData` JSON 数组,具体定义: + +{{% definition path="api/client-server/definitions/megolm_export_session_data" %}} + +#### 消息算法 + +##### 消息算法命名 + +消息算法命名使用全规范内统一扩展格式。以 `m.` 开头的算法名保留为本规范定义。自定义算法应按 Java 包规范全局唯一命名。 + +算法名应简短清晰,并表明所用原始算法,以便判断安全性。例如: + +`m.olm.v1` 太短,识别度低且难于扩展。 +`m.olm.v1.ecdh-curve25519-hdkfsha256.hmacsha256.hkdfsha256-aes256-cbc-hmac64sha256` 太冗长且损耗带宽、可读性差。 + +##### `m.olm.v1.curve25519-aes-sha2` + +此名代表 Olm 协议 v1,见 [Olm 规范](http://matrix.org/docs/spec/olm.html)。其组成: + +- Curve25519 初始密钥协商 +- HKDF-SHA-256 密钥推进 +- Curve25519 用作根密钥推进 +- HMAC-SHA-256 推进主键 +- HKDF-SHA-256,AES-256-CBC,8 字节 HMAC-SHA-256 验证加密 + +支持 Olm 的设备必须将 "m.olm.v1.curve25519-aes-sha2" 纳入支持算法列表,发布 Curve25519 设备密钥和一次性密钥。 + +一份 Olm 加密的事件: + +```json +{ + "type": "m.room.encrypted", + "content": { + "algorithm": "m.olm.v1.curve25519-aes-sha2", + "sender_key": "", + "ciphertext": { + "": { + "type": 0, + "body": "" + } + } + } +} +``` + +ciphertext 为设备 Curve25519 公钥到加密负载的映射。body 为 Base64 编码的 Olm 消息内容。type 整数:0 为初始 key,1 为后续普通消息。 + +Olm 会话发送消息前,均为类型 0;收到对端消息后,转为类型 1。 + +客户端收到类型 0 消息,需先查是否已有匹配会话;若没有则新建并尝试解密,解密成功前不得持久化会话或销毁一次性密钥。 + +类型 1 需已有会话才能解密,若无会话,则视为无效消息。 + +明文负载如下: + +```json +{ + "type": "", + "content": "", + "sender": "", + "recipient": "", + "recipient_keys": { + "ed25519": "" + }, + "keys": { + "ed25519": "" + } +} +``` + +type 与 content 对应具体消息类型与内容。 + +这些字段用于防止攻击者冒名发 curve25519 公钥假冒自己。sender 应为发送者用户,recipient 为本地用户,recipient_keys 标明本端 ed25519。 + +客户端需确认加密消息正文中 `sender_key` 和解密明文中的 `keys.ed25519` 与 [`/keys/query`](#post_matrixclientv3keysquery) 查询到的密钥相符。还需核实密钥签名。否则无法确认发送设备拥有所声称 ed25519 私钥,这对经过验证设备尤为重要。 + +如与对方建立了多个会话,应选用最近收到且成功解密过消息的那个。若尚无消息则以建立时间论新旧。为避免膨胀,可为每个设备设一个最大会话数(至少 4),采用 LRU 策略淘汰旧会话。 + +###### 恢复不可解密 Olm 消息 + +有时消息因各种原因无法解密。此时应假定 Olm 会话失效,需要新建会话。 + +{{% boxes/note %}} +Megolm 加密消息通常不会这样。未解密的消息一般密钥随后可获得。但 Olm 无此恢复机制,故必须新建会话。 +{{% /boxes/note %}} + +新建会话时,需向对端发送 [m.dummy](#mdummy) 事件通知会话变更。 + +客户端应限速,不得一小时内反复新建会话。 + +可通过 `m.room_key_request` 请求帮助找回因失效而丢失的 Megolm 会话密钥。 + +{{% boxes/note %}} +对于未知 Megolm 会话的密钥请求,应广播给该用户的所有设备(不只当前 event 的 device_id 或 sender_key),因这些字段已废弃。见 [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2)。 +{{% /boxes/note %}} + +##### `m.megolm.v1.aes-sha2` + +{{% changed-in v="1.3" %}} + +`m.megolm.v1.aes-sha2` 代表 Megolm 算法 v1, 详见 [Megolm 规范](http://matrix.org/docs/spec/megolm.html)。详细: + +- HMAC-SHA-256 连续哈希推进 +- HKDF-SHA-256,AES-256-CBC,加 8 字节 HMAC-SHA-256 验证 +- Ed25519 签名消息 + +支持 Megolm 的设备即需支持 Olm,且将本算法纳入支持算法列表。 + +加密事件格式: + +```json +{ + "type": "m.room.encrypted", + "content": { + "algorithm": "m.megolm.v1.aes-sha2", + "sender_key": "", + "device_id": "", + "session_id": "", + "ciphertext": "" + } +} +``` + +明文负载为: + +```json +{ + "type": "", + "content": "", + "room_id": "" +} +``` + +room_id 写入明文防止服务器篡改房间。 + +客户端须防范重放攻击,记录 Megolm ratchet index,应拒绝重复 index 的消息(须避免误杀,如正常流程可能重复解密一条消息)。 + +同 Olm,客户端需确认消息发送人即明文 sender 字段,其房间与 session_id 已被本端信任记录。 + +{{% boxes/note %}} +自 `v1.3` 起,`sender_key` 与 `device_id` 字段已废弃。应继续发送,但不得用其校验消息来源。 + +客户端不得用这两字段存储/检索会话。 + +将来规范版本中,这些字段将完全移除。 +{{% /boxes/note %}} + +{{% boxes/rationale %}} +移除此类字段,提升隐私和安全性,主设备不可见、降低对不受信数据(服务器可篡改、用户故意作假)的依赖。 + +session_id 本身全局唯一,无需额外 context 字段。 + +减少此依赖同时提升隐私与安全性。 +{{% /boxes/rationale %}} + +要在房间启用端到端加密,客户端可发 `m.room.encryption` 状态事件,`algorithm` 为 `m.megolm.v1.aes-sha2`。 + +房间新建 Megolm 会话后,需用 Olm 私信分发 session key 给目标设备,以便其解密今后消息。密钥由 `m.room_key` 事件发送。收到他人密钥后,须存储以便解密消息。 + +收到会话密钥时,必须确保密钥由 Olm channel 安全获得,以确认消息真实性。 + +当客户端要更新 Megolm 会话数据时,必须确保新数据仅来自可信来源(如本用户已验证设备的 `m.forwarded_room_key` 或 `m.room_key`),且新密钥的 message index 必须小于已有密钥。 + +#### 协议定义 + +##### 事件 + +{{% event event="m.room.encryption" %}} + +{{% event event="m.room.encrypted" %}} + +{{% event event="m.room_key" %}} + +{{% event event="m.room_key_request" %}} + +{{% event event="m.forwarded_room_key" %}} + +{{% event event="m.dummy" %}} + +##### 密钥管理 API + +{{% http-api spec="client-server" api="keys" %}} + +##### /sync 扩展 {#e2e-extensions-to-sync} + +本模块为 [`/sync`](/client-server-api/#get_matrixclientv3sync) 响应新增可选 `device_lists` 字段(详见下文)。仅增量 `/sync`(指定 `since` 参数时)需返回。客户端应在初始同步后用 [`/keys/query`](/client-server-api/#post_matrixclientv3keysquery) 或 [`/keys/changes`](/client-server-api/#get_matrixclientv3keyschanges) 跟进,见[跟踪用户设备列表](#tracking-the-device-list-for-a-user)。 + +同时新增 `device_one_time_keys_count` 属性。注意拼写与 [`/keys/upload`](/client-server-api/#post_matrixclientv3keysupload) 响应的 `one_time_key_counts` 有区别。 + +{{% added-in v="1.2" %}} 最后,新增 `device_unused_fallback_key_types` 列举当前设备已上传但尚未被领用的备用密钥算法。若某算法此前上传的备用密钥不在列表,则应在必要时上传替换密钥。此属性为强制包含项,亦可用于判断服务器对备用密钥的支持(如 `/versions` 外的备用判断方式)。 + +| 参数 | 类型 | 描述 | +|-------------------------------|--------------------|----------------------------------------------------------------------------| +| device_lists | DeviceLists | 可选。e2e 设备变更信息,仅在增量 sync 响应中出现。 | +| device_one_time_keys_count | {string: integer} | 可选。按算法分列当前设备未被认领的一次性密钥数,未传视为 0。 | +| device_unused_fallback_key_types | [string] | **必选。** 未被使用的备用密钥算法列表。 | + +`DeviceLists` + +| 参数 | 类型 | 描述 | +|----------|-----------|--------------------------------------------------------------------------------------------------------| +| changed | [string] | 设备身份或跨签名密钥有更新、或新近与本客户端共享加密房间的用户列表。 | +| left | [string] | 自上次 sync 后,本客户端不再与之共享任何加密房间的用户列表。 | + +{{% boxes/note %}} +最优逻辑下,仅在 Alice 更新设备、密钥或与 Bob 新建共享房间时,在 Bob 的 sync 的 changed 字段添加 Alice。但为了简化,服务器也可在 Alice 与 Bob 每次新建共享房间(无论是否已共享)时添加。 +{{% /boxes/note %}} + +例: + +```json +{ + "next_batch": "s72595_4483_1934", + "rooms": {"leave": {}, "join": {}, "invite": {}}, + "device_lists": { + "changed": [ + "@alice:example.com", + ], + "left": [ + "@bob:example.com", + ], + }, + "device_one_time_keys_count": { + "signed_curve25519": 20 + }, + "device_unused_fallback_key_types": ["signed_curve25519"] +} +``` + +#### 报告密钥被拒绝 + +当客户端向房间内其他设备发送加密事件时,可选择通知那些因未提供密钥而无法解密事件的设备。如此接收方即可明确原因而非泛泛报错。 + +同理,一台设备通过[密钥请求](#key-requests) 向他设备请求密钥,对方亦可主动说明拒绝分享密钥。 + +如 Alice 一开始不愿向 Bob 分享部分消息的 Megolm 会话,后期决定给予 Bob 解密后续消息的权力,可发送只包含最新版会话密钥的消息,且在 Bob 的新设备请求密钥时,会获得被 ratchet(推进)过的最新版本。Bob 旧设备可在 `m.forwarded_room_key` 里以对象 `withheld` 字段附上最初被拒绝的原因代码。 + +{{% event event="m.room_key.withheld" %}} \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/event_annotations.md b/locales/zh-Hans/client-server-api/modules/event_annotations.md new file mode 100644 index 00000000..d8f2b052 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/event_annotations.md @@ -0,0 +1,67 @@ +### 事件注释与反应 + +{{% added-in v="1.7" %}} + +#### `m.annotation` 关系类型 + +注释是一类采用[event 关系](#forming-relationships-between-events)并带有 `rel_type` 为 `m.annotation` 的事件。 + +注释通常用于“反应”:例如,如果用户想要对某个事件表示点赞,则客户端会发送一个带有相应表情(如👍)的注释事件。另一个可能的用例是让机器人发送事件来指示某条命令的成功或失败。 + +除了标准属性 `event_id` 和 `rel_type` 外,`m.relates_to` 属性中的 `rel_type: m.annotation` 应包含一个 `key`,用于表示所应用的注释。例如,在使用表情符号进行反应时,key 包含所使用的表情符号。 + +如下所示是一个 `m.annotation` 关系的示例: + +```json +"m.relates_to": { + "rel_type": "m.annotation", + "event_id": "$some_event_id", + "key": "👍" +} +``` + +{{% boxes/note %}} +任何类型的事件都可以被注释,包括状态事件。 +{{% /boxes/note %}} + +#### 事件 + +{{% event event="m.reaction" %}} + +#### 客户端行为 {id="annotations-client-behaviour"} + +注释设计的意图是对其进行计数,而不是单独展示。客户端必须为每个事件统计他们观察到的给定事件 `type` 和注释 `key` 的注释数量;这些计数通常在时间线上与事件一起显示。 + +在进行计数时: + + * 每个事件 `type` 和注释 `key` 通常应分别计数,但是否实际分开计数取决于具体的实现。 + + * [被忽略用户](#ignoring-users)发送的注释事件应排除在计数之外。 + + * 来自同一用户(即 `sender` 相同)的多个完全相同的注释(即 `type` 与 `key` 都相同)应计为一次注释。 + + * 对于引用了自身带有 `m.relates_to`,其 `rel_type` 为 `m.annotation` 或 `rel_type` 为 `m.replace` 的事件的注释事件,实现应忽略。换句话说,[替换事件](#event-replacements)或注释本身不能被再次注释。注释应仅指向原始事件。 + + * 当某个注释被撤回时,应从计数中移除。 + +{{% boxes/note %}} +反应不可编辑,因为替换事件不会更改 `m.relates_to`(见[应用 `m.new_content`](#applying-mnew_content)),并且 `m.reaction` 中没有其他有意义的内容。如果用户希望更改自己的反应,应该撤回原始反应,并发送新的反应事件替代。 +{{% /boxes/note %}} + +{{% boxes/note %}} +`m.reaction` 中的 `key` 字段可以为任意字符串,因此客户端在渲染过长反应内容时需采取合理方式。例如,客户端可以省略过长的反应内容。 +{{% /boxes/note %}} + +#### 服务器行为 + +##### 避免重复注释 + +HomeServer 应当防止用户针对同一事件,使用相同的事件 `type` 和注释 `key` 发送第二次注释(除非第一次发送的事件已被撤回)。 + +试图发送此类注释应返回 400 错误以及错误码 `M_DUPLICATE_ANNOTATION`。 + +但这并不能保证重复的注释不会通过联邦网络到达。客户端在[计数注释](#annotations-client-behaviour)时有责任对接收到的注释进行去重。 + +##### 服务器端对 `m.annotation` 关系的聚合 + +`m.annotation` 关系**不会**被服务器[聚合](#aggregations-of-child-events)。换句话说,`m.annotation` 不会包含在 `m.relations` 属性中。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/event_context.md b/locales/zh-Hans/client-server-api/modules/event_context.md new file mode 100644 index 00000000..32f43830 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/event_context.md @@ -0,0 +1,13 @@ +### 事件上下文 + +该 API 返回发生在指定事件之前和之后的一系列事件。这样,客户端可以获取围绕某一事件的上下文信息。 + +#### 客户端行为 + +用于检索事件上下文的 HTTP API 只有一个,具体文档如下。 + +{{% http-api spec="client-server" api="event_context" %}} + +#### 安全注意事项 + +服务器只能返回用户有权限查看的结果。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/event_replacements.md b/locales/zh-Hans/client-server-api/modules/event_replacements.md new file mode 100644 index 00000000..4baaee5e --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/event_replacements.md @@ -0,0 +1,317 @@ +### 事件替换 + +{{% added-in v="1.4" %}} + +事件替换,或称“消息编辑事件”,是指那些使用 [事件关系](#forming-relationships-between-events),`rel_type` 为 `m.replace` 的事件,表示原始事件将被替换。 + +一条消息编辑事件的示例如下: + +```json +{ + "type": "m.room.message", + "content": { + "body": "* Hello! My name is bar", + "msgtype": "m.text", + "m.new_content": { + "body": "Hello! My name is bar", + "msgtype": "m.text" + }, + "m.relates_to": { + "rel_type": "m.replace", + "event_id": "$some_event_id" + } + }, + // ... 事件所需的其他字段 +} +``` + +替换事件的 `content` 必须包含 `m.new_content` 属性,用于定义替换后的内容。正常的 `content` 属性(如 `body`、`msgtype` 等)则为不支持替换事件的客户端提供兼容回退。 + +`m.new_content` 可以包含事件内容中通常存在的任意属性,例如 `formatted_body`(参见 [`m.room.message` `msgtypes`](#mroommessage-msgtypes))。 + +#### 替换事件的有效性 + +替换事件需满足一系列要求,才能被视为有效替换: + + * 如同所有的事件关系一样,原始事件和替换事件必须具有相同的 `room_id`(即不能在一个房间发送事件,在另一个房间发送其编辑版本)。 + * 原始事件与替换事件必须拥有相同的 `sender`(即不能编辑他人的消息)。 + * 替换事件和原始事件的 `type` 必须相同(即不能更改原始事件的类型)。 + * 替换事件和原始事件不得包含 `state_key` 属性(即完全不能编辑状态事件)。 + * 原始事件本身不能具有 `rel_type` 为 `m.replace`(即不能编辑一条编辑事件——但可以为同一原始事件发送多次编辑)。 + * 替换事件(若适用,解密后)必须包含 `m.new_content` 属性。 + +如果未满足上述任一条件,则实现应忽略该替换事件(不应替换原文内容,也不应将该编辑纳入服务端聚合)。 + +请注意,替换事件 [`m.room.message`](#mroommessage-msgtypes) 的 `msgtype` 属性**不必**与原始事件相同。例如,将 `m.text` 事件替换为 `m.emote` 是合法的。 + +#### 编辑加密事件 + +若原始事件是 [加密](#end-to-end-encryption) 的,则替换事件也应加密。在这种情况下,`m.new_content` 被放置于加密负载的内容中。如同所有事件关系,`m.relates_to` 属性必须位于事件的未加密(明文)部分。 + +例如,一个加密事件的替换事件可能如下所示: + +```json +{ + "type": "m.room.encrypted", + "content": { + "m.relates_to": { + "rel_type": "m.replace", + "event_id": "$some_event_id" + }, + "algorithm": "m.megolm.v1.aes-sha2", + "sender_key": "", + "device_id": "", + "session_id": "", + "ciphertext": "" + } + // 未显示无关字段 +} +``` + +一旦解密,负载内容可能如下: + +```json +{ + "type": "m.room.", + "room_id": "!some_room_id", + "content": { + "body": "* Hello! My name is bar", + "msgtype": "m.text", + "m.new_content": { + "body": "Hello! My name is bar", + "msgtype": "m.text" + } + } +} +``` + +请注意: + + * 加密负载中**没有** `m.relates_to` 属性。如果有,将会被忽略。 + * `m.room.encrypted` 事件明文内容中**没有** `m.new_content` 属性。如果有,同样会被忽略。 + +{{% boxes/note %}} +加密替换事件的负载必须如常加密,包括像往常一样推进任何 [Megolm](#mmegolmv1aes-sha2) 会话。**不应**重复使用原有的 Megolm ratchet 条目。 +{{% /boxes/note %}} + +#### 应用 `m.new_content` + +应用替换时,原始事件的 `content` 被视为被 `m.new_content` 全量覆盖,仅保留 `m.relates_to` 属性**不变**。`m.new_content` 内部的任何 `m.relates_to` 属性均被忽略。 + +例如,给定以下两条事件: + +```json +{ + "event_id": "$original_event", + "type": "m.room.message", + "content": { + "body": "I really like cake", + "msgtype": "m.text", + "formatted_body": "I really like cake", + } +} +``` + +```json +{ + "event_id": "$edit_event", + "type": "m.room.message", + "content": { + "body": "* I really like *chocolate* cake", + "msgtype": "m.text", + "m.new_content": { + "body": "I really like *chocolate* cake", + "msgtype": "m.text", + "com.example.extension_property": "chocolate" + }, + "m.relates_to": { + "rel_type": "m.replace", + "event_id": "$original_event_id" + } + } +} +``` + +……最终结果如下所示: + +```json +{ + "event_id": "$original_event", + "type": "m.room.message", + "content": { + "body": "I really like *chocolate* cake", + "msgtype": "m.text", + "com.example.extension_property": "chocolate" + } +} +``` + +注意此时 `formatted_body` 已不存在,因为替换事件中已省略该字段。 + +#### 服务器行为 + +##### 服务端对 `m.replace` 关系的聚合 + +{{% changed-in v="1.7" %}} + +请注意,同一个原始事件可以有多个 `m.replace` 关系的事件(例如多次编辑)。这些应由主服务器进行 [聚合](#aggregations-of-child-events)。 + +`m.replace` 关系的聚合格式会提供**最新**的替换事件,格式 [同常规](#room-event-format)。 + +最新事件通过比较 `origin_server_ts` 决定;若有两个或以上替换事件 `origin_server_ts` 相同,则以字典序最大的 `event_id` 为最新。 + +同其他子事件聚合一样,对应于 `m.replace` 关系的聚合包含在被目标事件的 `unsigned` 的 `m.relations` 属性下。例如: + +```json +{ + "event_id": "$original_event_id", + "type": "m.room.message", + "content": { + "body": "I really like cake", + "msgtype": "m.text", + "formatted_body": "I really like cake" + }, + "unsigned": { + "m.relations": { + "m.replace": { + "event_id": "$latest_edit_event_id", + "origin_server_ts": 1649772304313, + "sender": "@editing_user:localhost" + "type": "m.room.message", + "content": { + "body": "* I really like *chocolate* cake", + "msgtype": "m.text", + "m.new_content": { + "body": "I really like *chocolate* cake", + "msgtype": "m.text" + }, + "m.relates_to": { + "rel_type": "m.replace", + "event_id": "$original_event_id" + } + } + } + } + } + // 未显示无关字段 +} +``` + +如果原始事件被 [抹除](#redactions),则任何 +`m.replace` 关系**不应**与其打包(无论后续替换本身是否被抹除)。请注意,此行为特定于 `m.replace` 关系。另请参考下文 [已编辑事件的抹除](#redactions-of-edited-events)。 + +**注意:**原始事件的 `content` 保持不变。特别是服务器**不应**将内容用替换事件内容替换。 + +{{% boxes/rationale %}} +此前规范版本要求服务器在向客户端提供已编辑事件时替换其内容(除 +[`GET /_matrix/client/v3/rooms/{roomId}/event/{eventId}`](#get_matrixclientv3roomsroomideventeventid) +接口外)。然而,这样会导致客户端实现难以保持一致,因此服务器不再进行此操作。 +{{% /boxes/rationale %}} + +#### 客户端行为 + +由于服务器不会替换任何已编辑事件内容,客户端应注意所有收到的替换事件,并尽可能和适当时应用替换。 + +客户端作者请注意 [替换事件的有效性](#validity-of-replacement-events) 要求,忽略所有无效的替换事件。 + +##### 永久链接 + +创建指向事件的[链接](/appendices/#uris)(即永久链接)时,客户端将构建指向其当前所见事件的链接(可能是消息编辑事件)。 + +查看该永久链接的客户端应定位到原始事件,并显示该事件的最新版本。 + +#### 已编辑事件的抹除 + +当使用 `rel_type` 为 `m.replace` 的事件被 [抹除](#redactions) 时,该编辑修订被移除。如果有后续编辑,影响较小;但如果这是最新编辑,则事件实际上回退为被抹除编辑前的内容。 + +抹除*原始*消息则实际上移除该消息及所有后续编辑,使其不再出现在可见时间线上。在这种情况下,homeserver 会如同处理其他抹除事件一样,为原始事件返回空的 `content`,且如 +[前述](#server-side-aggregation-of-mreplace-relationships) 替换事件不会打包于原始事件对应的聚合中。注意后续编辑本身并没有被真正抹除:它们仅在可见时间线之外不发挥作用。 + +#### 带有提及的事件编辑 + +编辑包含 [用户和房间提及](#user-and-room-mentions) 的事件时,替换事件会含有两个 `m.mentions` 属性: + +* 位于 `content` 顶层的,记录该修订中产生的新提及。 +* 位于 `m.new_content` 属性内的,记录事件最新版本中所有已解析的提及。 + +以上差异可确保用户不会对事件的每次编辑都收到通知,但又允许提及新用户(或在编辑幅度足够大的情况下重新通知)。 + +例如,存在一条提及 Alice 的事件: + +```json +{ + "event_id": "$original_event", + "type": "m.room.message", + "content": { + "body": "Hello Alice!", + "m.mentions": { + "user_ids": ["@alice:example.org"] + } + } +} +``` + +编辑后同时提及 Bob: + +```json +{ + "content": { + "body": "* Hello Alice & Bob!", + "m.mentions": { + "user_ids": [ + // 仅包含新提及的用户 + "@bob:example.org" + ] + }, + "m.new_content": { + "body": "Hello Alice & Bob!", + "m.mentions": { + "user_ids": [ + // 包含所有已提及的用户 + "@alice:example.org", + "@bob:example.org" + ] + }, + }, + "m.relates_to": { + "rel_type": "m.replace", + "event_id": "$original_event" + } + }, + // 事件需要的其他字段 +} +``` + +若某一修订移除了某个用户的提及,则该用户的 Matrix ID 不应出现在任何 `m.mentions` 属性中。 + +客户端也可据此调整 [提及事件的客户端行为](#user-and-room-mentions),通过检查 `m.new_content` 下的 `m.mentions` 属性判定事件是否提及当前用户。 + +#### 回复消息的编辑 + +对替换 [回复](#rich-replies) 的事件存在特殊约束:与原始回复不同,`m.relates_to` 对象中**不得**出现 `m.in_reply_to` 属性,因为这将显得多余(见上文[应用 `m.new_content`](#applying-mnew_content) 章节已说明原始事件的 `m.relates_to` 会保留),且与事件关系机制“一事件只存在一个‘父级’”的理念相悖。 + +{{% boxes/note %}} +{{% changed-in v="1.13" %}} +规范早期版本允许替换 [回复](#rich-replies) 的事件在 `content` 中包含回退信息。此规则已废除。 +{{% /boxes/note %}} + +编辑回复的示例如下: + +```json +{ + "type": "m.room.message", + // 未显示无关字段 + "content": { + "body": "* reply", + "msgtype": "m.text", + "m.new_content": { + "body": "reply", + "msgtype": "m.text", + }, + "m.relates_to": { + "rel_type": "m.replace", + "event_id": "$original_reply_event" + } + } +} +``` \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/guest_access.md b/locales/zh-Hans/client-server-api/modules/guest_access.md new file mode 100644 index 00000000..c74fae8d --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/guest_access.md @@ -0,0 +1,67 @@ +### 客户端访客访问 + +有时,客户端无需在主服务器上完整注册账户或加入房间即可与房间进行交互是更为理想的。本模块规定了此类客户端应如何与服务器交互,以便以访客身份参与房间。 + +访客用户通过使用普通的[注册接口](#post_matrixclientv3register)从主服务器获取访问令牌,将 `kind` 参数指定为 `guest`。随后,他们可以像其他用户一样与客户端-服务器 API 进行交互,但如客户端行为子章节所述,仅能访问 API 的子集。主服务器可以选择是否允许本地用户的访客访问,但并不了解其他主服务器上的用户是否为访客。 + +访客用户也可以通过正常的 `register` 流程升级其账户,需额外指定一个 POST 参数 `guest_access_token`,其值为访客令牌。同时,他们还需指定 `username` 参数(即用户名本地部分),该参数在其他情况下为可选项。 + +本模块并未完全考虑联合互通(Federation);它依赖于单个主服务器正确遵守本模块设定的规则,而不是允许所有主服务器相互强制执行这些规则。 + +#### 事件 + +{{% event event="m.room.guest_access" %}} + +#### 客户端行为 + +访客账户允许通过以下 API 端点获取事件及相关媒体资源: + +* [GET /rooms/{roomId}/state](#get_matrixclientv3roomsroomidstate) +* [GET /rooms/{roomId}/context/{eventId}](#get_matrixclientv3roomsroomidcontexteventid) +* [GET /rooms/{roomId}/event/{eventId}](#get_matrixclientv3roomsroomideventeventid) +* [GET /rooms/{roomId}/state/{eventType}/{stateKey}](#get_matrixclientv3roomsroomidstateeventtypestatekey) +* [GET /rooms/{roomId}/messages](#get_matrixclientv3roomsroomidmessages) +* {{% added-in v="1.1" %}} [GET /rooms/{roomId}/members](#get_matrixclientv3roomsroomidmembers) +* [GET /rooms/{roomId}/initialSync](#get_matrixclientv3roomsroomidinitialsync) +* [GET /sync](#get_matrixclientv3sync) +* [GET /events](#get_matrixclientv3events) 用于房间预览。 +* {{% added-in v="1.12" %}} [GET /media/download/{serverName}/{mediaId}](#get_matrixclientv1mediadownloadservernamemediaid) +* {{% added-in v="1.12" %}} [GET /media/download/{serverName}/{mediaId}/{fileName}](#get_matrixclientv1mediadownloadservernamemediaidfilename) +* {{% added-in v="1.12" %}} [GET /media/thumbnail/{serverName}/{mediaId}](#get_matrixclientv1mediathumbnailservernamemediaid) + +访客账户允许通过以下 API 端点发送事件: + +* [POST /rooms/{roomId}/join](#post_matrixclientv3roomsroomidjoin) +* [POST /rooms/{roomId}/leave](#post_matrixclientv3roomsroomidleave) +* [PUT /rooms/{roomId}/send/{eventType}/{txnId}](#put_matrixclientv3roomsroomidsendeventtypetxnid) + + * {{% changed-in v="1.2" %}} 访客现在可以发送*任何*类型的事件,而不仅限于 `m.room.message` 事件。 + +* {{% added-in v="1.2" %}} [PUT /rooms/{roomId}/state/{eventType}/{stateKey}](#put_matrixclientv3roomsroomidstateeventtypestatekey) +* [PUT /sendToDevice/{eventType}/{txnId}](#put_matrixclientv3sendtodeviceeventtypetxnid) + +访客账户允许通过以下 API 端点维护其自身账户: + +* [PUT /profile/{userId}/displayname](#put_matrixclientv3profileuseriddisplayname) +* [GET /devices](#get_matrixclientv3devices) +* [GET /devices/{deviceId}](#get_matrixclientv3devicesdeviceid) +* [PUT /devices/{deviceId}](#put_matrixclientv3devicesdeviceid) +* {{% added-in v="1.2" %}} [GET /account/whoami](#get_matrixclientv3accountwhoami) + +访客账户允许通过以下 API 端点进行端到端加密操作: + +* [POST /keys/upload](#post_matrixclientv3keysupload) +* [POST /keys/query](#post_matrixclientv3keysquery) +* [POST /keys/claim](#post_matrixclientv3keysclaim) + +#### 服务器行为 + +服务器**必须**仅在房间内存在 `m.room.guest_access` 状态事件且其 `guest_access` 值为 `can_join` 时允许访客用户加入房间。如果 `m.room.guest_access` 事件被修改为不再允许访客加入,服务器**必须**将这些访客用户的 `m.room.member` 状态设置为 `leave`。 + +#### 安全性考量 + +每个主服务器自行管理其访客账户,身份是否为访客账户的信息不会在服务器之间传递。因此,参与房间的任何服务器都被信任能够正确执行本节列出的权限规定。 + +主服务器可以考虑在访客注册时启用如验证码等保护措施,以防止垃圾信息、拒绝服务(DoS)等攻击。 + +主服务器可能会对访客账户采取更严格的速率限制,尤其是针对发送状态事件的操作。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/history_visibility.md b/locales/zh-Hans/client-server-api/modules/history_visibility.md new file mode 100644 index 00000000..f3b9bde0 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/history_visibility.md @@ -0,0 +1,42 @@ +### 房间历史可见性 + +该模块增加了对控制房间中过往事件可见性的支持。 + +除 `world_readable` 外,在所有情况下,用户都必须先加入房间才能查看该房间内的事件。一旦用户加入房间,他们将能访问该房间中某个事件子集。该子集如何选择由下文描述的 `m.room.history_visibility` 事件控制。用户离开房间后,仍可查看离开前被允许查看的事件,但无法查看离开后收到的事件。 + +`m.room.history_visibility` 事件有四个选项: + +- `world_readable` - 只要此项为 `m.room.history_visibility` 的值,任何参与的服务器都可以与任何人共享所有事件,无论其是否曾加入该房间。 +- `shared` - 以前的事件始终对新加入的成员可见。即使用户不在房间内时发送的事件,房间内的所有事件也都可访问。 +- `invited` - 新加入成员仅能访问自被邀请起的事件。当成员的状态变为非 `invite` 或 `join` 时,事件将不再可访问。 +- `joined` - 新加入成员仅能访问自加入该房间起的事件。当成员的状态变为非 `join` 时,事件将不再可访问。 + +{{% boxes/warning %}} +这些选项应用于事件*发送*时。判断依据是事件被添加到 DAG 时 `m.room.history_visibility` 的状态。这意味着,若当时的设置更为严格,客户端不能事后选择向新用户显示或隐藏历史记录。 +{{% /boxes/warning %}} + +#### 事件 + +{{% event event="m.room.history_visibility" %}} + +#### 客户端行为 + +若历史可见性设置为 `world_readable`,客户端可提示用户,非房间成员也可能读取事件内容。 + +#### 服务器行为 + +默认情况下,如果未设置 `history_visibility`,或其值无效,则视为 `shared`。关于用户能否查看某个事件,需依据*该事件发生时*房间的状态判定。 + +1. 如果 `history_visibility` 被设置为 `world_readable`,允许查看。 +2. 如果用户的 `membership` 为 `join`,允许查看。 +3. 如果 `history_visibility` 为 `shared`,且用户在事件发送后曾加入过房间,允许查看。 +4. 如果用户的 `membership` 为 `invite`,且 `history_visibility` 被设置为 `invited`,允许查看。 +5. 否则,拒绝访问。 + +针对 `m.room.history_visibility` 事件本身,如果事件*之前或之后*的 `history_visibility` 允许用户可见,则应允许该用户查看。例如,即使用户不是房间成员,也应可以看到将 `history_visibility` 从 `world_readable` 更改为 `joined` 或从 `joined` 更改为 `world_readable` 的 `m.room.history_visibility` 事件。 + +同样,对于用户自身的 `m.room.member` 事件,如果*事件前后*的 `membership` 有任一允许用户查看,则应允许该用户查看该事件。例如,用户始终可以看到将其 `membership` 设为 `join` 的事件,或将其从 `join` 更改为其他值的事件,即使 `history_visibility` 为 `joined`。 + +#### 安全注意事项 + +出于兼容性考虑,`history_visibility` 默认值为 `shared`。客户端需注意,若未设置该事件,则其房间历史对所有成员均可见。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/ignore_users.md b/locales/zh-Hans/client-server-api/modules/ignore_users.md new file mode 100644 index 00000000..94711410 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/ignore_users.md @@ -0,0 +1,25 @@ +### 忽略用户 + +在通过 Matrix 进行通信时,您可能希望出于某些原因忽略特定用户。本模块定义了客户端和服务器如何实现对用户的忽略。 + +#### 事件 + +{{% event event="m.ignored_user_list" %}} + +#### 客户端行为 + +若要忽略(实质上是屏蔽)某个用户,客户端应将目标用户添加至其账户数据中的 `m.ignored_user_list` 事件,使用 [`/user//account_data/`](#put_matrixclientv3useruseridaccount_datatype) 完成操作。用户被忽略后,客户端将不再收到该用户发送的事件,状态事件除外。客户端应选择隐藏被新忽略用户之前发送的内容,或执行一次不带历史 token 的新 [`/sync`](#get_matrixclientv3sync)。 + +被忽略用户对新房间的邀请将不会发送给客户端。服务器也可以选择代表客户端拒绝该邀请。 + +即使用户被忽略,状态事件仍然会发送给客户端。这是为了确保某些部分(如房间名)不会因为用户被忽略而在客户端表现出不同。 + +要将某个用户从忽略列表中移除,只需从账户数据事件中移除该用户。服务器将恢复发送此前被忽略用户的事件,但不应发送用户被忽略期间错过的事件。若需接收到被忽略期间发送的事件,客户端应执行一次全新同步。客户端还可取消对之前因忽略该用户而隐藏的事件的隐藏。 + +#### 服务器行为 + +在 `m.ignored_user_list` 更新后,所有客户端的同步 API 应立即开始忽略(或取消忽略)相关用户。客户端负责确定是隐藏已发送的事件,还是开启新的同步流。 + +服务器仍需向客户端发送被忽略用户发送的状态事件。 + +服务器不得将被忽略用户发起的房间邀请发送给客户端。服务器也可以选择拒绝该邀请。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/index.md b/locales/zh-Hans/client-server-api/modules/index.md new file mode 100644 index 00000000..290e33c8 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/index.md @@ -0,0 +1,8 @@ +--- +headless: true +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + diff --git a/locales/zh-Hans/client-server-api/modules/instant_messaging.md b/locales/zh-Hans/client-server-api/modules/instant_messaging.md new file mode 100644 index 00000000..55053a86 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/instant_messaging.md @@ -0,0 +1,237 @@ +### 即时消息 + +该模块增加了向房间发送易于理解的信息的支持,同时也支持为房间本身关联可读性强的信息,如房间名称和话题。 + +#### 事件 + +{{% event event="m.room.message" desired_example_name="m.room.message$m.text" %}} + +{{% event event="m.room.name" %}} + +{{% event event="m.room.topic" %}} + +{{% event event="m.room.avatar" %}} + +{{% event event="m.room.pinned_events" %}} + +##### m.room.message 消息类型(msgtype) + +每个 [m.room.message](#mroommessage) 必须包含一个 `msgtype` 键,用于标识发送消息的类型。不同类型的消息有各自必须和可选的键,具体如下。如果客户端无法显示给定的 `msgtype`,那么应当显示备用的纯文本 `body` 字段。 + +某些消息类型支持事件内容中的 HTML,客户端应优先显示可用的 HTML。目前,`m.text`、`m.emote`、`m.notice`、`m.image`、`m.file`、`m.audio`、`m.video` 和 `m.key.verification.request` 支持额外的 `format` 参数 `org.matrix.custom.html`。当提供该字段时,必须同时提供携带 HTML 的 `formatted_body`。HTML 的纯文本版本则应存于 `body` 字段。 + +{{% boxes/note %}} +{{% changed-in v="1.10" %}} +在以往的规范版本中,`format` 和 `formatted` 字段仅限于 `m.text`、`m.emote`、`m.notice` 以及 `m.key.verification.request`。现在该列表扩展至 `m.image`、`m.file`、`m.audio`、`m.video` 以支持[媒体标题](#media-captions)。 +{{% /boxes/note %}} + +为防止跨站脚本攻击(XSS)、HTML 注入及类似攻击,客户端应限制渲染的 HTML 范围。强烈建议仅允许以下 HTML 标签,其余标签应拒绝使用与渲染:`del`、`h1`、`h2`、`h3`、`h4`、`h5`、`h6`、`blockquote`、`p`、`a`、`ul`、`ol`、`sup`、`sub`、`li`、`b`、`i`、`u`、`strong`、`em`、`s`、`code`、`hr`、`br`、`div`、`table`、`thead`、`tbody`、`tr`、`th`、`td`、`caption`、`pre`、`span`、`img`、`details`、`summary`。 + +{{% boxes/note %}} +{{% added-in v="1.10" %}} +当 HTML 功能在 [WHATWG HTML Living Standard](https://html.spec.whatwg.org/multipage/) 标准中被弃用时,可以无需提交 [规范变更提案](/proposals)而弃用并用其现代等价替换之。 +{{% /boxes/note %}} + +{{% boxes/note %}} +{{% changed-in v="1.10" %}} +在以往规范中,建议使用 `font` 标签及其 `data-mx-bg-color`、`data-mx-color` 和 `color` 属性。该标签现已弃用,新的消息推荐使用带有 `data-mx-bg-color` 和 `data-mx-color` 属性的 `span` 标签替代。 +{{% /boxes/note %}} + +上述标签的所有属性均不应被允许,因为部分属性可能带来其他干扰性风险,比如添加 `onclick` 事件或设置过大的文本。客户端仅应允许下表中为各标签列出的属性。其中,`data-mx-bg-color` 和 `data-mx-color` 为列表项时,客户端应将其值(即 `#` 开头的 6 位十六进制颜色代码)转换为该标签相应的 CSS/属性。 + +| 标签 | 允许的属性 | +|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `span` | `data-mx-bg-color`、`data-mx-color`、`data-mx-spoiler`(参见[剧透消息](#spoiler-messages))、`data-mx-maths`(参见[数学消息](#mathematical-messages)) | +| `a` | `target`、`href`(前提是值不是相对路径,且 scheme 为 `https`、`http`、`ftp`、`mailto`、`magnet` 中之一) | +| `img` | `width`、`height`、`alt`、`title`、`src`(前提是来源为 [Matrix 内容 (`mxc://`) URI](#matrix-content-mxc-uris)) | +| `ol` | `start` | +| `code` | `class`(仅允许以 `language-` 开头的 class,以便语法高亮) | +| `div` | `data-mx-maths`(参见[数学消息](#mathematical-messages)) | + +除此之外,Web 客户端应确保*所有* `a` 标签获得 `rel="noopener"` 属性,以防目标页面获取当前客户端标签页/窗口的引用。 + +标签嵌套不得超过 100 层。客户端仅应支持其能够渲染的子集标签,对无法渲染的标签采用其他表现方式显示。例如,若客户端无法正确渲染表格,可回退为制表符分隔文本。 + +除了不渲染不安全的 HTML 外,客户端也不应在事件中生成不安全的 HTML。客户端同样不应生成不必要的 HTML,比如由于富文本编辑导致的多余的段落标签。事件中的 HTML 应为有效 HTML,例如有适当的闭合标签、正确的属性(结合本文档自定义说明),且整体结构合法。 + +{{% boxes/note %}} +{{% changed-in v="1.13" %}} +在更早的规范版本中,[富回复](#rich-replies) 可以使用特殊标签 `mx-reply`。现在不再需要这样做。客户端应去除该标签及其内容。详情请参见“富回复”章节。 +{{% /boxes/note %}} + +{{% boxes/note %}} +未来的规范会支持更强大且可扩展的消息格式化选项,例如提案 [MSC1767](https://github.com/matrix-org/matrix-spec-proposals/pull/1767)。 +{{% /boxes/note %}} + +{{% msgtypes %}} + +#### 客户端行为 + +客户端应验证收到事件的结构,确保所需字段存在且类型正确。对于格式错误的事件,可以选择丢弃或向用户显示占位提示消息。被修订(redacted)的 `m.room.message` 事件必须从客户端删除,可以用占位文本(如“[REDACTED]”)替换,或直接从消息视图移除。 + +带有附件的事件(如 `m.image`、`m.file`)应使用[内容仓库模块](#content-repository)上传(如可用)。所得的 `mxc://` URI 可用于 `url` 字段。 + +客户端可通过 `info.thumbnail_url` 字段为附件带上客户端生成的缩略图。该缩略图也应为 `mxc://` URI。呈现附带附件的事件时,客户端可直接使用缩略图,或者通过[内容仓库模块](#content-repository)请求 homeserver 基于原始附件生成缩略图。 + +##### 发送消息时的推荐做法 + +在发送失败时,客户端应使用指数退避算法重试请求,重试时间 T 为一段时间,建议不超过 5 分钟。超时后客户端应停止重试,并将消息标记为“未发送”。用户应能够手动重新发送未发送消息。 + +用户可能会一次输入并快速发送多条消息。客户端应保持用户发送消息的顺序,这意味着应等待上一请求响应后再发送下一个请求。这可能导致“队头阻塞”。为减轻此影响,应按房间分别使用队列而非全局队列,因为顺序仅在单一房间内有意义,房间间无需严格顺序。 + +##### 本地回显(Local Echo) + +用户点击“发送”按钮时,消息应立即在消息视图中显示,哪怕消息正在发送中。这一过程称为“本地回显”。客户端应实现本地消息回显。客户端可采用不同展示方式显示尚未被服务器处理的消息。当服务器响应后应移除该特殊格式。 + +客户端需要能将其发送的消息和从事件流中收到的同一消息进行匹配。从事件流收到的同一消息的回显称为“远程回显”。本地回显和远程回显都要能被识别为相同消息,以防止重复显示。理想情况下,这一过程对用户透明:UI 从本地回显切换为远程回显时不会闪烁。通过使用用于发送事件的事务 ID,可减少切换时的闪烁。事务 ID 会作为收到事件时 `unsigned` 数据中的 `transaction_id` 字段返回。 + +如果客户端无法使用事务 ID,那么当远程回显在消息发送请求完成*之前*到达事件流时,很可能会出现闪烁。在这种情况下,事件在消息发送请求完成、客户端获得事件 ID 之前就到了,导致无法将其识别为远程回显。这样客户端在一段时间内(取决于服务器响应速度)会同时显示两条消息。请求完成后,客户端可通过查找重复事件 ID 移除多余事件。 + +##### 计算用户的显示名 + +客户端可能希望在成员列表或消息发送时展示房间成员的可读型显示名。然而,不同成员可能出现显示名冲突。显示名在展示给用户前必须唯一化处理,以防止冒充其他用户。 + +为确保客户端间一致处理,推荐使用如下算法为指定用户计算唯一显示名: + +1. 检查相关用户的 `m.room.member` 状态事件。 +2. 若该状态事件无 `displayname` 字段或该字段为 `null`,则用其原始用户 ID 作为显示名。否则: +3. 若 `m.room.member` 事件中的 `displayname` 在房间中所有 `membership: join` 或 `membership: invite` 成员里是唯一的,则用该 `displayname` 作为可见显示名。否则: +4. 若 `displayname` 不唯一,应结合用户 ID 做唯一化处理,例如“显示名 (@id:homeserver.org)”。 + +开发者在实现该算法时需注意: + +- 一名成员的显示名有可能因其他成员状态变化而变化。例如,若 `@user1:matrix.org` 在房间中显示为 `Alice`,当 `@user2:example.com` 也以 `Alice` 加入该房间时,两名用户都必须使用唯一化后的显示名。相反,若其中一名用户更改显示名致不再冲突,两者又可拥有自己原先的显示名。客户端需注意并确保对受影响成员正确重命名。 +- 房间显示名也可能因成员名单变化而受影响。因为房间名有时基于用户显示名派生(见[计算房间显示名](#calculating-the-display-name-for-a-room))。 +- 若全量遍历成员列表以查重显示名,则会导致 O(N^2) 复杂度,该实现对房间成员众多时很低效。建议客户端维护一个从 `displayname` 到使用该名成员列表的哈希表,以高效判断是否需唯一化。 + +##### 随消息同步展示成员信息 + +客户端可能希望显示发送消息成员的显示名与头像 URL。可通过检查该用户 ID 的 `m.room.member` 状态事件获取(参见[计算用户显示名](#calculating-the-display-name-for-a-user))。 + +在用户分页浏览历史记录时,客户端可能希望展示成员的**历史**显示名与头像 URL。由于分页时会返回旧的 `m.room.member` 事件,因此可以实现该功能。一般做法是同时维护两组房间状态:旧状态和当前状态。随着新事件到达和/或用户回溯浏览,这两组状态会逐渐分化:新事件更新当前状态,分页事件更新旧状态。当分页事件顺序处理时,旧状态即为*消息发送时*的房间状态。历史显示名和头像 URL 可由此设置。 + +##### 计算房间显示名 + +客户端可能希望显示房间的可读型名称。命名方式有多种选择。为保持不同客户端之间房间命名一致,推荐按照如下算法选择房间名: + +1. 若房间具有 [m.room.name](#mroomname) 状态事件且其 `name` 字段非空,则采用该字段给出的名称。 +2. 若房间有 [m.room.canonical_alias](#mroomcanonical_alias) 状态事件且该 `alias` 字段有效,则使用之。请注意,客户端在计算房间名时应避免使用 `alt_aliases`。 +3. 如果以上条件都不满足,应根据房间成员组合房间名。客户端应考虑除当前用户外的 [m.room.member](#mroommember) 事件(定义如下)。 + 1. 若房间 `m.heroes` 数量大于等于 `m.joined_member_count + m.invited_member_count - 1`,则可利用英雄成员的事件计算用户显示名([必要时唯一化](#calculating-the-display-name-for-a-user))并拼接。比如,客户端可选择展示“Alice, Bob,以及 Charlie (@charlie:example.org)”作为房间名。客户端可根据用户体验选择限制用于生成房间名的成员数量。 + 2. 若英雄成员数少于 `m.joined_member_count + m.invited_member_count - 1`,且总成员数大于 1,则应用英雄成员计算显示名([必要时唯一化](#calculating-the-display-name-for-a-user)),拼接后加上剩余成员人数。例如,“Alice、Bob 及其他 1234 位成员”。 + 3. 若成员总数(加入和被邀请之和)小于等于 1(表明该成员为唯一成员),则依据上述规则显示房间为空。例如,“空房间(曾为 Alice)”、“空房间(曾为 Alice 及 1234 位成员)”或无成员时显示“空房间”。 + +客户端用 `m.heroes` 计算房间名时应对各国语言进行国际化处理。生成房间名时,客户端应尽量使用不少于 5 名英雄成员,但可根据实际需求调整数量以配合用户体验。 + +##### 剧透消息 + +{{% added-in v="1.1" %}} + +消息中的部分内容可通过剧透形式在视觉上对用户隐藏。这不影响服务器对事件内容的存储,仅是在视觉上提示用户相关内容可能会暴露重要信息,导致“剧透”。 + +发送剧透消息时,客户端必须使用 `formatted_body`,即上文描述的 `org.matrix.custom.html` 格式。因此,支持剧透的任意 `msgtype` 都须支持该格式。 + +剧透内容包裹在 `span` 标签中,原因(可选)放在 `data-mx-spoiler` 属性里。若无原因,属性值可留空或未定义,但该属性不能省略。 + +一个剧透消息示例: + +```json +{ + "msgtype": "m.text", + "format": "org.matrix.custom.html", + "body": "Alice [剧透](mxc://example.org/abc123) 在电影里。", + "formatted_body": "Alice 最终幸福地生活下去 在电影里。" +} +``` + +若提供原因,则如下: + +```json +{ + "msgtype": "m.text", + "format": "org.matrix.custom.html", + "body": "Alice [健康剧透](mxc://example.org/abc123) 在电影里。", + "formatted_body": "Alice 最终幸福地生活下去 在电影里。" +} +``` + +发送剧透时,客户端应如上示例在 `body` 字段提供包含原因的备用内容。备用 `body` 字段不应包含剧透正文,因为 `body` 可能被文本类客户端或通知直接显示。为防止剧透内容被泄露,强烈推荐客户端首先将剧透正文上传至媒体仓库,然后以 markdown 链接形式引用对应 `mxc://` URI,如上述示例。 + +客户端应区别渲染剧透内容,并以某种显式交互提示。例如,可将剧透文本模糊化,提示用户点击后显示。 + +##### 媒体标题 + +{{% added-in v="1.10" %}} + +媒体消息(包括 `m.image`、`m.file`、`m.audio`、`m.video`)可包含题注,以补充说明媒体内容。 + +发送标题时,客户端必须同时使用 `filename` 和 `body` 字段,`formatted_body` 及 `org.matrix.custom.html` 格式为可选。 + +如存在 `filename` 字段,且其与 `body` 不同,则将 `body` 视为题注,否则 `body` 视为文件名。`format` 和 `formatted_body` 仅用于题注。 + +{{% boxes/note %}} +在旧规范中,`body` 字段通常用于上传文件名,而 `filename` 字段仅出现在 `m.file` 上且用法一致。 +{{% /boxes/note %}} + +媒体消息附带题注示例: + +```json +{ + "msgtype": "m.image", + "url": "mxc://example.org/abc123", + "filename": "dog.jpg", + "body": "这是一张~~猫咪~~照片 :3", + "format": "org.matrix.custom.html", + "formatted_body": "这是一张 猫咪 照片 :3", + "info": { + "w": 479, + "h": 640, + "mimetype": "image/jpeg", + "size": 27253 + }, + "m.mentions": {} +} +``` + +客户端必须与媒体一起渲染标题,并应优先渲染其格式化形式。 + +##### 数学消息 + +{{% added-in v="1.11" %}} + +用户可能希望在消息中发送数学符号或公式。 + +发送数学公式时,客户端必须使用 `formatted_body`,即采用上述 `org.matrix.custom.html` 格式。任何可用该格式的 `msgtype` 均可支持数学形式。 + +数学内容根据是否需要行内显示,使用 `span` 或 `div` 标签。用 `data-mx-maths` 属性书写 [LaTeX](https://www.latex-project.org/) 格式的公式。 + +标签内容为不能渲染 LaTeX 的客户端备用显示。可用图片、HTML 近似表示或原始 LaTeX 源文本作为备用。若用图片作为备用,发送方应注意接收端可能背景色不同所带来的显示问题。`body` 字段应包含文本表示的公式。 + +数学消息示例: + +```json +{ + "msgtype": "m.text", + "format": "org.matrix.custom.html", + "body": "这是一个方程:sin(x)=a/b。", + "formatted_body": "这是一个方程:sin(x)=a/b" +} +``` + +LaTeX 语法定义不完整且有多种扩展,若客户端遇到无法渲染的语法,应优先显示备用内容。但客户端最低应支持[LaTeX2e](https://www.latex-project.org/) 的数学命令及 [TeX](https://tug.org/) 数学命令(部分命令因安全风险可例外)。 + +{{% boxes/warning %}} +总的说来,LaTeX 给客户端带来了安全处理压力。部分命令(如[可创建宏的命令](https://katex.org/docs/supported#macros))具潜在风险。客户端应拒绝处理此类命令,或确保安全处理(如限制递归)。客户端应以白名单方式只允许已知安全命令,而非黑名单拒绝已知不安全命令。 + +因此,客户端在未安全隔离环境下,不应直接调用 LaTeX 编译器渲染数学表达式,因为相关可执行文件并未设计处理不可信输入。有些 LaTeX 渲染库适合,仅允许部分 LaTeX 并限制递归深度。 +{{% /boxes/warning %}} + +#### 服务器行为 + +HomeServer 在收到不包含 `msgtype` 键,或无文本型 `body` 键的 `m.room.message` 事件时,应拒绝请求并返回 400 HTTP 状态码。 + +#### 安全注意事项 + +使用本模块发送的消息不会加密,端到端加密(E2E)仍在开发中(详见 [E2E 模块](#end-to-end-encryption))。 + +客户端应对**所有显示的键**进行不安全 HTML 的过滤,以防止跨站脚本(XSS)攻击。这包括房间名称和话题。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/mentions.md b/locales/zh-Hans/client-server-api/modules/mentions.md new file mode 100644 index 00000000..29a2dfae --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/mentions.md @@ -0,0 +1,56 @@ +### 用户和房间提及 + +{{% changed-in v="1.7" %}} + +本模块允许用户在房间事件中“提及”其他用户和房间。 这主要用于指示收件人应接收到关于该事件的通知。 通过在事件的 `m.mentions` 内容属性中包含元数据以引用被提及的实体来实现这一点。 + +`m.mentions` 的定义如下: + +{{% definition path="api/client-server/definitions/m.mentions" %}} + +一个事件的内容示例如下: + +```json +{ + "body": "Hello Alice!", + "msgtype": "m.text", + "format": "org.matrix.custom.html", + "formatted_body": "Hello Alice!", + "m.mentions": { + "user_ids": ["@alice:example.org"] + } +} +``` + +此外,请参阅 [`.m.rule.is_user_mention`](#_m_rule_is_user_mention) 和 +[`.m.rule.is_room_mention`](#_m_rule_is_room_mention) 推送规则。 +用户不应将自己的 Matrix ID 添加到 `m.mentions` 属性中,因为发出的消息无法对本人进行通知。 + +{{% boxes/warning %}} +如果加密事件的载荷中包含 `m.mentions`,应像普通内容一样进行加密。为正确处理加密房间中的提及,必须首先对事件进行解密。参见[接收通知](#receiving-notifications)。 +{{% /boxes/warning %}} + +请注意,为了向后兼容,像 [`.m.rule.contains_display_name`](#_m_rule_contains_display_name)、 +[`.m.rule.contains_user_name`](#_m_rule_contains_user_name) 和 +[`.m.rule.roomnotif`](#_m_rule_roomnotif) 这样的推送规则,仍将在事件的 `body` 包含用户显示名或 ID 时匹配。为避免无意的通知,**建议客户端在每个事件中都包含一个 `m.mentions` 属性**。(若无提及内容,可为一个空对象。) + +{{% boxes/rationale %}} +在以往的规范版本中,用户提及是通过在事件明文 `body` 中包含用户的显示名或其 Matrix ID localpart 实现的,而房间提及则是包含字符串“@room”。这种方式容易导致混乱和 bug。 +{{% /boxes/rationale %}} + +#### 客户端行为 + +虽然可以悄悄地提及用户,但推荐在 [m.room.message](#mroommessage) 事件的 HTML 正文中包含一个 [Matrix URI](/appendices/#uris)。这仅适用于 `msgtype` 为 `m.text`、`m.emote` 或 `m.notice` 的 [m.room.message](#mroommessage) 事件。事件的 `format` 必须为 `org.matrix.custom.html`,因此需要有 `formatted_body`。 + +客户端在向即将发送的事件中添加用于提及的 `Matrix URI` 时,应遵循以下准则: + +- 当链接到用户时,在锚文本中显示用户可能存在歧义的显示名。若用户无显示名,则使用用户的 ID。 +- 当链接到房间时,使用该房间的规范别名(canonical alias)。若房间无规范别名,则优先使用房间上列出的别名之一。若找不到任何别名,则退回到房间 ID。在所有情况下,锚文本应为所链接的别名或房间 ID。 + +锚文本部分应在事件的 `body` 中用于原本表示该链接的位置,如上例所示。 + +客户端应将提及与其他元素区分开来。例如,可以通过改变提及的背景色以突出其与普通链接的不同。 + +如果当前用户在消息中被提及,客户端应将此提及以不同于其他提及的方式显示,例如使用红色背景以提醒用户本人被提及。请注意,用户可能会被提及但事件中未包含其 `Matrix URI`。 + +点击提及时,应导航到相应的用户或房间信息。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/moderation_policies.md b/locales/zh-Hans/client-server-api/modules/moderation_policies.md new file mode 100644 index 00000000..1c8b48a2 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/moderation_policies.md @@ -0,0 +1,56 @@ +### 内容审核策略列表 + +Matrix 作为一个开放网络,任何人都可以参与,因而存在着种类极为丰富的内容。让用户有权选择希望看到的内容以及想要屏蔽的内容显得尤为重要。进一步来说,房间管理员和服务器管理员同样应当能够选择他们不希望在其房间和服务器中托管的内容。 + +协议对此持中立立场:它不应为任何特定实体判断哪些内容为不当内容,而应赋权这些实体自行做出决策。因此,这里描述了一套通用框架,用于传递“内容审核策略列表”或“内容审核策略房间”。需要注意的是,本模块仅描述数据结构,而不涉及如何解读它们:决定过滤内容的实体最适合根据自身需求解读这些规则。 + +内容审核策略列表以房间状态事件的形式存储。对于房间的配置没有任何限制(可以是公开、私有、加密等)。 + +目前有三类实体可能会被规则影响:`user`(用户)、`server`(服务器)和 `room`(房间)。三者均以 `m.policy.rule.` 状态事件进行描述。策略规则的 `state_key` 是由规则发送者自定义的任意字符串。 + +规则包含关于为何制定此规则的建议及原因。`reason` 是描述 `recommendation` 的、供人阅读的字符串。目前,仅定义了一个建议类型——`m.ban`。 + +#### `m.ban` 建议 + +当使用此建议时,应尽可能禁止规则中所影响的实体参与活动。其执行方式特意作为实现细节留给开发者,以避免协议对如何解读策略列表做出强制规定。以下是一个简单实现建议: + +- 针对 `user`(用户)规则... + - 作用于用户:应将该用户加入订阅者的忽略列表。 + - 作用于房间:应禁止该用户进入该房间(可见时或立即)。 + - 作用于服务器:不应允许该用户向服务器上的其他用户发送邀请。 +- 针对 `room`(房间)规则... + - 作用于用户:该用户应离开该房间,并不得重新加入(参见 [MSC2270](https://github.com/matrix-org/matrix-spec-proposals/pull/2270) 风格的忽略策略)。 + - 作用于房间:无操作,因为房间无法对自己执行禁令。 + - 作用于服务器:服务器应阻止用户加入该房间,并阻止他们收到该房间的邀请。 +- 针对 `server`(服务器)规则... + - 作用于用户:不应让该用户从该服务器接收事件或邀请。 + - 作用于房间:应将该服务器添加到 ACL 的拒绝服务器列表中。 + - 作用于服务器:订阅者应尽量避免与该服务器进行联邦交互,通过阻止来自该服务器的邀请,不发送除非必要的流量(不发送外部邀请)来实现。 + +#### 订阅策略列表 + +这一部分有意留作实现细节。对于使用客户端-服务器 API 的实现而言,这只需像加入或窥视房间一样简单。但加入或窥视并非必需:实现可以通过轮询更新或采用其他方式接收策略规则的更新。 + +#### 事件 + +状态事件中描述的 `entity` 采用 [glob 风格模式](/appendices#glob-style-matching)进行解释。注意,针对房间的规则既可以描述房间 ID 也可以描述房间别名——如有需要,由订阅者负责将别名解析为房间 ID。 + +{{% event event="m.policy.rule.user" %}} + +{{% event event="m.policy.rule.room" %}} + +{{% event event="m.policy.rule.server" %}} + +#### 客户端行为 + +如上所述,客户端行为未做强制定义。 + +#### 服务器行为 + +本模块对服务器没有提出额外要求。 + +#### 安全考虑 + +本模块可用于构建一套共享黑名单系统,如果部署不当,可能导致现有社区出现分化。对所有社群而言,这未必是合适的解决方案。 + +具体实现中,依据如何处理订阅关系,用户ID 有可能与策略列表关联进而暴露该用户的立场。例如,若客户端实现让用户加入策略房间,则会向策略房间的观察者显示该用户的 ID。未来,[MSC1228](https://github.com/matrix-org/matrix-spec-proposals/pulls/1228) 和 [MSC1777](https://github.com/matrix-org/matrix-spec-proposals/pulls/1777)(或相似手段)可有助于缓解这一问题。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/openid.md b/locales/zh-Hans/client-server-api/modules/openid.md new file mode 100644 index 00000000..1da25295 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/openid.md @@ -0,0 +1,5 @@ +### OpenID + +该模块允许用户通过第三方服务验证其身份。第三方服务需要具备 Matrix 兼容性,即需要能够解析 Matrix 主服务器以便用用户的令牌交换身份信息。 + +{{% http-api spec="client-server" api="openid" %}} \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/presence.md b/locales/zh-Hans/client-server-api/modules/presence.md new file mode 100644 index 00000000..c402c5bd --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/presence.md @@ -0,0 +1,42 @@ +### 在线状态 + +每个用户都有在线状态信息的概念。该信息包含以下内容: + +- 用户当前是否在线 +- 用户最近一次活跃的时间(由服务器检测) +- 某客户端是否认为用户当前处于空闲状态 +- 关于用户当前状态的任意信息(例如“正在开会”) + +这些信息既包括设备级(`online`、`idle`、`last_active`),也包括用户级(status)数据,由用户的宿主服务器聚合后,通过 `m.presence` 事件传输。在线状态事件会发送给有房间成员关系的相关用户。 + +用户的在线状态通过 `presence` 键表示,该键枚举以下几种状态之一: + +- `online` :用户连接到事件流时的默认状态。 +- `unavailable` :此时用户不可达,例如用户处于空闲状态。 +- `offline` :用户未连接到事件流,或有意禁止发送其个人信息。 + +#### 事件 + +{{% event-group group_name="m.presence" %}} + +#### 客户端行为 + +客户端可以通过下述 HTTP API 手动设置/获取自身的在线状态。 + +{{% http-api spec="client-server" api="presence" %}} + +##### 距离上一次活跃时长 + +服务器会维护一次记录“最后一次检测到用户主动事件”的时间戳。主动事件可能是向房间发送消息,或将在线状态更改为 `online`。这个时间戳通过名为 `last_active_ago` 的键呈现,表示自上次主动事件以来的相对毫秒数。 + +为减少服务器向客户端发送的在线状态更新数量,当在线状态为 `online` 时,服务器可能会包含一个布尔字段 `currently_active`。如果该字段为 true,服务器将不会继续发送活跃时间的更新,直到向客户端发送的更新中 a) `currently_active` 变为 false,或 b) 状态变为非 `online`。在此期间,客户端应始终认为该用户处于活跃状态,而不考虑 `last_active_ago` 的具体值。 + +每当服务器向客户端推送在线状态事件时,最新的活跃时间必须是当前的。`currently_active` 机制仅用于服务器停止持续推送在线状态更新,而不应禁用活跃时间的追踪。因此,客户端可以通过显式请求某用户的在线状态来获取最新的活跃持续时长。 + +##### 空闲超时 + +如果用户的最后一次活跃时间超过了设定的阈值(比如 5 分钟),服务器会自动将用户状态设置为 `unavailable`。客户端也可以手动将用户状态设置为 `unavailable`。只要用户任意一个客户端有新的活动导致活跃时间刷新,服务器会自动将其在线状态设置为 `online`。 + +#### 安全性注意事项 + +在线状态信息会与所有目标用户的房间成员共享。在大型公共房间中,这种共享可能并不理想。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/push.md b/locales/zh-Hans/client-server-api/modules/push.md new file mode 100644 index 00000000..bdf856e0 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/push.md @@ -0,0 +1,916 @@ +### 推送通知 + +``` + +--------------------+ +-------------------+ + Matrix HTTP | | | | + Notification Protocol | 应用开发者 | | 设备厂商 | + | | | | + +-------------------+ | +----------------+ | | +---------------+ | + | | | | | | | | | | + | Matrix 主服务器 +-----> 推送网关(Gateway)+------> 推送供应商 | | + | | | | | | | | | | + +-^-----------------+ | +----------------+ | | +----+----------+ | + | | | | | | + Matrix | | | | | | + 客户端/服务器API + | | | | | + | | +--------------------+ +-------------------+ + | +--+-+ | + | | <-------------------------------------------+ + +---+ | + | | 供应商推送协议 + +----+ + 移动设备或客户端 +``` + +本模块增加了对推送通知的支持。主服务器会将事件的通知发送到用户配置的 HTTP 端点。用户也可以自定义多条规则,决定哪些事件会生成通知。这些规则全部存储并由用户的主服务器管理。这允许用户专属的推送设置在不同客户端应用之间复用。 + +上述图示显示了推送通知发送到手机时的流程,通知通过手机厂商(例如 Apple 的 APNS 或 Google 的 GCM)进行提交。具体流程如下: + +1. 客户端应用登录到主服务器。 +2. 客户端应用在其厂商的推送供应商处注册,并获得某种路由令牌。 +3. 移动应用通过客户端/服务器 API 添加一个“推送者(pusher)”,并提供为该应用配置的特定推送网关的 URL,同时提供从推送供应商获得的路由令牌。 +4. 主服务器使用提供的 URL 向推送网关发送 HTTP 请求。推送网关将该通知中继给推送供应商,并附带发送推送通知所需的路由令牌及相关私密凭证。 +5. 推送供应商将通知发送至设备。 + +本节相关术语定义如下: + +推送供应商(Push Provider) + +: 推送供应商是由设备厂商管理的服务,可以直接将通知发送到设备。例如 Google Cloud Messaging(GCM)和 Apple Push Notification Service(APNS)都是推送供应商的例子。 + +推送网关(Push Gateway) + +: 推送网关是接收主服务器 HTTP 事件通知并将其转发给其他协议(如 iOS 设备的 APNS 或 Android 设备的 GCM)的服务器。客户端在设置 Pusher 时,会告知主服务器该将通知发送至哪个推送网关。 + +推送者(Pusher) + +: Pusher 是主服务器上负责管理并发送 HTTP 通知给用户的工作进程。每个用户可以有多个 pusher,每组装置对应一个。 + +推送规则(Push Rule) + +: 推送规则是一条声明了在什么*条件*下事件会被发送到推送网关,以及通知应该如何呈现的规则。这些规则储存在用户的主服务器上。用户可通过客户端/服务器 API 手动配置、创建与查看这些规则。 + +推送规则集(Push Ruleset) + +: 推送规则集*根据某些标准限定某组规则的作用范围*。比如,某些规则只针对来自特定发信人的消息、特定聊天室、或作为默认规则。推送规则集包含了全部作用域与规则集合。 + +#### 推送规则 + +推送规则是一条声明了在什么*条件*下事件会被发送到推送网关,以及通知该如何呈现的规则。推送规则有多种“类型(kind)”,每条规则都有相应的优先级。每条推送规则必须包含 `kind` 和 `rule_id`。`rule_id` 是在该类型和作用域内部唯一的字符串:同种类型但属于不同设备的规则之间,`rule_id` 并不要求全局唯一。依据 `kind` 类型,规则可以具有额外的键。 + +不同的 `kind` 类型按如下顺序检查: + +1. **Override 规则 (`override`)。** + 最高优先级的规则,由用户配置作为覆盖项。 + +2. **内容专属规则 (`content`)。** + 针对匹配某些模式的消息配置行为。内容规则包含一个参数 —— `pattern`,提供待匹配的[glob 风格模式](/appendices#glob-style-matching)。 + 该匹配大小写不敏感,必须匹配消息内容的 `content.body` 属性中任何以单词边界起止的子串。单词边界指文本的起始或结尾,或者非 `[A-Z]`, `[a-z]`, `[0-9]`, `_` 集合中的任意字符。大小写不敏感的具体实现由主服务器定义。 + +3. **房间专属规则 (`room`)。** + 更改某个房间内所有消息的通知行为。房间规则的 `rule_id` 总为其作用房间的 ID。 + +4. **发信人专属规则 (`sender`)。** + 针对某个 Matrix 用户 ID 发出的消息配置通知行为。发信人规则的 `rule_id` 总为该用户的 Matrix ID。 + +5. **Underride 规则 (`underride`)。** + 与 `override` 规则作用相同,但其优先级低于 `content`、`room` 和 `sender` 规则。 + +同一 `kind` 的规则可以指定顺序优先级,用于确定在多条规则命中时选择哪一条。例如,规则 A 匹配“tea”,规则 B 匹配“time”,则消息 “It's time for tea” 会被两条规则匹配,随后按顺序决定实际生效的规则。只有优先级最高的规则的 `actions` 会被发送给推送网关。 + +每条规则可以启用或禁用。被禁用的规则永不匹配。如果没有任何规则匹配某事件,主服务器不得为该事件通知推送网关。主服务器也不得为用户自己发送的事件通知推送网关。 + +##### 动作(Actions) + +所有规则都有一个关联的 `actions` 动作列表。动作决定对于匹配的事件,通知是否被送达及如何送达。定义如下: + +`notify` + +: 为每个匹配事件产生推送通知。 + +`set_tweak` + +: 设置发送通知请求给推送网关时 `tweaks` 字典键中的一项。格式为字典对象,`set_tweak` 为要设置的调整项名,如果需要还可带有 `value` 指定其值。 + + 已定义以下调整项: + + `sound` + + : 字符串,表示此通知到达时播放的声音。`default` 表示播放默认提示音。设备也可根据实际选择如振动等其他告警方式。 + + `highlight` + + : 布尔值,是否应在界面中高亮展示这条消息。通常会以不同颜色/样式突出消息,或调整 UI 以特别提示发生消息的房间。如果给定了没有显式值的 `highlight` 调整项,其值视为 `true`。若未指定则为 `false`。 + + 调整项会透明地通过主服务器传递,客户端应用与推送网关可约定自定义调整项。例如,可指定在移动设备上如何闪烁通知灯。 + +无参数的动作用字符串表示,否则用以动作名为键、相关参数为其他键的字典表示,例如:`{ "set_tweak": "sound", "value": "default" }`。 + +###### 历史动作说明 + +早期 Matrix 规范包含 `dont_notify` 和 `coalesce` 动作。客户端和主服务器必须忽略这些动作,比如遇到时应从动作数组中剔除。因此,包含 `["dont_notify"]` 的规则应等效于动作数组为空的规则。 + +##### 条件(Conditions) + +`override` 和 `underride` 规则可以有“条件”列表。事件必须满足所有条件,该规则才会匹配。若规则无任何条件,则总是匹配。 + +无法识别的条件不得匹配任何事件,相当于禁用该规则。 + +`room`、`sender` 和 `content` 规则不以条件列表的方式定义,而是有预定义条件。房间和发信人规则中,`rule_id` 的内容决定其行为。 + +以下条件类型已定义: + +**`event_match`** + +对事件某属性用 glob 模式匹配。参数: + +- `key`:事件属性的[点分路径](/appendices#dot-separated-property-paths),如 `content.body`。 +- `pattern`:[glob 风格模式](/appendices#glob-style-matching)。 + +匹配大小写不敏感,必须匹配 `key` 指定属性的整个值(但 `content.body` 见下文)。大小写不敏感的实现由主服务器定义。 + +如事件中 `key` 指定属性完全不存在或不是字符串,即便 `pattern` 是 `*`,条件也不匹配。 + +{{% boxes/note %}} +例如,若 `key` 为 `content.topic`,`pattern` 为 `lunc?*`,其事件如下将会匹配: + +```json +{ + "content": { + "topic": "Lunch plans", + }, + "event_id": "$143273582443PhrSn:example.org", + "room_id": "!636q39766251:example.com", + "sender": "@example:example.org", + "state_key": "", + "type": "m.room.topic" +} +``` + +其它能匹配的 `topic` 值有: + + * `"LUNCH"`(大小写不敏感,`*` 可匹配零个字符) + +以下 `topic` 不匹配: + * `" lunch"`(前导空格) + * `"lunc"`(`?` 必须匹配一个字符) + * `null`(不是字符串) +{{% /boxes/note %}} + +特殊情况:若 `key` 为 `content.body`,`pattern` 必须匹配属性值任一单词边界起止的子串。单词边界指值的起止或非 `[A-Z]`、`[a-z]`、`[0-9]`、`_` 集合的字符。 + +{{% boxes/note %}} +例如,`key` 若为 `content.body`,`pattern` 为 `ex*ple`,则如下消息会匹配: + +```json +{ + "content": { + "body": "An example event." + }, + "event_id": "$143273976499sgjks:example.org", + "room_id": "!636q39766251:example.com", + "sender": "@example:example.org", + "type": "m.room.message" +} +``` + +其它匹配 `body` 值有: + + * `"exple"`(模式可匹配 body 起止) + * `"An exciting triple-whammy"`(模式可跨多单词,且 `-` 被视为分隔符) +{{% /boxes/note %}} + + +{{% boxes/warning %}} +注意,`state_key` 没有默认隐式条件。即,针对只匹配状态事件的推送规则,必须明确指定对 `state_key` 的条件。 + +例如,见下方默认规则 +[`.m.rule.tombstone`](#mruletombstone)。 +{{% /boxes/warning %}} + +**`event_property_is`** + +对事件属性值进行精确匹配。参数: + +- `key`:事件属性的[点分路径](/appendices#dot-separated-property-paths),如 `content.body`。 +- `value`:要匹配的值。 + +匹配为精确等值,仅支持非复合(canonical JSON)类型:字符串、区间 `[-(2**53)+1, (2**53)-1]` 内的整数、布尔值和 `null`。 + +如 `key` 指定属性不存在,或类型不是字符串、整数、布尔或 `null`,条件不匹配。 + +{{% boxes/note %}} +例如,若 `key` 为 `content.m\.federate`,`value` 为 `true`,事件如下匹配: + +```json +{ + "content": { + "creator": "@example:example.org", + "m.federate": true, + "predecessor": { + "event_id": "$something:example.org", + "room_id": "!oldroom:example.org" + }, + "room_version": "1" + }, + "event_id": "$143273582443PhrSn:example.org", + "room_id": "!636q39766251:example.com", + "sender": "@example:example.org", + "state_key": "", + "type": "m.room.create" +} +``` + +下列 `m.federate` 值不匹配: + * `"true"`(类型不同,字符串) + * `1`(不进行类型转换) +{{% /boxes/note %}} + +**`event_property_contains`** + +如事件某数组属性*精确包含*特定值则匹配。参数: + +- `key`:事件属性的[点分路径](/appendices#dot-separated-property-paths),如 `content.body`。 + +- `value`:要匹配的值。 + +仅当数组元素为非复合 canonical JSON 类型(字符串、上述区间内整数、布尔、`null`)时有效。其他类型将被忽略。 + +如 `key` 指定属性不存在,或不是数组,则条件不匹配。 + +{{% boxes/note %}} +例如,若 `key` 为 `content.alt_aliases`,`value` 为 `"#myroom:example.com"`,如下事件会匹配: + +```json +{ + "content": { + "alias": "#somewhere:localhost", + "alt_aliases": [ + "#somewhere:example.org", + "#myroom:example.com" + ] + }, + "event_id": "$143273582443PhrSn:example.org", + "origin_server_ts": 1432735824653, + "room_id": "!jEsUZKDJdhlrceRyVU:example.org", + "sender": "@example:example.org", + "state_key": "", + "type": "m.room.canonical_alias", + "unsigned": { + "age": 1234 + } +} +``` + +下列 `alt_aliases` 值不匹配: + * `":example.com"`(部分匹配不通过) +{{% /boxes/note %}} + +**`contains_display_name`** + +匹配 `content.body` 含有房间内该用户当前显示昵称的消息。因显示昵称可能变化,维护对应规则较难,故单独为此设一条件。该条件无参数。 + +**`room_member_count`** + +匹配房间当前成员数。参数: + +- `is`:一个支持可选前缀的十进制整数,前缀包括 `==`、`<`、`>`、`>=` 或 `<=` 。如 `<` 匹配成员数*小于*给定数字,依此类推。缺省无前缀时为 `==`。 + +**`sender_notification_permission`** + +结合房内当前权限设置,确保事件发送者权限足够以触发通知。 + +参数: + +- `key`:字符串,指定需触发何种类型通知时发信人需具备的权限级别,如 `room`。详见 + [m.room.power\_levels](#mroompower_levels) 事件结构。该 `key` 用于根据 power level 对象内容查找通知类型对应权限级别。 + +#### 预定义规则 + +主服务器可指定“服务器默认规则”。该类规则优先级低于“用户自定义规则”,唯一例外是 `.m.rule.master`,它总是所有规则中最高的。所有服务器默认规则的 `rule_id` 必须以点(".")开头以便区分。以下为规定的服务器默认规则: + +##### 默认 Override 规则 + +**`.m.rule.master`** + +匹配所有事件。启用后可关闭所有推送通知。不同于其它服务器默认规则,此规则始终优先级最高,连用户自定义规则都排在其后。默认禁用。 + +定义: + +```json +{ + "rule_id": ".m.rule.master", + "default": true, + "enabled": false, + "conditions": [], + "actions": [] +} +``` + +**`.m.rule.suppress_notices`** + +匹配 `msgtype` 为 `notice` 的消息。 + +定义: + +```json +{ + "rule_id": ".m.rule.suppress_notices", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "content.msgtype", + "pattern": "m.notice" + } + ], + "actions": [] +} +``` + +**`.m.rule.invite_for_me`** + +匹配针对该用户的新房间邀请。 + +定义: + +```json +{ + "rule_id": ".m.rule.invite_for_me", + "default": true, + "enabled": true, + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + }, + { + "key": "content.membership", + "kind": "event_match", + "pattern": "invite" + }, + { + "key": "state_key", + "kind": "event_match", + "pattern": "[the user's Matrix ID]" + } + ], + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + } + ] +} +``` + +**`.m.rule.member_event`** + +匹配任意 `m.room.member_event`。 + +定义: + +```json +{ + "rule_id": ".m.rule.member_event", + "default": true, + "enabled": true, + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + } + ], + "actions": [] +} +``` + + **`.m.rule.is_user_mention`** + +{{% added-in v="1.7" %}} + +匹配在 `m.mentions` 属性下 `user_ids` 包含用户 Matrix ID 的任意消息。 + +定义: + +```json +{ + "rule_id": ".m.rule.is_user_mention", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_property_contains", + "key": "content.m\\.mentions.user_ids", + "value": "[the user's Matrix ID]" + } + ], + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight" + } + ] +} +``` + + **`.m.rule.contains_display_name`** + +{{% changed-in v="1.7" %}} + +自 `v1.7` 起,该规则已废弃,**仅在事件未含 [`m.mentions` 属性](#definition-mmentions) 时启用**。 + +匹配内容含有用户当前房间显示昵称的消息。 + +定义: + +```json +{ + "rule_id": ".m.rule.contains_display_name", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "contains_display_name" + } + ], + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight" + } + ] +} +``` + + **`.m.rule.is_room_mention`** + +{{% added-in v="1.7" %}} + +匹配拥有相应权限、`m.mentions` 属性中的 `room` 字段为 `true` 的发信人消息。 + +定义: + +```json +{ + "rule_id": ".m.rule.is_room_mention", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_property_is", + "key": "content.m\\.mentions.room", + "value": true + }, + { + "kind": "sender_notification_permission", + "key": "room" + } + ], + "actions": [ + "notify", + { + "set_tweak": "highlight" + } + ] +} +``` + + **`.m.rule.roomnotif`** + +{{% changed-in v="1.7" %}} + +自 v1.7 起,该规则已废弃,**仅在事件未含 [`m.mentions` 属性](#definition-mmentions) 时启用**。 + +匹配拥有权限且内容含有 `@room` 字符串(需全房通知)的消息。 + +定义: + +```json +{ + "rule_id": ".m.rule.roomnotif", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "content.body", + "pattern": "@room" + }, + { + "kind": "sender_notification_permission", + "key": "room" + } + ], + "actions": [ + "notify", + { + "set_tweak": "highlight" + } + ] +} +``` + +**`.m.rule.tombstone`** + +匹配所有类型为 `m.room.tombstone` 的状态事件。用于通知房间升级,效果类似于 `@room` 通知。 + +定义: + +```json +{ + "rule_id": ".m.rule.tombstone", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.tombstone" + }, + { + "kind": "event_match", + "key": "state_key", + "pattern": "" + } + ], + "actions": [ + "notify", + { + "set_tweak": "highlight" + } + ] +} +``` + +**`.m.rule.reaction`** + +{{% added-in v="1.7" %}} + +匹配所有类型为 `m.reaction` 的事件。用于抑制 [`m.reaction`](#mreaction) 事件的通知。 + +定义: + +```json +{ + "rule_id": ".m.rule.reaction", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.reaction" + } + ], + "actions": [] +} +``` + +**`.m.rule.room.server_acl`** + +{{% added-in v="1.4" %}} + +抑制对 [`m.room.server_acl`](#mroomserver_acl) 事件的通知。 + +定义: + +```json +{ + "rule_id": ".m.rule.room.server_acl", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.server_acl" + }, + { + "kind": "event_match", + "key": "state_key", + "pattern": "" + } + ], + "actions": [] +} +``` + +**`.m.rule.suppress_edits`** + +{{% added-in v="1.9" %}} + +抑制与[事件替换](#event-replacements)相关的通知。 + +定义: + +```json +{ + "rule_id": ".m.rule.suppress_edits", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_property_is", + "key": "content.m\\.relates_to.rel_type", + "value": "m.replace" + } + ], + "actions": [] +} +``` + +##### 默认 Content 规则 + + **`.m.rule.contains_user_name`** + +{{% changed-in v="1.7" %}} + +自 v1.7 起,该规则已废弃,**仅当事件无 [`m.mentions` 属性](#definition-mmentions) 时启用**。 + +匹配内容包含用户 Matrix ID 本地部分(以单词边界分隔)的消息。 + +定义(作为 `content` 规则): + +```json +{ + "rule_id": ".m.rule.contains_user_name", + "default": true, + "enabled": true, + "pattern": "[the local part of the user's Matrix ID]", + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight" + } + ] +} +``` + +##### 默认 Underride 规则 + +**`.m.rule.call`** + +匹配所有传入 VOIP 呼叫事件。 + +定义: + +```json +{ + "rule_id": ".m.rule.call", + "default": true, + "enabled": true, + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.call.invite" + } + ], + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "ring" + } + ] +} +``` + +**`.m.rule.encrypted_room_one_to_one`** + +匹配发送至仅有两名成员的加密房间内的任意加密事件。不同于普通推送规则,加密后事件无法基于内容匹配,故此规则表现为“全匹配”或“不匹配” —— 若为 1:1 房间内所有加密事件都匹配,否则全不匹配。 + +定义: + +```json +{ + "rule_id": ".m.rule.encrypted_room_one_to_one", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "room_member_count", + "is": "2" + }, + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.encrypted" + } + ], + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + } + ] +} +``` + +**`.m.rule.room_one_to_one`** + +匹配仅有两名成员的房间内任意消息。 + +定义: + +```json +{ + "rule_id": ".m.rule.room_one_to_one", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "room_member_count", + "is": "2" + }, + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.message" + } + ], + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + } + ] +} +``` + +**`.m.rule.message`** + +匹配所有聊天消息。 + +定义: + +```json +{ + "rule_id": ".m.rule.message", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.message" + } + ], + "actions": [ + "notify" + ] +} +``` + +**`.m.rule.encrypted`** + +匹配所有加密事件。由于加密,事件内容不能被常规匹配,本规则表现为组房内所有加密事件全匹配或全不匹配。 + +定义: + +```json +{ + "rule_id": ".m.rule.encrypted", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.encrypted" + } + ], + "actions": [ + "notify" + ] +} +``` + +#### 推送规则:API + +客户端可通过以下 API 全局或针对各设备获取、添加、修改、删除推送规则。 + +{{% http-api spec="client-server" api="pushrules" %}} + +#### 推送规则:事件 + +当用户更改推送规则,会向所有客户端在下次 [`/sync`](#get_matrixclientv3sync) 请求的 `account_data` 部分发送 `m.push_rules` 事件。 +事件内容为用户当前的全部推送规则。 + +{{% event event="m.push_rules" %}} + +##### 示例 + +为 ID 为 `!dj234r78wl45Gh4D:matrix.org` 的房间创建禁止通知的规则: + + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/room/%21dj234r78wl45Gh4D%3Amatrix.org?access_token=123456" -d \ + '{ + "actions" : [] + }' + +禁止为用户名为 `@spambot:matrix.org` 的用户发送通知: + + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/sender/%40spambot%3Amatrix.org?access_token=123456" -d \ + '{ + "actions" : [] + }' + +为所有消息内容含 “cake” 的消息始终通知,并设置专用提示音(规则 ID 为 `SSByZWFsbHkgbGlrZSBjYWtl`): + + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/content/SSByZWFsbHkgbGlrZSBjYWtl?access_token=123456" -d \ + '{ + "pattern": "cake", + "actions" : ["notify", {"set_tweak":"sound", "value":"cakealarm.wav"}] + }' + +添加规则:禁止通知以 “cake” 开头、“lie” 结尾的消息,并优先级高于上一条规则: + + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/content/U3BvbmdlIGNha2UgaXMgYmVzdA?access_token=123456&before=SSByZWFsbHkgbGlrZSBjYWtl" -d \ + '{ + "pattern": "cake*lie", + "actions" : ["notify"] + }' + +为成员数不超过 10 的房间内含有 “beer” 的消息添加自定义通知音(优先级高于 room, sender, content 规则): + + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/v3/pushrules/global/override/U2VlIHlvdSBpbiBUaGUgRHVrZQ?access_token=123456" -d \ + '{ + "conditions": [ + {"kind": "event_match", "key": "content.body", "pattern": "beer" }, + {"kind": "room_member_count", "is": "<=10"} + ], + "actions" : [ + "notify", + {"set_tweak":"sound", "value":"beeroclock.wav"} + ] + }' + +#### 客户端行为 + +客户端必须先配置 Pusher,才能接收推送通知。具体 API 如下所述。 + +{{% http-api spec="client-server" api="pusher" %}} + +##### 列出通知 + +客户端可获取已收到通知的事件列表,帮助用户查看收到的重要消息摘要。 + +{{% http-api spec="client-server" api="notifications" %}} + +##### 接收通知 + +服务器必须在客户端的 [`/sync`](#get_matrixclientv3sync) 流中包含未读通知数,并随计数变化更新。通知判定依赖于事件适用的推送规则。 + +对于加密事件,主服务器仅有限访问事件内容,推送规则需由客户端在*解密后*处理,客户端收到每条事件都需执行推送规则。这可能导致需修正从主服务器收到的未读通知数。 + +##### 标记通知为已读 + +当用户更新已读回执(无论使用 API 还是通过发送事件),在该事件之前(含自身)的通知必须被标记为已读。具体被影响的事件取决于是否使用了[线程已读回执](#threaded-read-receipts)。用户可同时发送 `m.read` 和 `m.read.private` 回执,两者都可清除通知。 + +如同一房间内用户同时拥有 `m.read` 和 `m.read.private`,应取更“新”或“更靠前”的回执为判断依据。例如,若事件 A、B、C、D 按时间升序排列,`m.read` 回执在事件 C,`m.read.private` 在事件 A,则用户已读至 C。如果 `m.read.private` 更新为 B 或 C,通知状态不变(`m.read` 回执仍领先);如 `m.read.private` 更新为 D,则用户已读到 D(`m.read` 落后于 `m.read.private`)。 + +{{% added-in v="1.4" %}} 处理线程已读回执时,服务器需将通知数分配至各线程(主时间线看作一条线程)。判定事件属于哪个线程,服务器应按[event 关系](#forming-relationships-between-events)查找,直到遇到 `m.thread` 关系定义的根事件(详见[线程模块](#threading)),但不建议无限遍历。建议实现时至多跳 3 层,未找到线程即视为事件不属于线程。主要确保后续事件如 `m.reaction` 被正确划分为某线程。 + +#### 服务器行为 + +主服务器收到新事件时,为房间内每位本地用户(不含发信人)处理推送规则,结果可能为: + +* 生成新的未读通知数; +* 向配置的推送网关发起请求。 + +新事件导致的未读通知数必须与事件本身一起在同一次 [`/sync`](#get_matrixclientv3sync) 响应中返回。 + +#### 推送网关行为 + +##### APNS 推荐 + +APNS 推送通知的具体格式灵活,由客户端应用与其推送网关约定。由于 APNS 需求发送者具有应用开发者的私钥,每个应用需有专属推送网关。推荐如下: + +- APNS Token 基于 base64 编码,直接用于 pushkey。 +- 正式环境和沙箱环境使用不同的 app_id 。 +- APNS 推送网关不必等待 APNS 网关返回错误再响应;可记录失败,并在下次推送相同 pushkey 时返回 'rejected'。 + +#### 安全性注意事项 + +客户端需指定用于发送事件通知的推送网关 URL 。此 URL 必须为 HTTPS,*绝不能*是 HTTP。 + +推送通知会经过推送供应商,消息内容应尽量不随推送本体一起发送。推送网关应发送 "sync" 指令,指导客户端直接向主服务器获取新事件。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/read_markers.md b/locales/zh-Hans/client-server-api/modules/read_markers.md new file mode 100644 index 00000000..e75baa4b --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/read_markers.md @@ -0,0 +1,59 @@ +### 已读与未读标记 + +#### 完全已读标记 + +某个房间的消息历史可以被划分为三个部分:用户已读(或表示对其不感兴趣)的消息、用户可能只读了一部分的消息,以及用户尚未见过的消息。“完全已读标记”(也称为“已读标记”)标记了第一部分的最后一个事件,而用户的已读回执则标记了第二部分的最后一个事件。 + +##### 事件 + +用户的完全已读标记作为房间[账户数据](#client-config)中的一个事件进行保存。可以通过读取该事件来判断用户当前的完全已读标记在房间中的位置,并且和其他账户数据事件一样,该事件在更新时将通过事件流推送下发。 + +完全已读标记以 `m.fully_read` 事件的形式保存。如果该事件在用户账户数据中不存在,应将完全已读标记视为用户的已读回执位置。 + +{{% event event="m.fully_read" %}} + +##### 客户端行为 + +客户端无法通过直接修改 `m.fully_read` 账户数据事件来更新完全已读标记。相反,客户端必须使用已读标记 API 来更改该值。 + +{{% changed-in v="1.4" %}} 现在可以通过 `/read_markers` 发送 `m.read.private` 回执。 + +已读标记 API 还可以在设置完全已读标记位置的同时,更新用户的已读回执(`m.read` 或 `m.read.private`)的位置。因为已读回执和已读标记通常会被同时更新,因此客户端可能希望节省一次额外的 HTTP 调用。提供 `m.read` 和/或 `m.read.private` 的效果与对 +[`/receipt/{receiptType}/{eventId}`](#post_matrixclientv3roomsroomidreceiptreceipttypeeventid) 的请求相同。 + +{{% http-api spec="client-server" api="read_markers" %}} + +##### 服务器行为 + +服务器必须阻止客户端在房间账户数据中直接设置 `m.fully_read`。此外,服务器必须确保其对 `/read_markers` 请求中存在的 `m.read` 和 `m.read.private` 的处理方式与对 +[`/receipt/{receiptType}/{eventId}`](#post_matrixclientv3roomsroomidreceiptreceipttypeeventid) 的请求完全相同。 + +当由于 `/read_markers` 请求导致 `m.fully_read` 事件被更新时,服务器必须通过事件流(例如 `/sync`),并在满足任何适用过滤器的前提下,将更新后的账户数据事件发送到客户端。 + +#### 未读标记 + +{{% added-in v="1.12" %}} + +客户端可以使用“未读标记”允许用户独立于[已读回执](#receipts)或[完全已读标记](#fully-read-markers)对房间进行后续关注的标记。 + +##### 事件 + +用户在某房间中的未读标记通过房间[账户数据](#client-config)中的 `m.marked_unread` 事件进行保存。可通过该事件来确定用户在房间中的当前未读标记状态。和其他账户数据事件一样,该事件在更新时会通过事件流下发。 + +{{% event event="m.marked_unread" %}} + +##### 客户端行为 + +客户端必须通过直接修改 `m.marked_unread` 房间账户数据事件来更新未读标记。当标记房间为未读时,客户端不应更改 `m.fully_read` 标记,以便保留用户在该房间的已读位置。 + +当 `unread` 字段为 `true` 时,客户端应以视觉方式标注房间为未读。具体如何实现为实现细节。推荐客户端使用与未读通知房间相似的表现方式。 + +当打开某房间以展示其时间线时,客户端应通过将 `unread` 设为 `false` 来重置未读标记。 + +如果客户端提供通过为最新事件发送已读回执将房间标记为“已读”的功能,应同时重置未读标记。 + +如果 `m.marked_unread` 事件在用户账户数据中不存在,客户端必须视为 `unread` 为 `false` 进行处理。 + +##### 服务器行为 + +此子模块对服务器没有额外要求。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/receipts.md b/locales/zh-Hans/client-server-api/modules/receipts.md new file mode 100644 index 00000000..63b3c1b2 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/receipts.md @@ -0,0 +1,165 @@ +### 回执 + +{{% changed-in v="1.4" %}} 新增了私有已读回执。 + +本模块增加了对回执的支持。回执是一种对事件的确认方式。该模块定义了用于表示用户已读至某一事件的 `m.read` 回执,以及用于相同目的但不会被其他用户察觉的 `m.read.private` 回执。主要来说,`m.read.private` 旨在清除[通知](#receiving-notifications),而不向他人公开已读状态。 + +为每个事件发送回执可能导致向主服务器发送大量流量。为了防止这一问题,回执采用“已读至”标记的方式实现。此标记表示确认适用于“至(含)”指定事件的所有事件。例如,将某事件标记为“已读”就意味着用户已经阅读了*至此*的所有事件。关于已读回执如何影响通知计数,请参见[接收通知](#receiving-notifications)章节。 + +{{% added-in v="1.4" %}} 已读回执主要有三种形式: +* 非线程化:表示已读至某事件的回执,与线程无关。这等同于线程功能引入前的已读回执。 +* 线程化,主时间线:表示对非特定线程事件的已读回执。用线程 ID `main` 标识。 +* 线程化,特定线程:表示在指定线程内的已读回执。用线程根事件的事件 ID 标识。 + +有关线程化回执的更多详细信息,请参阅[下文](#threaded-read-receipts)。 + +#### 事件 + +{{% changed-in v="1.4" %}} 每个 `user_id`、`receipt_type` 和类别(非线程化,或 `thread_id`)三元组必须只关联一个 `event_id`。 + +{{% event event="m.receipt" %}} + +#### 客户端行为 + +{{% changed-in v="1.4" %}} 修订以支持线程化已读回执。 + +在 [`/sync`](#get_matrixclientv3sync) 接口中,回执列在指定房间的 `ephemeral` 事件数组下。新收到的回执是增量信息,用于更新已有的映射。客户端应依据 `user_id`、`receipt_type` 和(如有)`thread_id` 替换旧的已读回执。例如: + + 客户端收到 m.receipt: + user = @alice:example.com + receipt_type = m.read + event_id = $aaa:example.com + thread_id = undefined + + 客户端收到另一个 m.receipt: + user = @alice:example.com + receipt_type = m.read + event_id = $bbb:example.com + thread_id = main + + 此时客户端尚未替换任何确认。 + + 客户端再次收到 m.receipt: + user = @alice:example.com + receipt_type = m.read + event_id = $ccc:example.com + thread_id = undefined + + 客户端用新回执 $ccc:example.com 替换之前 $aaa:example.com 的确认,但不会替换 $bbb:example.com,因为它属于线程。 + + 客户端再次收到 m.receipt: + user = @alice:example.com + receipt_type = m.read + event_id = $ddd:example.com + thread_id = main + + 现在客户端用新 $ddd:example.com 的确认替换旧的 $bbb:example.com。客户端不会替换 $ccc:example.com 的旧回执,因为它是未线程化的。 + +客户端应在确定事件**已显示**给用户时才发送已读回执。仅仅收到事件并不能确保用户已经看到。用户应当*执行某些操作*,如查看事件所处房间或关闭通知,事件方可计为“已读”。客户端**不应**为自己的用户发送已读回执。 + +与发送回执的规则类似,线程化回执应出现在线程上下文中。如果线程被折叠,客户端尚未向用户展示该事件(或任何相关已读回执)。一旦用户展开线程,就应发送线程化已读回执,并显示来自其他用户的每线程回执。 + +客户端可通过以下 HTTP API 与其用户相关的回执状态进行更新。 + +{{% http-api spec="client-server" api="receipts" %}} + +##### 私有已读回执 + +{{% added-in v="1.4" %}} + +部分用户希望标记房间为已读,以清除其[通知计数](#receiving-notifications),但又不希望暴露自己已经阅读了特定消息。为此,客户端可以发送 `m.read.private` 回执,作用同 `m.read`,但不会向其他用户广播回执,从而实现只清除通知不公开已读状态。 + +服务器**不得**将 `m.read.private` 回执发送给除最初发送用户外的任何其他用户。 + +在 `m.read` 和 `m.read.private` 两者间,决定最高已读至标记时会采用“更靠前”或“更近期”的回执。关于这对通知计数影响的更多信息,请参见[通知](#receiving-notifications)章节。 + +如果客户端发送的 `m.read` 回执“落后”于 `m.read.private` 回执,其他用户会看到该变化,但发送用户的通知计数不会回退到那一时间点。尽管不常见,出现 `m.read`(公开)回执比 `m.read.private` 回执滞后几条消息的情况也是合法的。 + +##### 线程化已读回执 + +{{% added-in v="1.4" %}} + +如果客户端未使用[线程](#threading)功能,则只会发送“非线程化”已读回执,无论线程如何都影响整个房间。 + +线程化回执指的是带有 `thread_id` 的回执,其目标为线程根事件的事件 ID 或主时间线用 `main`。 + +线程化引入了在同一房间中进行多次独立会话的概念,因此也对应有独立的已读回执和通知计数。某事件被认为“属于线程”,需满足以下任一条件: + +* 其 `rel_type` 为 `m.thread`,或 +* 在事件关系链上,其父事件通过 `rel_type` 为 `m.thread` 的方式被关联到线程根。实现时不应无限级递归,建议最多递归 3 级以覆盖间接关系。 + +房间内未归属于某线程的事件视为主时间线中的事件。当用作线程引用(如回执和通知计数中),主时间线采用特殊线程 ID `main`。 + +线程根本身被视作主时间线事件,通过非线程关系与线程根相关的事件也被视为主时间线事件。 + +以下是一个房间的 DAG 示例,虚线表示事件间关系,实线表示拓扑排序。 + +{{% diagram name="threaded-dag" alt="呈现包含线程关系的单一时间线的DAG图" %}} + +该 DAG 可分解为 3 条线程化时间线,其中 `A` 和 `B` 为线程根: + +{{% diagram name="threaded-dag-threads" alt="呈现包含3条相关线程化时间线的 DAG 图" %}} + +据此可说明: +* 在 `I` 上的线程化已读回执会标记 `A`、`B` 和 `I` 为已读。 +* 在 `E` 上的线程化已读回执会标记 `C` 和 `E` 为已读。 +* 在 `D` 上的非线程化已读回执会标记 `A`、`B`、`C` 和 `D` 为已读。 + +注意,仅用线程化回执将 `A` 标记为已读,并不会让 `C`、`E`、`G` 或 `H` 也被标记为已读。线程 A 的时间线需在 `H` 上设置属于该线程的线程化回执才能做到。 + +上述 3 个例子的回执示例如下: + +```json +{ + "$I": { + "m.read": { + "@user:example.org": { + "ts": 1661384801651, + "thread_id": "main" // 因为 `I` 不在任何线程中,但回执为线程化回执 + } + } + }, + "$E": { + "m.read": { + "@user:example.org": { + "ts": 1661384801651, + "thread_id": "$A" // 因为 `E` 属于线程 `A` + } + } + }, + "$D": { + "m.read": { + "@user:example.org": { + "ts": 1661384801651 + // 无 `thread_id`,因为这是*非线程化*回执 + } + } + } +} +``` + +发送已读回执的条件在线程化与非线程化场景下适用方式一致。例如,当用户展开某线程时,客户端可能会为该线程事件发送私有已读回执。 + +#### 服务器行为 + +出于高效性考虑,应将回执合并打包为按房间和线程分组的事件后再发送给客户端。 + +部分回执会作为类型为 `m.receipt` 的 EDU 跨联邦发送。该 EDU 格式为: + +``` +{ + : { + : { + : { <内容(ts & thread_id, 当前支持)> } + }, + ... + }, + ... +} +``` + +这些均以增量方式相较此前已发送的回执推送。目前仅应使用一个 `` :`m.read`。`m.read.private` **不得**出现在联邦 `m.receipt` EDU 内。 + +#### 安全性注意事项 + +回执是在事件图之外发送的,因此 `m.receipt` 事件内容不会进行完整性校验。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/reference_relations.md b/locales/zh-Hans/client-server-api/modules/reference_relations.md new file mode 100644 index 00000000..649fcd5e --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/reference_relations.md @@ -0,0 +1,43 @@ +### 引用关系 + +{{% added-in v="1.5" %}} + +以通用方式引用其他事件时,可以使用 `rel_type` 为 `m.reference` 作为一种[关系类型](#forming-relationships-between-events)。引用本身没有特定含义,通常依赖于具体的应用场景。例如,[密钥验证框架](#key-verification-framework)便使用引用关系,将不同的事件与某次特定的验证尝试关联起来。 + +{{% boxes/note %}} +希望支持话题或回复功能的客户端应使用除引用以外的其他关系类型。引用通常用于关联数据而非消息。 +{{% /boxes/note %}} + +#### 服务器行为 + +##### `m.reference` 的服务端聚合 + +`m.reference` 关系的[聚合格式](#aggregations-of-child-events)包含一个名为 `chunk` 的属性,该属性列出了所有对该事件(父事件)进行 `m.reference` 的事件。目前,`chunk` 中的事件只包含单一的 `event_id` 字段。 + +例如,给定一个带有如下 `m.reference` 关系的事件: + +```json +{ + "content": { + "m.relates_to": { + "rel_type": "m.reference", + "event_id": "$another_event" + } + // 其他需要的内容字段 + } + // 事件所需的其他字段 +} +``` + +其聚合结果如下所示: + +```json +{ + "m.reference": { + "chunk": [ + { "event_id": "$one" }, + { "event_id": "$two" } + ] + } +} +``` \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/report_content.md b/locales/zh-Hans/client-server-api/modules/report_content.md new file mode 100644 index 00000000..c429b01d --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/report_content.md @@ -0,0 +1,19 @@ +### 举报内容 + +用户可能会遇到他们认为不适当的内容,并且应当能够将其举报给服务器管理员或房间管理员进行审核。本模块定义了用户举报内容的方法。 + +#### 客户端行为 + +{{% http-api spec="client-server" api="report_content" %}} + +#### 服务器行为 + +服务器可以以任何他们认为合适的方式处理被举报的内容。这可能包括专用的房间,用于提醒服务器管理员有关被举报内容的信息,或者其他通知相关人员的机制。 + +尤其是在有害内容爆发期间,用户可能会举报整个房间而不仅仅是单个事件。因此,服务器管理员和安全团队在处理举报时,应当谨慎,避免关闭那些可能本身是合法的房间。 + +{{% changed-in v="1.8" %}} 在处理事件举报时,服务器在接受举报前必须验证举报用户当前已加入该事件所在的房间。 + +{{% added-in v="1.13" %}} 相反,服务器不得根据举报用户是否已加入房间来限制对房间的举报。这是因为用户即使未加入房间,也可能会接触到有害内容。例如,通过房间目录或邀请等途径。 + +{{% added-in v="1.14" %}} 同样,服务器不得根据举报用户是否已加入被举报用户所在的任意房间来限制对用户的举报。这是因为用户即使未加入房间,也可能会接触到有害内容。例如,通过用户目录或邀请等途径。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/rich_replies.md b/locales/zh-Hans/client-server-api/modules/rich_replies.md new file mode 100644 index 00000000..91489bdd --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/rich_replies.md @@ -0,0 +1,67 @@ +### 富回复(Rich replies) + +富回复是一种特殊类型的[关系](#forming-relationships-between-events),它有效地引用了被引用事件,供客户端以其所希望的方式进行渲染或处理。富回复通常与 [`m.room.message`](#mroommessage) 事件一起使用。 + +{{% boxes/note %}} +{{% changed-in v="1.3" %}} +在规范 v1.3 之前,富回复仅限于表示为 HTML 格式正文的 `m.room.message` 事件。从 v1.3 开始,这一限制被解除,富回复现在可以应用于*所有*事件类型,无需再强制要求包含 HTML 格式正文。 + +此外,从 v1.3 起,富回复可以引用任何其他事件类型。此前,富回复只能引用另一条 `m.room.message` 事件。 +{{% /boxes/note %}} + +{{% boxes/note %}} +{{% changed-in v="1.13" %}} +在规范早期版本中,富回复可在 `body`(通过前缀序列)和 `formatted_body`(通过自定义 HTML 元素)中包含原始消息的回退表示,供不支持富回复的客户端使用。目前已不再要求如此,但客户端仍*应*在渲染事件前移除这些回退内容。 + +要去除 `body` 中的回退内容,客户端应逐行遍历字符串,移除以回退前缀序列(`> `,包括尾随空格)开始的所有行,遇到不含该前缀的行时停止处理。 + +要去除 `format` 为 `org.matrix.custom.html` 的 `m.room.message` 事件的 `formatted_body` 回退内容:如果 `formatted_body` 以 `` 起始标签开头,客户端应移除整个 `` 元素。 +{{% /boxes/note %}} + +虽然富回复与另一个事件形成关系,但它们并不使用 `rel_type` 来建立这种关系。相反,采用名为 `m.in_reply_to` 的子键来描述回复关系,从而使 `m.relates_to` 的其它属性可被用于描述该事件的主关系。这意味着,如果一个事件只是单纯回复另一事件而无其它关系,`m.relates_to` 中的 `rel_type` 和 `event_id` 属性*变为可选*。 + +一个回复示例: + +```json +{ + "content": { + "m.relates_to": { + "m.in_reply_to": { + "event_id": "$another_event" + } + }, + "body": "That sounds like a great idea!" + }, + // 事件所需的其他字段 +} +``` + +请注意,`m.in_reply_to` 对象中的 `event_id` 具有与其直接位于 `m.relates_to` 下时相同的要求。 + +#### 提及被回复用户 + +为了通知用户被回复,建议在回复中包括被回复事件的 `sender` 以及该事件中提及的所有用户。更多信息请参见[用户和房间提及](#user-and-room-mentions)。 + +包含原始发送者及其他用户提及的示例: + +```json +{ + "content": { + "m.relates_to": { + "m.in_reply_to": { + "event_id": "$another_event" + } + }, + "body": "That sounds like a great idea!", + "m.mentions": { + "user_ids": [ + // $another_event 的发送者 + "@alice:example.org", + // 从 $another_event 的 m.mentions 属性中复制的另一个 Matrix ID + "@bob:example.org" + ] + } + }, + // 事件所需的其他字段 +} +``` \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/room_previews.md b/locales/zh-Hans/client-server-api/modules/room_previews.md new file mode 100644 index 00000000..d150b200 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/room_previews.md @@ -0,0 +1,21 @@ +### 房间预览 + +有时,允许用户在未加入房间的情况下“旁听”并阅读房间中发布的消息,即为房间提供预览,是十分有用的功能。当与 [访客访问](#guest-access) 结合使用时,这一功能效果尤为明显。 + +房间预览通过 `world_readable` 的 [房间历史消息可见性](#room-history-visibility) 设置以及 [GET /events](#get_matrixclientv3events) 接口的特殊版本实现。 + +#### 客户端行为 + +希望在未加入房间的情况下查看房间内容的客户端,应调用 [GET /rooms/:room_id/initialSync](#get_matrixclientv3roomsroomidinitialsync),然后调用 [GET /events](#peeking_get_matrixclientv3events)。对于每一个希望查看的房间,客户端都需要并行执行此操作。 + +当然,客户端也可以调用其他接口,例如 [GET /rooms/:room_id/messages](#get_matrixclientv3roomsroomidmessages) 和 [GET /search](#post_matrixclientv3search),以访问 `/events` 流以外的事件。 + +{{% http-api spec="client-server" api="peeking_events" anchor_base="peeking" %}} + +#### 服务器行为 + +对于尚未加入房间的客户端,服务器仅需返回这些事件:在事件发生时,房间状态存在 `m.room.history_visibility` 状态事件,且其 `history_visibility` 值为 `world_readable`。 + +#### 安全性注意事项 + +客户端可以向用户展示房间处于 `world_readable` 状态时,*可能*会向未加入房间的用户显示消息。通过此模块无法判断是否确有未加入的访客用户实际查看了房间中的事件,也无法列举或统计正在“旁听”的用户数量。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/room_upgrades.md b/locales/zh-Hans/client-server-api/modules/room_upgrades.md new file mode 100644 index 00000000..f651271d --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/room_upgrades.md @@ -0,0 +1,43 @@ +### 房间升级 + +有时,由于各种原因,房间可能需要升级为不同的房间版本。本模块定义了一种在需要时将房间升级到不同房间版本的方法。 + +#### 事件 + +{{% event event="m.room.tombstone" %}} + +#### 客户端行为 + +能够识别 `m.room.tombstone` 事件及 `m.room.create` 事件中的 `predecessor` 字段的客户端,应向用户传达房间已升级的信息。一种实现方式是将旧房间从用户的房间列表中隐藏,并显示横幅,在新旧房间间提供相互链接——确保在引用旧房间时永久链接仍能正常工作。另一种做法是虚拟合并房间,使旧房间的时间线能够无缝延续到新房间的时间线,用户无需在房间间切换即可继续体验。 + +{{% http-api spec="client-server" api="room_upgrades" %}} + +#### 服务器行为 + +当客户端请求将已知房间升级为已知版本时,服务器应: + +1. 检查用户有权限在房间中发送 `m.room.tombstone` 事件。 + +2. {{% changed-in v="1.4" %}} 创建一个替代房间,并在新房间中发送包含 `predecessor` 字段、相应 `room_version` 以及从前置房间复制的 `type` 字段的 `m.room.create` 事件。如果前一个房间未设置 `type`,则新房间的创建事件同样不指定 `type`。 + +3. 将可转移的状态事件复制到新房间。具体转移哪些内容留给实现方决定,不过推荐转移的状态事件包括: + + - `m.room.server_acl` + - `m.room.encryption` + - `m.room.name` + - `m.room.avatar` + - `m.room.topic` + - `m.room.guest_access` + - `m.room.history_visibility` + - `m.room.join_rules` + - `m.room.power_levels` + + 会员事件不应用于转移到新房间,这是因为服务器在技术上无法冒充来自其他主服务器的用户。此外,服务器也不应转移对发送者有敏感要求的状态事件,例如 Matrix 命名空间之外的事件,客户端可能要求这些事件的发送者满足特定条件。 + +4. 将所有本地别名迁移到新房间。 + +5. 向旧房间发送 `m.room.tombstone` 事件,以指示该房间不再建议继续使用。 + +6. 如有可能,还应修改旧房间的权限级别(power levels),以阻止发送事件和邀请新用户。例如,将 `events_default` 和 `invite` 设置为 `50` 与 `users_default + 1` 中的较大者。 + +当用户加入新房间时,服务器应自动转移或复制用户的一些个性化设置,如通知、标签等。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/search.md b/locales/zh-Hans/client-server-api/modules/search.md new file mode 100644 index 00000000..dcfa07c6 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/search.md @@ -0,0 +1,64 @@ +### 服务器端搜索 + +搜索 API 允许客户端对用户所加入过的所有房间中的事件进行全文搜索,包括用户已经离开的房间。仅搜索用户有权限查看的事件,例如,用户离开房间后发生的事件将不会被包含。 + +#### 客户端行为 + +服务器端搜索有一个统一的 HTTP API,具体文档如下。 + +{{% http-api spec="client-server" api="search" %}} + +#### 搜索类别 + +搜索 API 允许客户端按不同类别进行搜索。目前唯一被明确定义的类别是 `room_events`。 + +##### `room_events` + +该类别包含所有用户有权限查看的事件,包括用户已经离开的房间中的事件。搜索会在特定事件类型的特定键值上进行。 + +支持检索的字段包括: + +- `m.room.message` 事件的 `content.body` +- `m.room.name` 事件的 `content.name` +- `m.room.topic` 事件的 `content.topic` + +加密的房间(端对端加密)不会被包含在搜索范围内。 + +搜索结果包含一个 `rank` 键,可用于按相关度排序结果。`rank` 值越高,结果越相关。 + +`count` 字段用于大致表示总结果数。Homeserver 可能会返回一个估计值,而非精确值。 + +#### 排序方式 + +客户端可以指定服务器返回结果的排序方式。允许的两种排序方式为: + +- `rank`:首先返回最相关的结果。 +- `recent`:首先返回最新的结果。 + +默认排序方式为 `rank`。 + +#### 分组 + +客户端可以请求返回带有分组信息的结果,例如按 `room_id` 分组。在这种情况下,响应中会包含每个不同 `room_id` 的分组条目。每个分组条目至少包含该分组内的 `event_id` 列表,也可能包含关于该分组的其他元数据。 + +当前要求支持的分组方式有: + +- `room_id` +- `sender` + +#### 分页 + +服务器响应中各处可能会返回一个 `next_batch` 键。它用于对结果进行分页。若需获取更多结果,客户端应使用相同的请求,并将 `next_batch` 查询参数设置为该标记。 + +分页的范围取决于 `next_batch` 标记返回的位置。例如,在分组内使用该标记将返回该分组中的更多结果。 + +目前支持的 `next_batch` 标记位置有: + +- `search_categories..next_batch` +- `search_categories..groups...next_batch` + +即使存在更多匹配结果,服务器也可以选择不支持分页。在这种情况下,响应中不得返回 `next_batch` 标记。 + +#### 安全性注意事项 + +服务器只能返回用户有权限查看的结果。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/secrets.md b/locales/zh-Hans/client-server-api/modules/secrets.md new file mode 100644 index 00000000..9b80804a --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/secrets.md @@ -0,0 +1,229 @@ +### 机密信息 + +{{% added-in v="1.1" %}} + +客户端可能拥有希望授权给其他客户端访问但不希望服务器知晓的机密信息,因此这些信息在通过服务器传递时必须进行加密。这可以通过异步方式(将加密后的数据存储在服务器供之后获取)或同步方式(客户端之间互发消息)来实现。 + +每个机密信息都有一个标识符,客户端在存储、获取、请求或共享机密信息时会通过该标识符进行引用。机密信息是普通字符串;如需存储结构化数据,可将其编码为字符串形式。 + +本节所描述的机制被称为“安全机密信息存储与共享”(secure secret storage and sharing)、简称“SSSS”或“4S”。 + +#### 存储 + +当机密信息存储在服务器上时,会以[账户数据](#client-config)的形式存储在用户的账户数据中,事件类型等于机密信息的标识符。用于加密机密信息的密钥,其描述也会存储在用户的账户数据中。用户可以拥有多个密钥,从而根据分配给客户端的密钥控制其可访问哪些机密信息。 + +##### 密钥存储 + +每个密钥都有一个 ID,其描述以事件类型 `m.secret_storage.key.[key ID]` 存储在用户的账户数据中。密钥的账户数据内容包含一个 `algorithm` 属性,表示所用加密算法,以及一个 `name` 属性,为该密钥的可读名称。密钥描述中还可以包含一个 `passphrase` 属性,该属性用于根据用户输入的口令生成密钥,详见[从口令派生密钥](#deriving-keys-from-passphrases)。 + +`KeyDescription` + +| 参数 | 类型 | 说明 | +|-------------|-----------|--------------------------------------------------------------------------------------------------------------------------------------------| +| name | string | 可选。密钥名称。如果未提供,客户端可使用“未命名密钥”之类的通用名称;若该密钥被标记为默认密钥(见下文),则可用“默认密钥”。 | +| algorithm | string | **必需。** 此密钥使用的加密算法。目前仅支持 `m.secret_storage.v1.aes-hmac-sha2`。 | +| passphrase | string | 详见[从口令派生密钥](#deriving-keys-from-passphrases)一节。 | + +其他属性依赖于加密算法,详见下文。 + +如需将某个密钥标记为“默认”密钥,应在用户的账户数据中,设置事件类型为 `m.secret_storage.default_key` 的对象,其 `key` 属性为该密钥 ID。默认密钥将用于加密用户期望在所有客户端均可用的所有机密信息。除非用户另行指定,客户端将尝试使用默认密钥解密机密信息。 + +希望为用户提供简化界面的客户端可只支持默认密钥。若未指定默认密钥,客户端可视为不存在任何密钥。当此类客户端创建密钥时,应将其标为默认密钥。 + +`DefaultKey` + +| 参数 | 类型 | 说明 | +|------|--------|----------------------------| +| key | string | **必需。** 默认密钥的ID。 | + + +###### `m.secret_storage.v1.aes-hmac-sha2` + +为便于客户端检查用户输入密钥的正确性,`m.secret_storage.v1.aes-hmac-sha2` 算法使用的密钥会存储附加数据。 + +存储密钥时,客户端应: + +1. 以机密信息存储密钥为基础,使用 SHA-256 为哈希值,32字节0为salt,空字符串为info执行 HKDF,生成64字节数据。前32字节为AES密钥,后32字节为MAC密钥。 + +2. 生成16字节随机数,将第63位设为0(为兼容不同 AES-CTR 实现),作为AES初始化向量(IV)。 + +3. 用第1步所得的AES密钥和IV,以 AES-CTR-256 加密32字节的零组成的消息。 + +4. 用第1步所得的MAC密钥,对第3步所得的原始加密数据执行 HMAC-SHA-256。 + +5. 将第2步生成的IV与第4步生成的 MAC,使用[无填充 base64](/appendices/#unpadded-base64) 编码,并分别存储在 `iv` 和 `mac` 属性中,属性位置为 `m.secret_storage.key.[key ID]` 账户数据。(第3步得到的密文仅用于MAC计算后即丢弃。) + +客户端在检查密钥正确性时可重复此过程:若MAC值匹配,则密钥正确。但需注意,这些属性为**可选**。若不存在此类属性,客户端必须假定密钥有效。 + +还需注意,虽然建议客户端应当如上采用无填充base64进行编码,但部分现有实现使用标准[RFC4648规范base64](https://datatracker.ietf.org/doc/html/rfc4648#section-4)并含有填充,因此客户端必须同时兼容两种编码。 + +因此,面向该算法的 `m.secret_storage.key.[key ID]` 账户数据结构如下: + +`AesHmacSha2KeyDescription` + +| 参数 | 类型 | 说明 | +|-----------|--------|---------------------------------------------------------------------------------------------------| +| name | string | 可选。密钥名称。 | +| algorithm | string | **必需。** 此密钥使用的加密算法:`m.secret_storage.v1.aes-hmac-sha2`。 | +| passphrase| object | 详见[从口令派生密钥](#deriving-keys-from-passphrases)一节。 | +| iv | string | 可选。校验用的16字节初始化向量,base64编码。 | +| mac | string | 可选。对32字节零加密结果的MAC,base64编码。 | + +示例: + +```json +{ + "name": "m.default", + "algorithm": "m.secret_storage.v1.aes-hmac-sha2", + "iv": "random+data", + "mac": "mac+of+encrypted+zeros" +} +``` + +##### 机密信息存储 + +加密后的数据以具体功能定义的事件类型,存储在用户账户数据中。账户数据会有一个 `encrypted` 属性,为从密钥ID到对象的映射。特定密钥的 `m.secret_storage.key.[key ID]` 数据中的算法定义了解释其他属性的方式,但大多数加密方案应包含 `ciphertext` 和 `mac` 两个属性,其中 `ciphertext` 属性为无填充base64编码的密文,`mac` 用于保证数据完整性。 + +`Secret` + +| 参数 | 类型 | 说明 | +|-----------|--------------------|----------------------------------------------------------------------------------------------------------------| +| encrypted | {string: object} | **必需。** 密钥ID到加密数据的映射。加密数据的确切格式取决于密钥算法。参见[m.secret_storage.v1.aes-hmac-sha2](#msecret_storagev1aes-hmac-sha2-1) 节中的 `AesHmacSha2EncryptedData` 定义。 | + +示例: + +某机密信息使用 ID 为 `key_id_1` 和 `key_id_2` 的密钥加密: + +`org.example.some.secret`: + +``` +{ + "encrypted": { + "key_id_1": { + "ciphertext": "base64+encoded+encrypted+data", + "mac": "base64+encoded+mac", + // ... 其他属性,见 m.secret_storage.key.key_id_1 的 algorithm 属性 + }, + "key_id_2": { + // ... + } + } +} +``` + +相应密钥的描述: + +`m.secret_storage.key.key_id_1`: + +``` +{ + "name": "Some key", + "algorithm": "m.secret_storage.v1.aes-hmac-sha2", + // ... 其他属性,见 algorithm +} +``` + +`m.secret_storage.key.key_id_2`: + +``` +{ + "name": "Some other key", + "algorithm": "m.secret_storage.v1.aes-hmac-sha2", + // ... 其他属性,见 algorithm +} +``` + +若 `key_id_1` 为默认密钥,则还应有: + +`m.secret_storage.default_key`: + +``` +{ + "key": "key_id_1" +} +``` + +###### `m.secret_storage.v1.aes-hmac-sha2` + +采用 `m.secret_storage.v1.aes-hmac-sha2` 算法加密的机密信息,使用 AES-CTR-256 进行加密,并用 HMAC-SHA-256 进行认证,加密过程如下: + +1. 以机密信息存储密钥为基础,使用 SHA-256 作为哈希,32字节0为salt,以机密名称为info,执行HKDF生成64字节。前32字节为AES密钥,后32字节为MAC密钥。 + +2. 生成16字节随机数,将第63位设为0(为兼容不同AES-CTR实现),用作AES初始化向量(IV)。 + +3. 用第1步获得的AES密钥和IV,采用 AES-CTR-256 加密数据。 + +4. 用第1步获得的MAC密钥,对第3步获得的原始加密数据执行HMAC-SHA-256。 + +5. 将第2步的 IV、第3步的密文和第4步的 MAC 用[无填充 base64](/appendices/#unpadded-base64) 编码,分别存为账户数据对象的 `iv`、`ciphertext` 和 `mac` 属性。 + + **注意**:部分现有实现使用标准[RFC4648规范base64](https://datatracker.ietf.org/doc/html/rfc4648#section-4)带填充进行编码,因此客户端必须两种编码均可接受。 + +采用该算法加密的账户数据对象的 `encrypted` 属性结构如下: + +`AesHmacSha2EncryptedData` + +| 参数 | 类型 | 说明 | +|-----------|---------|------------------------------------------------------------------| +| iv | string | **必需。** 16字节初始化向量,base64编码。 | +| ciphertext| string | **必需。** AES-CTR加密的数据,base64编码。 | +| mac | string | **必需。** MAC,base64编码。 | + +示例,加密后数据形态如下: + +```json +{ + "encrypted": { + "key_id": { + "iv": "16+bytes+base64", + "ciphertext": "base64+encoded+encrypted+data", + "mac": "base64+encoded+mac" + } + } +} +``` + +##### 密钥表示 + +用户获得 `m.secret_storage.v1.aes-hmac-sha2` 的原始密钥时,应以[通用加密密钥表示方法](/appendices/#cryptographic-key-representation)的字符串形式呈现密钥。 + +##### 从口令派生密钥 + +用户可能希望使用自选口令而非随机生成的密钥。在这种情况下,如何从口令生成密钥的信息会保存在 `m.secret_storage.key.[key ID]` 账户数据的 `passphrase` 属性中。`passphrase` 属性包含一个 `algorithm` 属性,表示如何据口令生成密钥。`passphrase` 的其他属性由指定的算法定义。 + +当前只定义了 `m.pbkdf2` 算法。对于 `m.pbkdf2`,`passphrase` 属性包括: + +| 参数 | 类型 | 说明 | +|-----------|---------|---------------------------------------------| +| algorithm | string | **必需。** 必须为 `m.pbkdf2` | +| salt | string | **必需。** PBKDF2 算法使用的 salt。 | +| iterations| integer | **必需。** PBKDF2 算法使用的迭代次数。 | +| bits | integer | 可选。生成密钥的位数,默认256。 | + +密钥将使用 PBKDF2 算法,以 SHA-512 为哈希,使用 `salt` 属性作为盐值,`iterations` 属性指明迭代次数生成。 + +示例: + +``` +{ + "passphrase": { + "algorithm": "m.pbkdf2", + "salt": "MmMsAlty", + "iterations": 100000, + "bits": 256 + }, + ... +} +``` + +#### 共享 + +客户端如需向其他设备请求机密信息,可发送 `m.secret.request` 设备事件,`action` 设为 `request`,`name` 设为机密信息标识符。有意愿分享机密信息的设备将用Olm加密,发送 `m.secret.send` 事件回复。当原始客户端获取到机密信息后,应向所有除获得机密信息那台设备外的其他设备发送 `m.secret.request` 事件,`action` 设置为 `request_cancellation`。客户端应忽略未针对本机发送 `m.secret.request` 事件的设备所收到的 `m.secret.send` 事件。 + +客户端必须确保仅将机密信息共享给被授权查看的其他设备。例如,客户端应仅与自己已验证的设备共享机密信息,必要时还可提示用户确认共享操作。 + +##### 事件定义 + +{{% event event="m.secret.request" %}} + +{{% event event="m.secret.send" %}} \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/send_to_device.md b/locales/zh-Hans/client-server-api/modules/send_to_device.md new file mode 100644 index 00000000..68b871d4 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/send_to_device.md @@ -0,0 +1,68 @@ +### 设备间消息发送(Send-to-Device messaging) + +本模块为客户端提供了一种交换信令消息的方式,这些消息不会作为共享通信历史的一部分被永久存储。每条消息将精确地送达每个客户端设备一次。 + +该 API 的主要动机是用于交换在房间有向无环图(DAG)中无意义或不希望持久保存的数据——例如,一次性身份验证令牌或密钥数据。它并不适用于会话内容,会话内容应使用常规的 [`/rooms//send`](/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid) API 发送,以保持 Matrix 协议的一致性。 + +#### 客户端行为 + +要向其他设备发送消息,客户端应调用 [`/sendToDevice`](/client-server-api/#put_matrixclientv3sendtodeviceeventtypetxnid)。每个事务中,每台设备只能发送一条消息,且所有消息的事件类型必须一致。请求体中的设备ID可以设置为 `*`,以请求将消息发送到所有已知设备。 + +如果有等待客户端接收的设备间消息,这些消息将通过 [`/sync`](/client-server-api/#get_matrixclientv3sync) 返回,详见[对 /sync 的扩展](/client-server-api/#extensions-to-sync)。客户端应检查每个返回事件的 `type` 字段,并忽略其无法识别的事件。 + +#### 服务器行为 + +服务器应为本地用户存储待发送消息,直到它们成功送达目标设备。当客户端使用与有待发送消息的设备相关联的访问令牌调用 [`/sync`](/client-server-api/#get_matrixclientv3sync) 时,服务器应按到达顺序在响应体中列出这些待发送消息。 + +当客户端再次使用第一次响应中的 `next_batch` 令牌调用 `/sync` 时,服务器应推断该响应中的所有设备间消息已成功送达,并从存储中删除它们。 + +如果有大量待发送的设备间消息,服务器应限制在每次 `/sync` 响应中发送的消息数量。建议合理的上限为 100 条消息。 + +如果客户端向远程域的用户发送消息,这些消息应通过[联邦协议(federation)](/server-server-api#send-to-device-messaging)发送至远程服务器。 + +#### 协议定义 + +{{% http-api spec="client-server" api="to_device" %}} + +##### 对 /sync 的扩展 + +本模块在 [`/sync`](/client-server-api/#get_matrixclientv3sync) 响应中增加了以下属性: + +| 参数 | 类型 | 说明 | +|------------|-------------|--------------------------------------------------------------------| +| to_device | ToDevice | 可选。关于本客户端设备的设备间消息(send-to-device)信息。 | + +`ToDevice` + +| 参数 | 类型 | 说明 | +|------------|-------------|----------------------------------------| +| events | [Event] | 设备间消息列表。 | + +`Event` + +| 参数 | 类型 | 说明 | +|-----------|----------------|------------------------------------------------------------------------------------------| +| content | EventContent | 本事件的内容。此对象中的字段将根据事件类型有所不同。 | +| sender | string | 发送本事件的 Matrix 用户ID。 | +| type | string | 事件类型。 | + +示例响应: + +```json +{ + "next_batch": "s72595_4483_1934", + "rooms": {"leave": {}, "join": {}, "invite": {}}, + "to_device": { + "events": [ + { + "sender": "@alice:example.com", + "type": "m.new_device", + "content": { + "device_id": "XYZABCDE", + "rooms": ["!726s6s6q:example.com"] + } + } + ] + } +} +``` \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/server_acls.md b/locales/zh-Hans/client-server-api/modules/server_acls.md new file mode 100644 index 00000000..91a2b34b --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/server_acls.md @@ -0,0 +1,31 @@ +### 房间的服务器访问控制列表(ACLs) + +在某些场景下,房间管理员可能希望阻止恶意或不受信任的服务器参与他们的房间。向房间发送一个 [m.room.server_acl](#mroomserver_acl) 状态事件,是在联邦层面上阻止服务器参与房间的有效方法。 + +服务器 ACL 也可用于使房间仅与有限的服务器集合联邦,或事后让房间不再与任何其他服务器联邦,这类似于在 [m.room.create](#mroomcreate) 事件中设置 `m.federate` 值。 + +{{% event event="m.room.server_acl" %}} + +{{% boxes/note %}} +端口号不受支持,因为解析器无法确定应该匹配端口号还是 IP 地址字面量。此外,几乎不会有人只信任某个域上的特定端口而不信任其他端口,尤其是考虑到服务器主机可以轻易更换端口。 +{{% /boxes/note %}} + +{{% boxes/note %}} +CIDR 表示法不支持 IP 地址,因为 Matrix 并不鼓励使用 IP 作为服务器的身份标识。相反,提供了一个通用的 `allow_ip_literals` 选项用于全面禁止它们。 +{{% /boxes/note %}} + +#### 客户端行为 + +客户端除了发送该事件外,无需执行任何额外操作。客户端应在用户界面中描述对服务器 ACL 的更改,例如在时间线上展示。 + +客户端可以选择在拒绝服务器访问房间之前,先踢出受影响的用户,以帮助防止这些服务器参与,并向用户提供被排除在房间之外的反馈。 + +#### 服务器行为 + +当房间状态中存在 [m.room.server_acl](#mroomserver_acl) 事件时,服务器必须阻止被列入黑名单的服务器发送事件或参与房间。具体受影响的 API,在服务器-服务器 API 规范中有详细说明。 + +如果被拒绝的服务器仍然是房间成员,服务器仍应向其发送事件。 + +#### 安全性考量 + +服务器 ACL 只有在房间内的每个服务器都遵守它们时才有效。不遵守 ACL 的服务器仍可能允许被拒绝服务器发送的事件进入房间,并将其泄露给房间内的其他服务器。要在房间有效执行 ACL,还应在房间内拒绝那些不遵守 ACL 的服务器。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/server_notices.md b/locales/zh-Hans/client-server-api/modules/server_notices.md new file mode 100644 index 00000000..e98303b4 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/server_notices.md @@ -0,0 +1,31 @@ +### 服务器通知 + +Homeserver 提供商通常希望以官方身份向用户发送消息,或者其资源限制会影响用户使用 homeserver 的能力。例如,homeserver 可能每月只允许一定数量的活跃用户,并且已经超出了该限制。为了向用户传达这一限制,homeserver 会使用服务器通知房间(Server Notices Room)。 + +房间的外观(名称、主题、头像等)作为实现细节留给实现方决定。建议 homeserver 对房间进行装饰,使其在用户看来像是一个官方房间。 + +#### 事件 + +通知会作为正常的 `m.room.message` 事件发送到客户端,在服务器通知房间内的事件 `msgtype` 为 `m.server_notice`。客户端必须忽略服务器通知房间外,`msgtype` 为 `m.server_notice` 的事件。 + +`server_notice_type` 的指定取值如下: + +`m.server_notice.usage_limit_reached` +服务器已超出某项限制,需要服务器管理员进行干预。`limit_type` 描述已达成的限制类型。`limit_type` 的指定取值如下: + +`monthly_active_user` +服务器在过去 30 天内的活跃用户数已超过最大值。服务器正在拒绝新的连接。“活跃”的定义作为实现细节留给实现方决定,但建议服务器将同步用户视为“活跃”。 + +{{% event event="m.room.message$m.server_notice" title="`m.room.message`,`msgtype: m.server_notice`" %}} + +#### 客户端行为 + +客户端可以通过房间的 `m.server_notice` 标签识别服务器通知房间。活跃通知通过服务器通知房间中的[置顶事件](#mroompinned_events)表示。在该房间中被置顶的服务器通知事件,客户端应通过特殊的用户界面展示给用户,而不是通过普通的置顶事件界面。例如,客户端可以显示警告横幅或弹窗以引起用户注意。在服务器通知房间中被置顶但不是服务器通知事件的事件,应与房间中其他置顶事件一样展示。 + +客户端不得期望能够拒绝加入服务器通知房间的邀请。尝试拒绝该邀请必须导致返回 `M_CANNOT_LEAVE_SERVER_NOTICE_ROOM` 错误。服务器不应阻止用户在加入服务器通知房间后离开该房间,但如果服务器要阻止离开房间,则必须使用同样的错误码。 + +#### 服务器行为 + +服务器应为每个用户管理正好 1 个服务器通知房间。服务器必须通过 `m.server_notice` 标签向客户端标识此房间。服务器应向目标用户发送邀请,而不是自动将其加入服务器通知房间。 + +服务器如何向客户端发送通知、以及使用哪个用户发送事件,均作为服务器的实现细节处理。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/spaces.md b/locales/zh-Hans/client-server-api/modules/spaces.md new file mode 100644 index 00000000..3be84d7b --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/spaces.md @@ -0,0 +1,176 @@ +### 空间 + +{{% added-in v="1.2" %}} + +空间常用于将主题相似的房间进行分组(例如公共的“Official matrix.org rooms”空间或个人的“Work stuff”空间),是一种用于组织房间的方式,同时自身也被表示为房间。 + +空间通过 [`m.space` 房间类型](#types) 定义,因此被称为“空间房间(space-room)”。空间的名称、主题、头像、别名等,均通过空间房间内已有的相关状态事件来定义。 + +在空间房间内发送普通的 [`m.room.message`](#mroommessage) 事件是不推荐的——客户端通常并不预期会有方法渲染该房间的时间线。因此,空间房间应当通过设置 [`m.room.power_levels`](#mroompower_levels) 中的 `events_default` 为足够高的数值来禁止普通事件的发布。在默认的权限层级结构中,该值应为 `100`。客户端还可进一步不对空间房间计入通知数。 + +空间成员资格通过现有的房间管理机制定义和控制:即 [`m.room.member`](#mroommember)、[`m.room.history_visibility`](#mroomhistory_visibility) 和 [`m.room.join_rules`](#mroomjoin_rules)。建议公共空间与公共房间采用类似设置:`world_readable` 的历史可见性、已发布的规范别名以及适当的公共加入规则。邀请(包括第三方邀请)同样适用于空间房间。 + +常规房间的其他特性也同样适用于空间,如可设置任意状态事件、存储房间账户数据等。空间本质上是具有额外功能的房间。 + +#### 管理空间内包含的房间/空间 + +空间组成了一个房间层级体系,客户端可借此将房间列表结构化为树状视图。父子关系有两种定义方式:在空间房间中通过 [`m.space.child`](#mspacechild) 状态事件,或在子房间中通过 [`m.space.parent`](#mspaceparent) 状态事件。 + +多数情况下,应同时定义子房间与父房间的关系,以便于发现空间及其内容。仅使用 `m.space.child` 时,空间实质上就像一个由空间管理者精心挑选的房间列表,而房间本身可能并不知晓被包含其中。仅使用 `m.space.parent` 时,房间则会被“秘密”添加到空间中,而不会被空间直接宣传。 + +{{% boxes/warning %}} +鉴于空间本身就是房间,因此可以在空间中嵌套空间,也存在创建环路(循环)的可能。尽管明确禁止创建循环,实际实现时仍可能遇到这种情况,必须注意避免无限循环。 + +客户端及服务器还需警惕树结构过长,以免带来性能问题。 +{{% /boxes/warning %}} + +##### `m.space.child` 关系 + +采用此方法时,状态事件发送至作为父房间的空间房间,事件的 `state_key` 为子房间的ID。 + +例如,实现以下结构: + +``` +#space:example.org + #general:example.org (!abcdefg:example.org) + !private:example.org +``` + +则 `#space:example.org` 的状态为: + +*为简明起见,省略无关字段。* + +```json +{ + "type": "m.space.child", + "state_key": "!abcdefg:example.org", + "content": { + "via": ["example.org"] + } +} +``` +```json +{ + "type": "m.space.child", + "state_key": "!private:example.org", + "content": { + "via": ["example.org"] + } +} +``` + +子房间本身无需任何状态事件(当然也可以存在)。如此,用户可以无需房间版主/管理员明确授权,定义个人/私有空间组织自己的房间。 + +通过在相关状态事件的 `content` 中省略 `via` 键(如通过撤回或清空 `content`),可将子房间从空间中移除。 + +{{% event event="m.space.child" %}} + +###### 空间内子项排序 + +当客户端展示空间的子项时,应按照以下算法排序。在部分场景(如传统的左侧房间列表),客户端可能会覆盖排序规则以提升用户体验。但理论上的空间摘要视图会显示有序的子项。 + +对于空间的所有子项,先将带有有效 `order` 键的子项按照 Unicode 码点字典序排序,使得 `\x20`(空格)在 `\x7E`(`~`)之前。再将剩余未定义 `order` 的子项按其 `m.space.child` 事件的 `origin_server_ts` 时间戳升序排列,置于前者之后。 + +若 `order` 值相同,则按事件时间戳排序。若时间戳也相同,则按照房间ID(即 state key)升序字典序排列。 + +注意此处对 ASCII 空格的精确用法,以下为一组空间子项的合理排序示例: + +*为简明起见,省略无关字段。* + +```json +[ + { + "type": "m.space.child", + "state_key": "!b:example.org", + "origin_server_ts": 1640341000000, + "content": { + "order": " ", + "via": ["example.org"] + } + }, + { + "type": "m.space.child", + "state_key": "!a:example.org", + "origin_server_ts": 1640141000000, + "content": { + "order": "aaaa", + "via": ["example.org"] + } + }, + { + "type": "m.space.child", + "state_key": "!c:example.org", + "origin_server_ts": 1640841000000, + "content": { + "order": "first", + "via": ["example.org"] + } + }, + { + "type": "m.space.child", + "state_key": "!e:example.org", + "origin_server_ts": 1640641000000, + "content": { + "via": ["example.org"] + } + }, + { + "type": "m.space.child", + "state_key": "!d:example.org", + "origin_server_ts": 1640741000000, + "content": { + "via": ["example.org"] + } + } +] +``` + +1. `!b:example.org` 排在最前,因为 `\x20` 字典序在 `aaaa` 之前。 +2. `!a:example.org` 紧随其后,因为 `aaaa` 字典序在 `first` 之前。 +3. `!c:example.org` 接下来,因为 `first` 是最后一个 `order` 值。 +4. `!e:example.org` 其后,因为其事件时间戳最小。 +5. `!d:example.org` 最后,因为其事件时间戳最大。 + +##### `m.space.parent` 关系 + +房间还可以通过在自身状态中添加父房间事件来声明属于某个空间。类似空间中的子事件,父事件的 `state_key` 是父空间的房间ID,`content` 中的 `via` 列表用于说明链接是否有效,以及可通过哪些服务器加入。 + +为避免房间伪称属于某空间,`m.space.parent` 事件在下列任一条件满足时才应被接受: + +* 在设定为父空间的房间中可找到对应的 `m.space.child` 事件。 +* `m.space.parent` 事件的发送者在该父空间拥有足够权限可发送 `m.space.child` 状态事件(无需确有对应子事件存在)。 + +{{% boxes/note %}} +如客户端尚未加入父空间,可能需要窥探父空间房间状态。若客户端无法窥探,则应认为链接无效。 +{{% /boxes/note %}} + +{{% boxes/note %}} +第二个条件的后果是:若房间管理员在父空间内被降权、退出或被移除父空间,则之前合法的 `m.space.parent` 事件可能变为无效。 +{{% /boxes/note %}} + +`m.space.parent` 事件的 `content` 可包含布尔值 `canonical`,表示该父空间为该房间的主空间。例如可用于让客户端通过窥探该空间发现其他相关房间并向用户推荐。只能有一个主(canonical)父空间,尽管这一点没有强制约束。若有冲突,采用 Unicode 码点升序排序的最小房间ID进行决议。 + +{{% event event="m.space.parent" %}} + +#### 在空间中发现房间 + +客户端常需帮助用户探索某空间包含哪些房间/空间。可通过在客户端中遍历该空间的 [`m.space.child`](#mspacechild) 状态事件并窥探房间以获取名称等信息,然而这种方式在大多数场景下并不实用。 + +为此,提供了一个层级API以深度优先方式遍历空间树并发现带美观细节的房间信息。 + +[`GET /hierarchy`](#get_matrixclientv1roomsroomidhierarchy) API 按深度优先方式工作:遇到子项为空间时将递归至该空间,然后返回非空间子房间。 + +{{% boxes/warning %}} +循环虽被禁止,但仍有可能出现。服务器应优雅地中断循环。 + +此外,某个子房间(例如作为孙子房间)可能多次出现在响应中。 +{{% /boxes/warning %}} + +{{% http-api spec="client-server" api="space_hierarchy" %}} + +##### 服务器行为 + +当服务器无法获取子房间状态时,可通过联邦接口 +[`GET /hierarchy`](/server-server-api/#get_matrixfederationv1hierarchyroomid) 请求所需信息。该端点响应应在一段时间内做缓存。响应还可包含请求用户已加入或本地服务器已知的房间信息——本地数据应优先于远端服务器数据。 + +请注意,返回客户端的响应基于用户上下文。建议服务器对数据做短暂缓存,但仍须进行权限校验以确保响应对于该用户的准确性。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/sso_login.md b/locales/zh-Hans/client-server-api/modules/sso_login.md new file mode 100644 index 00000000..968a727b --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/sso_login.md @@ -0,0 +1,177 @@ +### SSO 客户端登录/认证 + +单点登录(Single Sign-On, SSO)是一个通用术语,指的是允许用户通过单一的基于 Web 的认证门户登录应用程序的协议。例如 OpenID Connect、“中央认证服务”(CAS)以及 SAML。 + +本模块允许 Matrix 主服务器将用户认证委托给支持这些协议之一的外部认证服务器。在此过程中,涉及三个系统: + +- 一个使用本规范定义的 API 的 Matrix 客户端,它试图将用户认证至 Matrix 主服务器。 +- 一个实现了本规范所定义 API 的 Matrix 主服务器,但其用户认证委托给了认证服务器。 +- 一个“认证服务器”,负责对用户进行认证。 + +本规范只关注 Matrix 客户端与主服务器之间的通信,与用于与认证服务器通信的 SSO 协议无关。不同的 Matrix 主服务器实现可能支持不同的 SSO 协议。 + +实现 SSO 流程的客户端和主服务器需要同时考虑 [登录](#login) 和 [用户交互式认证](#user-interactive-authentication-api)。两个过程类似,但存在细微差异。 + +通常,SSO 系统要求在认证服务器上配置一个“回调”URI。用户完成认证后,浏览器会被重定向到该 URI。Matrix 主服务器的实现需提供合适的端点。例如,对于 CAS 认证,主服务器应为管理员提供配置 CAS 服务器及消费票据的 REST 端点的方法。 + +主服务器可以选择性地向用户显示多个可选的 SSO 选项,通常以多个“使用 $provider 登录”按钮的形式展示。这些被称为“身份提供者”(IdPs)。 + +#### 客户端通过 SSO 登录 + +流程概述如下: + +1. Matrix 客户端调用 [`GET /login`](/client-server-api/#get_matrixclientv3login),以查询支持的登录类型,主服务器在响应中包含带有 `"type": "m.login.sso"` 的流程。 +2. 为发起 `m.login.sso` 登录类型,Matrix 客户端引导用户浏览器跳转至用户主服务器上的 [`/login/sso/redirect`](/client-server-api/#get_matrixclientv3loginssoredirect) 端点。若用户选择了某个 `identity_providers`,则可能是该端点的 IdP 版本。 +3. 主服务器以 HTTP 重定向响应至 SSO 用户界面,浏览器跟随重定向。 +4. 认证服务器与主服务器交互,验证用户身份及其他认证信息,过程中可能涉及多次重定向。 +5. 浏览器被引导至客户端提供的 `redirectUrl`,并带有 `loginToken` 查询参数,供客户端登录使用。 +6. 客户端通过携带 `type` 为 `m.login.token` 的 [`/login`](/client-server-api/#post_matrixclientv3login) 端点调用,用登录令牌换取访问令牌。 + +对于原生应用,1 至 4 步通常通过打开嵌入式 Web 视图实现。 + +流程如下图所示: + +``` + Matrix 客户端 Matrix 主服务器 认证服务器 + | | | + |-------------(0) GET /login------->| | + |<-------------登录类型--------------| | + | | | + | Webview | | + | | | | + |----->| | | + | |--(1) GET /login/sso/redirect-->| | + | |<---------(2) 302----------------| | + | | | | + | |<========(3) 认证流程==============>| | + | | | | + | |<--(4) 重定向到 redirectUrl--| | + |<-----| | | + | | | + |---(5) POST /login (携 login token)->| | + |<-------------访问令牌---------------| | +``` + +{{% boxes/note %}} +在此规范的旧版 [r0.4.0 +版本](https://matrix.org/docs/spec/client_server/r0.4.0.html#cas-based-client-login) 中,如果主服务器提供 `m.login.cas` 登录流程,则可以通过 CAS 认证。本规范废弃了 `m.login.cas` 的使用,转而推荐使用 `m.login.sso`,其过程相同,仅区别在于重定向端点:对于 `m.login.cas`,使用 `/cas/redirect`,对于 `m.login.sso`,使用 `/sso/redirect`(见下文)。其他端点保持一致。 +{{% /boxes/note %}} + +{{% definition path="api/client-server/definitions/sso_login_flow" %}} + +##### 客户端行为 + +客户端通过引导浏览器跳转至 [`/login/sso/redirect`](/client-server-api/#get_matrixclientv3loginssoredirect) +(或使用某个 `identity_providers` 时跳转至 [`/login/sso/redirect/{idpId}`](/client-server-api/#get_matrixclientv3loginssoredirectidpid)) +并携带适当的 `redirectUrl` 启动流程。认证成功后,浏览器将被重定向至该 `redirectUrl`。 + +{{% http-api spec="client-server" api="sso_login_redirect" %}} + +###### 安全注意事项 + +1. 通过操控 `redirectUrl` 参数进行的 CSRF 攻击 + + 客户端应校验对 `redirectUrl` 的任何请求。攻击者可能伪造查询参数,导致跨站请求伪造(CSRF)攻击。 + + 例如,假设一个 Web 客户端托管于 + `https://client.example.com`,希望在主服务器 [服务器名称](/appendices/#server-name) 为 `server.example.org` 上发起 SSO 登录,其通过在 `redirectUrl` 查询参数中存储服务器名实现重定向: + `https://server.example.org/login/sso/redirect?redirectUrl=https://client.example.com?hs=server.example.org`。 + + 攻击者可能诱导受害者访问 + `https://server.example.org/login/sso/redirect?redirectUrl=https://client.example.com?hs=evil.com`,导致客户端将登录令牌发送到攻击者控制的 `evil.com`。 + + 为防范此类风险,客户端不得将状态(如登录主服务器的地址)存储于任何可能被外部进程修改的位置。 + + 状态应存储在 [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) 或 Cookie 中。 + +2. 为进一步安全,客户端应在 `redirectUrl` 中携带唯一标识符,并拒绝不含已知标识符的回调,以防未授权登录尝试和重放攻击。 + +##### 服务器行为 + +服务器应注意,`identity_providers` 是可选的,较老的客户端可能无法正确解析该值。在这些情况下,客户端将使用通用的 `/redirect` 端点,而不是 `/redirect/{idpId}` 端点。 + +###### 重定向到认证服务器 + +服务器应如下处理 `/_matrix/client/v3/login/sso/redirect`: + +1. 构建适合 SSO 系统的请求。 +2. 存储足够的状态信息,以便在 SSO 流程完成后能够安全恢复流程。可通过为用户浏览器设置 Cookie 的方式完成,即在响应头中添加 `Set-Cookie`。 +3. 将用户浏览器重定向到 SSO 登录页,并带上合适参数。 + +另请参见下方“安全注意事项”。 + +###### 处理认证服务器回调 + +通常,会有一个回调 URI 同时用于登录与用户交互式认证,由主服务器实现区分当前流程。 + +主服务器应验证来自 SSO 系统的响应:这可能需要对认证服务器发起附加调用,和/或验证响应中的签名。 + +主服务器后续操作如下: + +1. 主服务器必须将认证服务器收到的用户详细信息映射为合法的 [Matrix 用户标识符](/appendices#user-identifiers)。可参见 [其他字符集的映射](/appendices#mapping-from-other-character-sets) 指南。 +2. 若生成的用户标识符为新用户,则应注册为新用户。 +3. 主服务器应生成一个短期登录令牌(login token)。这是一个不透明令牌,可用于以 `m.login.token` 类型调用 [`/login`](/client-server-api/#post_matrixclientv3login) API。令牌有效期建议限制在五秒左右。 +4. 主服务器在最初的 `/_matrix/client/v3/login/sso/redirect` 请求所带的 `redirectUrl` 上,添加名为 `loginToken` 的查询参数,值为生成的登录令牌。(注意:`redirectURL` 可能含有已有的查询参数。若已存在一个或多个 `loginToken` 参数,应先移除后再添加新的。) +5. 主服务器将浏览器重定向到构建完成的 URI。 + +##### 安全注意事项 + +1. 主服务器应确保登录令牌不会发送给恶意客户端。 + + 例如,假设主服务器为 `server.example.org`。攻击者诱导受害者点击 + `https://server.example.org/login/sso/redirect?redirectUrl=https://evil.com`,结果导致登录令牌发送至攻击者控制的 `evil.com`,这属于 CSRF 攻击。 + + 为缓解风险,主服务器在处理 `/_matrix/client/v3/login/sso/redirect` 端点时,重定向到 SSO 登录页前或在认证服务器回调后,应征得用户同意,将 Matrix 账号的访问权限授予 `redirectUrl` 指定的站点。 + + 可以设置信任白名单,仅允许已知受信任的客户端 URL。主服务器自身的 [登录回退](#login-fallback) 实现可排除在外。 + +2. 为进一步安全,主服务器可追踪待处理请求,防止未授权认证。可通过在处理 `/_matrix/client/v3/login/sso/redirect` 时设置 Cookie,并在从认证服务器回调时校验并清除该 Cookie 实现。 + +#### 用户交互式认证中的 SSO + +[用户交互式认证](#user-interactive-authentication-api) 适用于客户端-服务器端点,需要对用户身份进行额外确认(超出持有访问令牌以外)。通常情况下用户需要重新输入密码,但对于将认证委托给 SSO 服务器的主服务器,这意味着在用户交互式认证过程中重定向到认证服务器。 + +该实现基于用户交互式认证的 [回退](#fallback) 机制。 + +#### 客户端行为 + +客户端除确保实现回退机制,并将 `m.login.sso` 类型认作任意未知类型外,无需额外操作,即应为 +`/_matrix/client/v3/auth/m.login.sso/fallback/web?session=` +打开浏览器窗口。流程完成后,客户端仅携带 session 重新尝试请求。 + +#### 服务器行为 + +##### 重定向至认证服务器 + +服务器应以类似于 `/_matrix/client/v3/login/sso/redirect` 的方式处理 +`/_matrix/client/v3/auth/m.login.sso/fallback/web`: + +1. 构建适合 SSO 系统的请求。 +2. 存储足够的状态信息,以便在 SSO 流程完成后能够安全恢复流程。可通过为用户浏览器设置 Cookie 的方式实现,即在响应头设置 `Set-Cookie`。 +3. 将用户浏览器重定向到 SSO 登录页,并携带适当参数。 + +另请参阅下方“安全注意事项”。 + +###### 处理来自认证服务器的回调 + +通常,会有单一回调 URI 同时用于登录和用户交互式认证,由主服务器确定当前流程。 + +主服务器应对来自 SSO 系统的响应进行验证:这可能需要对认证服务器进行额外调用,和/或验证响应的签名。 + +随后主服务器向用户浏览器返回[用户交互式认证回退完成](#fallback)页面。 + +###### 安全注意事项 + +1. 操作确认 + + 主服务器应确认用户同意继续操作。用户交互式认证的目标是防止被盗用的 `access_token` 用于接管用户账号。仅重定向到 SSO 系统远远不够,因为用户可能尚未意识到正在进行的操作,或 SSO 系统可能会自动确认认证。 + + 例如,主服务器可向用户展示类似如下内容的页面: + + > 某客户端正在尝试从您的账户移除设备。请通过单点登录重新认证以确认此操作。如果此操作并非您本人发起,请警惕您的账户可能被盗用! + + 此操作确认可发生在重定向到 SSO 认证页前(处理 `/_matrix/client/v3/auth/m.login.sso/fallback/web` 端点时)、或认证服务器回调后。如果在认证前确认,尤其要防范下述未授权认证尝试。 + +2. 为进一步安全,主服务器应追踪待处理请求,防止未授权认证。例如可在处理 + `/_matrix/client/v3/auth/m.login.sso/fallback/web` + 时设置 Cookie,并在认证服务器回调时校验并清除该 Cookie。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/stickers.md b/locales/zh-Hans/client-server-api/modules/stickers.md new file mode 100644 index 00000000..08bd00e2 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/stickers.md @@ -0,0 +1,21 @@ +### 贴纸消息 + +该模块允许用户在房间或直接消息会话中发送贴纸消息。 + +贴纸消息是一种特殊的图片消息,展示时不带有控件(例如,不会显示“下载”链接,或在点击时以灯箱方式显示,如 [m.image](#mimage) 事件中所示)。 + +贴纸消息旨在在消息时间线上提供简单的“反馈”事件。Matrix 客户端应提供某种机制,以显示贴纸的“body”,例如在悬停时作为工具提示显示,或在点击贴纸图片时以弹窗形式展示。 + +#### 事件 + +贴纸事件以单个 `m.sticker` 事件的形式,在房间的 `timeline` 部分,通过 [`/sync`](#get_matrixclientv3sync) 接收。 + +{{% event event="m.sticker" %}} + +#### 客户端行为 + +支持此消息类型的客户端应直接在时间线中展示事件 URL 指向的图片内容。 + +应在 `info` 对象中提供缩略图图片。这主要是为那些尚未完全支持 `m.sticker` 事件类型的客户端提供的降级方案。在大多数情况下,将缩略图 URL 设为与主事件内容相同的 URL 即可。 + +建议贴纸图片内容的大小为 512x512 像素或更小。图片文件的尺寸应为 `info` 对象中指定的理想展示尺寸的两倍,以便在高 DPI 屏幕上渲染更清晰的图像。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/tags.md b/locales/zh-Hans/client-server-api/modules/tags.md new file mode 100644 index 00000000..d57e7b6f --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/tags.md @@ -0,0 +1,33 @@ +### 房间标签 + +用户可以为房间添加标签。标签是带有命名空间的字符串,用于标记房间。一个房间可以有多个标签。标签仅对设置它们的用户可见,但会在该用户的所有设备之间同步。 + +#### 事件 + +房间上的标签通过房间的 `account_data` 部分中的单个 `m.tag` 事件接收。`m.tag` 事件的内容包含一个 `tags` 键,其值是一个对象,将每个标签的名称映射到另一个对象。 + +与每个标签关联的 JSON 对象包含关于该标签的信息,例如如何对带有某一标签的房间进行排序。 + +排序信息通过 `order` 键给出,值为介于 0 到 1 之间的数字。数字比较时,0 会最先显示。因此,`order` 为 `0.2` 的房间将显示在 `order` 为 `0.7` 的房间之前。如果房间拥有某标签但未包含 `order` 键,则应排在具有该标签且含有 `order` 键的房间之后。 + +标签的名称不得超过 255 字节。 + +标签的命名空间定义如下: + +- `m.*` 命名空间保留用于 Matrix 协议中定义的标签。客户端必须忽略这一命名空间中自己不支持的标签。 +- `u.*` 命名空间保留给用户自定义的标签。`u.` 之后的字符串定义为该标签的显示名称。客户端不应从该命名空间的标签推断除显示名之外的含义。 +- 客户端或应用如果需使用特殊标签以实现高级功能,应参照 state key 方式使用命名空间,例如:`tld.name.*` +- 任何以 `tld.name.*` 形式出现但与当前客户端命名空间不匹配的标签都应被忽略 +- 不符合上述规则的标签应被解释为来自 `u.*` 命名空间的用户标签,视为其名称前已被去掉 `u.`(即标签的名称直接作为显示名)。这些无命名空间的标签是出于历史原因而被支持。新标签应当使用上述定义的命名空间之一。 + +协议中列出了一些特殊的标签名称:以下标签被定义在 `m.*` 命名空间下: + +- `m.favourite`:用户收藏的房间。应当优先于其他房间显示。 +- `m.lowpriority`:应当低于其他房间显示优先级。 +- `m.server_notice`:用于标识[服务器通知房间](#server-notices)。 + +{{% event event="m.tag" %}} + +#### 客户端行为 + +{{% http-api spec="client-server" api="tags" %}} \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/third_party_invites.md b/locales/zh-Hans/client-server-api/modules/third_party_invites.md new file mode 100644 index 00000000..ea275cdc --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/third_party_invites.md @@ -0,0 +1,163 @@ +### 第三方邀请 + +本模块为邀请新成员加入房间提供了支持,即使对方的 Matrix 用户 ID 未知,也可以通过第三方标识符(如电子邮件地址)进行邀请。此处包含两种流程:一种是已知该第三方标识符对应的 Matrix 用户 ID,另一种是未知。无论哪种情况,客户端都通过 [`/invite`](#post_matrixclientv3roomsroomidinvite) 接口并提供第三方标识符的详细信息来发起邀请。 + +主服务器会向身份服务器查询该标识符是否对应已知的 Matrix 用户 ID: + +- 如果已知,则直接向该用户发出邀请。 +- 如果未知,主服务器会请求身份服务器记录该邀请的详细信息,并在未来为该标识符分配绑定时通知被邀请者的主服务器有待处理的邀请。身份服务器会向发起邀请的主服务器返回一个令牌和公钥。 + +当被邀请者的主服务器收到绑定通知时,应在房间的事件图中插入一个 `m.room.member` 事件,其中 `content.membership` 为 `invite`,同时包含一个 `content.third_party_invite` 属性,以证明被邀请者确实拥有该第三方标识符。更多信息请参见 [m.room.member](#mroommember) 事件架构说明。 + +#### 事件 + +{{% event event="m.room.third_party_invite" %}} + +#### 客户端行为 + +客户端通过第三方标识符请求服务器邀请用户。 + +{{% http-api spec="client-server" api="third_party_membership" anchor_base="thirdparty" %}} + +#### 服务器行为 + +在收到 [`/invite`](#post_matrixclientv3roomsroomidinvite) 请求后,服务器需要使用指定的身份服务器查询第三方标识符。如果查询结果返回了 Matrix 用户 ID,则可以启动标准的邀请流程。该流程如下所示: + +``` + +---------+ +-------------+ +-----------------+ + | 客户端 | | 主服务器 | | 身份服务器 | + +---------+ +-------------+ +-----------------+ + | | | + | POST /invite | | + |----------------------------------->| | + | | | + | | GET /lookup | + | |--------------------------------------------------->| + | | | + | | 用户 ID 结果 | + | |<---------------------------------------------------| + | | | + | | 对发现的用户 ID 启动邀请流程 | + | |------------------------------------------ | + | | | | + | |<----------------------------------------- | + | | | + | 完成 /invite 请求 | | + |<-----------------------------------| | + | | | +``` + +然而,如果查询结果没有返回已绑定的用户 ID,主服务器必须将邀请信息存储在身份服务器上,并向房间发出有效的 `m.room.third_party_invite` 事件。该流程如下所示: + +``` + +---------+ +-------------+ +-----------------+ + | 客户端 | | 主服务器 | | 身份服务器 | + +---------+ +-------------+ +-----------------+ + | | | + | POST /invite | | + |----------------------------------->| | + | | | + | | GET /lookup | + | |------------------------------------------------------------>| + | | | + | | “无用户” 结果 | + | |<------------------------------------------------------------| + | | | + | | POST /store-invite | + | |------------------------------------------------------------>| + | | | + | | m.room.third_party_invite 事件所需信息 | + | |<------------------------------------------------------------| + | | | + | | 向房间发出 m.room.third_party_invite 事件 | + | |------------------------------------------- | + | | | | + | |<------------------------------------------ | + | | | + | 完成 /invite 请求 | | + |<-----------------------------------| | + | | | +``` + +所有主服务器必须验证事件中 `content.third_party_invite.signed` 对象的签名。 + +第三方用户随后需要验证其身份,这将使身份服务器调用主服务器,将该第三方标识符绑定到用户的主服务器。此时,主服务器会将房间中的 `m.room.third_party_invite` 事件替换为该用户的完整 `membership: invite` 的 `m.room.member` 事件。 + +如果主服务器是通过 `m.room.third_party_invite` 首次加入某个房间,则已在该房间中的服务器(根据标准服务器间协议选定)必须校验用于签名的公钥仍然有效,方法即如上文所述检查 `key_validity_url`。 + +其他主服务器不得仅因 `key_validity_url` 拒绝房间加入请求,这是为了确保所有主服务器都能获得一致的房间视图。但主服务器可以向其客户端指出成员的成员资格可能存在疑问。 + +例如,假设 H1、H2、H3 为主服务器,UserA 是 H1 的用户,身份服务器为 IS,第三方邀请的完整流程如下图所示。图中假定 H1、H2 已在房间,H3 尝试加入。 + +``` + +-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+ + | UserA | | 第三方用户 | | H1 | | H2 | | H3 | | IS | + +-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+ + | | | | | | + | POST /invite 针对第三方用户 | | | | + |--------------------------------->| | | | + | | | | | | + | | | GET /lookup | | | + | | |---------------------------------------------------------------------------------------------->| + | | | | | | + | | | | 查询结果(空对象) | + | | |<----------------------------------------------------------------------------------------------| + | | | | | | + | | | POST /store-invite | | | + | | |---------------------------------------------------------------------------------------------->| + | | | | | | + | | | | 第三方邀请生成的令牌、公钥等 | + | | |<----------------------------------------------------------------------------------------------| + | | | | | | + | | | (联邦)向房间发出 m.room.third_party_invite | | | + | | |----------------------------------------------->| | | + | | | | | | + | 完成 /invite 请求 | | | | + |<---------------------------------| | | | + | | | | | | + | | 验证身份 | | | | + | |-------------------------------------------------------------------------------------------------------------------->| + | | | | | | + | | | | | POST /3pid/onbind | + | | | | |<---------------------------| + | | | | | | + | | | PUT /exchange_third_party_invite/:roomId | | + | | |<-----------------------------------------------------------------| | + | | | | | | + | | | 验证该请求 | | | + | | |------------------- | | | + | | | | | | | + | | |<------------------ | | | + | | | | | | + | | | (联邦)发出 m.room.member 邀请 | | | + | | |----------------------------------------------->| | | + | | | | | | + | | | | | | + | | | (联邦)将 m.room.member 事件发送给 H2 | | + | | |----------------------------------------------------------------->| | + | | | | | | + | | | 完成 /exchange_third_party_invite/:roomId 请求 | | + | | |----------------------------------------------------------------->| | + | | | | | | + | | | | | 加入房间 | + | | | | |------------------------ | + | | | | | | | + | | | | |<----------------------- | + | | | | | | +``` + +注意当 H1 向 H2 和 H3 发送 `m.room.member` 事件时,H1 不需要等待任何服务器确认收到该事件。同样,H1 可以在向 H2、H3 发送 `m.room.member` 事件的同时完成 [`/exchange_third_party_invite`](/server-server-api/#put_matrixfederationv1exchange_third_party_inviteroomid) 请求。另外,H3 可以在任意时刻完成其从 IS 接收到的 [`/3pid/onbind`](/server-server-api/#put_matrixfederationv13pidonbind) 请求——此流程中的完成未在图中展示。 + +H1 必须校验来自 H3 的请求,确保 `signed` 属性正确,且 `key_validity_url` 仍有效。此操作需向 [身份服务器 /isvalid](/identity-service-api/#get_matrixidentityv2pubkeyisvalid) 端点发起请求,且应使用已提供的 URL 而非自行构造。查询字符串和返回值必须符合身份服务规范。 + +不允许其他主服务器仅基于校验 `key_validity_url` 的结果拒绝事件,因为我们必须保证事件的接受方式具备确定性。如果某些参与服务器无法连接到密钥服务器、密钥服务器宕机或吊销密钥,则其他服务器会拒绝该事件,导致参与服务器的事件图发生分歧。此行为依赖参与服务器间的信任,但该信任已通过服务器间协议隐含。此外,还必须完成公钥签名验证,从而最大限度减少攻击面。 + +#### 安全性考虑 + +本模块涉及若干隐私和信任问题。 + +为保护用户隐私,必须强力防止 Matrix 用户 ID 与第三方标识符之间的映射泄露。尤其是,应尽量阻止通过 Matrix 用户 ID 查找所有第三方标识符(从而能够关联各第三方标识符)。为此,任何事件都不会直接包含第三方标识符,而是采用由身份服务器提供的不透明显示名称。客户端不应因邀请而记住或显示第三方标识符,仅限于邀请方自身的使用。 + +主服务器不需要信任特定的身份服务器。一般而言,由客户端自行决定信任哪些身份服务器,而非主服务器决定。因此,此 API 从最终用户处获取身份服务器,并未指定受信任服务器集。当然,一些主服务器可能会为其用户提供默认配置或拒绝个别身份服务器,但主服务器无权对其他主服务器的用户信任哪些身份服务器进行干预。 + +身份服务器或主服务器可能因收到大量请求或存储大量状态而面临拒绝服务攻击风险。如何防御此类风险由实现方自行决定。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/third_party_networks.md b/locales/zh-Hans/client-server-api/modules/third_party_networks.md new file mode 100644 index 00000000..321f4984 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/third_party_networks.md @@ -0,0 +1,9 @@ +### 第三方网络 + +应用服务可以通过桥接提供对第三方网络的访问。这使得 Matrix 用户能够与其他通信平台上的用户进行交流,消息由应用服务在双方之间传递。单个应用服务可以桥接多个第三方网络,以及这些网络中的许多具体位置。单个第三方网络位置可以桥接到多个 Matrix 房间。 + +#### 第三方查找 + +客户端可能希望为加入第三方位置和连接第三方用户提供丰富的界面。实现此类界面所需的信息由第三方查找功能提供。 + +{{% http-api spec="client-server" api="third_party_lookup" %}} \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/threading.md b/locales/zh-Hans/client-server-api/modules/threading.md new file mode 100644 index 00000000..d845cda5 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/threading.md @@ -0,0 +1,169 @@ +### 线程 + +{{% added-in v="1.4" %}} + +线程允许用户在一个房间中以可视方式分支他们的对话。通常在线上讨论多个主题时使用,线程相较于传统的 [富回复](#rich-replies) 能够提供更有组织的交流方式,而富回复未必能够兼顾所有场景。 + +客户端应当在时间线上以区别于普通消息或回复的方式渲染线程,例如为线程提供一些上下文信息,但将完整的对话历史隐藏于可展开内容之后。 + +线程通过 `rel_type` 设为 `m.thread` 来建立,并引用 *线程根*(即该线程事件所指向的主时间线事件)。无法从本身已是事件关系子事件(即带有 `m.relates_to` 和 `rel_type` 属性的事件,参考 [关系类型](#relationship-types))创建线程。因此,线程也无法嵌套。 + +与富回复链不同,线程中的所有事件都引用线程根,而不是最新的消息。 + +下面通过示例展示线程及其形成方式: + +```json +{ + // 已省略无关字段 + "type": "m.room.message", + "event_id": "$alice_hello", + "sender": "@alice:example.org", + "content": { + "msgtype": "m.text", + "body": "Hello world! How are you?" + } +} +``` + +```json +{ + // 已省略无关字段 + "type": "m.room.message", + "event_id": "$bob_hello", + "sender": "@bob:example.org", + "content": { + "m.relates_to": { + "rel_type": "m.thread", + "event_id": "$alice_hello" + }, + "msgtype": "m.text", + "body": "I'm doing okay, thank you! How about yourself?" + } +} +``` + +```json +{ + // 已省略无关字段 + "type": "m.room.message", + "event_id": "$alice_reply", + "sender": "@alice:example.org", + "content": { + "m.relates_to": { + "rel_type": "m.thread", + "event_id": "$alice_hello" // 注意:始终指向 *线程根* + }, + "msgtype": "m.text", + "body": "I'm doing great! Thanks for asking." + } +} +``` + +如上所示,任何没有 `rel_type` 的事件都可以仅通过 `m.thread` 关系被引用来成为线程根。 + +#### 非线程化客户端的回退机制 + +能够理解线程的客户端应直接以线程方式处理,但某些客户端(出于历史原因或功能范围限制)可能无法向用户有效展现对话历史。 + +为此,支持线程的客户端发送事件时应包含 [富回复](#rich-replies) 元数据,以尝试形成对话的回复链。这种方式在高线程活跃房间中并不理想,但可以为用户提供与房间内其他消息相关的上下文信息。 + +该兼容方式通过合并两种关系并为 `is_falling_back` 标记设为 `true` 实现。 + +```json +// 在事件内容中…… +"m.relates_to": { + // m.thread 关系结构 + "rel_type": "m.thread", + "event_id": "$root", + + // 富回复结构 + "m.in_reply_to": { + // 线程中客户端已知的最新消息,应选取其他客户端有较大渲染概率的事件, + // 如 `m.room.message` 事件。 + "event_id": "$target" + }, + + // 标记此事件为带回复回退的线程 + "is_falling_back": true +} +``` + +{{% boxes/note %}} +对于对线程有一定感知(即不直接渲染线程、但知道规范中有该功能)的客户端,可以将对带有 `rel_type` 为 `m.thread` 事件的富回复视作线程内部的回复,以实现线程客户端侧的对话连续性。 + +实现方法为:从被回复事件中复制出 `event_id`(线程根),添加 `m.in_reply_to` 元数据,并在 `m.relates_to` 中加入 `is_falling_back: true`。 +{{% /boxes/note %}} + +#### 线程内的回复 + +在 [非线程化客户端的回退机制](#fallback-for-unthreaded-clients) 部分,为 `m.relates_to` 新增了 `is_falling_back` 字段。当未提供该字段时,默认为 `false`,这同样允许线程消息本身作为回复。 + +除了 `is_falling_back` 为 `false`(或未指定)以外,客户端应利用非线程化客户端的回退机制在线程内创建回复,并据此渲染事件。 + +#### 服务器行为 + +##### `m.thread` 关系的验证 + +服务器应拒绝客户端针对带有 `m.relates_to` 属性的事件尝试发起线程的请求。如果客户端试图对带有 `m.relates_to` 属性的事件作为目标事件,则应返回 HTTP 400 错误及相应错误信息,按照 [标准错误响应](#standard-error-response) 结构处理。 + +{{% boxes/note %}} +此种情况目前没有单独的错误码:服务器应与 HTTP 400 一同返回 `M_UNKNOWN`。 +{{% /boxes/note %}} + +##### 服务器侧对 `m.thread` 关系的聚合 + +由于线程总是引用线程根,一个事件将拥有多个“子事件”,共同组成该线程。服务器应对这些事件进行 [聚合](#aggregations-of-child-events)。 + +线程聚合的数据包括用户在该线程中的参与情况、线程(服务器已知范围内)大致的事件数量,以及线程内最新(按服务器视角的拓扑顺序)的一条消息。 + +与任何其他子事件聚合一样,`m.thread` 聚合结果通过 `unsigned` 下的 `m.relations` 属性返回给线程根。例如: + +```json +{ + "event_id": "$root_event", + // 未显示无关字段 + "unsigned": { + "m.relations": { + "m.thread": { + "latest_event": { + // 线程中最新事件的序列化副本。 + // 部分字段为简化未示出。 + "event_id": "$message", + "sender": "@alice:example.org", + "room_id": "!room:example.org", + "type": "m.room.message", + "content": { + "msgtype": "m.text", + "body": "Woo! Threads!" + }, + "unsigned": { + "m.relations": { + // ... + } + } + }, + "count": 7, + "current_user_participated": true + } + } + } +} +``` + +`latest_event` 为线程中由未被[忽略的用户](#ignoring-users)发送,服务器视拓扑顺序最新的一条事件。 + +注意,正如上例,`latest_event` 的子事件本身也需被聚合并包含在该事件下的 `m.relations` 下。服务器需注意避免形成循环,尽管由于 `m.thread` 不允许指向带有 `m.relates_to` 属性的事件,目前不可能产生循环。 + +`count` 仅指向目标事件的 `rel_type` 为 `m.thread` 的事件数量,未包含[被忽略用户](#ignoring-users)发送的事件。 + +`current_user_participated` 为 `true` 时,表明认证用户满足以下任一条件: +1. 是线程根事件的 `sender`; +2. 是某个引用线程根且 `rel_type` 为 `m.thread` 的事件的 `sender`。 + +#### 查询房间内线程 + +客户端如需获取某线程内的所有事件,可通过 +[`GET /relations/{threadRootId}/m.thread`](#get_matrixclientv1roomsroomidrelationseventidreltype); +如需获取某房间内所有线程,则需专用 API: + +{{% http-api spec="client-server" api="threads_list" %}} \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/typing_notifications.md b/locales/zh-Hans/client-server-api/modules/typing_notifications.md new file mode 100644 index 00000000..f28b5379 --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/typing_notifications.md @@ -0,0 +1,19 @@ +### 输入通知 + +用户可能希望在有人在房间中输入时收到通知。这可以通过输入通知实现。这些属于临时事件,因此不会成为[事件图](/#event-graphs)的一部分。输入通知的作用范围仅限于某个房间。 + +#### 事件 + +{{% event event="m.typing" %}} + +#### 客户端行为 + +当客户端接收到 `m.typing` 事件时,必须使用该事件中的用户 ID 列表来**替换**其当前所知的正在输入的所有用户。其原因在于服务器*不会记住*那些当前未在输入的用户,因为该列表增长得很快。客户端应将所有未在此列表中的用户 ID 标记为未输入状态。 + +建议客户端存储一个表示用户是否正在输入的 `boolean` 值。当该值为 `true` 时,应每隔 N 秒定时触发一次定时器,发送一次输入状态的 HTTP 请求。N 推荐值为 20-30 秒以内。客户端应不断重新发送此请求,以持续告知服务器用户仍在输入中。由于后续请求会取代旧的请求,建议在预期超时前留有 5 秒的安全余量。当用户停止输入时,将 `boolean` 状态变为 `false` 的变化应触发另一次 HTTP 请求,以告知服务器用户已停止输入。 + +{{% http-api spec="client-server" api="typing" %}} + +#### 安全性注意事项 + +客户端可能不希望通知房间内的所有人他们正在输入,而只通知房间内特定的用户。 \ No newline at end of file diff --git a/locales/zh-Hans/client-server-api/modules/voip_events.md b/locales/zh-Hans/client-server-api/modules/voip_events.md new file mode 100644 index 00000000..e8a3ba0a --- /dev/null +++ b/locales/zh-Hans/client-server-api/modules/voip_events.md @@ -0,0 +1,141 @@ +### 语音通信(VoIP) + +本模块描述了房间内两位用户如何建立语音通信(VoIP)通话。语音和视频通话均基于 WebRTC 1.0 标准构建。通话信令通过向房间发送[消息事件](#events)来实现。在本规范版本中,仅支持双方通信(如两点对两点,或点对多点会议设备)。虽然通话可在包含多位成员的房间中发起,但同一时间仅允许两台设备参与通话。 + +所有 VoIP 事件均包含一个 `version` 字段。该字段用于判断设备是否支持此新版本的协议。例如,客户端可利用该字段判断是否应期待来自对方的 `m.call.select_answer` 事件。如果客户端接收到的事件 `version` 字段不是 `0` 或 `"1"`(包括如数值型 `1`),则应视同其 `version` == `"1"` 处理。 + +需注意,这意味着未来任何版本的 VoIP 事件均应保持向后兼容性。如有必要引入非兼容性新规范,则将采用一套独立的事件类型。 + +#### 通话方标识符 +每当客户端首次参与新通话时,应为自身生成一个 `party_id`,在通话期间一直使用。此标识符应足够长,确保即使多设备同时生成应答,其间发生冲突的概率极低:建议使用 8 个大小写字母+数字字符。通话方通过 `(user_id, party_id)` 元组进行识别。 + +客户端将包含该 `party_id` 字段,并放置于所有 VoIP 事件内容的顶层,包括 `m.call.invite`。客户端用此字段识别自身事件的远端回显:由于用户可能与自己通话,无法简单地忽略来自自身用户的事件。此外,该字段还能区分不同客户端对同一邀请发出的不同应答,并将 `m.call.candidates` 事件与相应的应答/邀请进行匹配。 + +客户端实现可选择使用端到端加密中使用的设备 ID,用作此目的;或者可为每次通话生成不同 ID,以避免在未加密房间中泄露使用设备信息,或隐藏单一设备(即 Access Token)被用于多个通话方信令发送等信息。 + +`party_id` 的语法定义见[下文](#grammar-for-voip-ids)。 + +#### 礼让规则 +根据 [WebRTC 完美协商示例](https://w3c.github.io/webrtc-pc/#perfect-negotiation-example),在重新协商过程中存在礼让(politeness)规则。被叫方始终为礼让方。在碰撞(glare)情况下,通话方的礼让状态由是采纳呼入通话还是主动呼叫决定:如果客户端舍弃本地呼出而采用呼入通话,则其为礼让方。 + +#### 通话事件存活性 +`m.call.invite` 中包含 `lifetime` 字段,指示邀约有效的时长。收到邀请后,客户端应结合事件同步响应中的 `age` 字段与自接收到该事件以来的时间,判断邀约是否依然有效。使用 `age` 字段可确保客户端设备错误时钟不会导致通话异常。 + +若邀约有效*且在用户可接受通话期间保持有效*,应提示有来电。用户可接受通话的时长可由不同客户端自行决定,例如在锁定的移动设备上,可以比在解锁的桌面设备上更长。 + +在处理完整个同步响应(sync response)并(对于加密房间)尝试解密该房间全部加密事件后,客户端才应提示来电。这样可以避免同步响应中含有随后指示通话已挂断、被拒绝或已被他处接听的事件时,重复提示来电。 + +若客户端启动后,在处理本地已存储事件后,发现仍有有效的邀约,应在与 homeserver 完成一次同步后再予以提示。 + +建议的最小有效时长为 90 秒——这样可确保用户有充足时间接听来电。 + +#### ICE 候选(Candidate)批量发送 +客户端应设法只发送少量候选事件,具体指引如下: + * 在邀请/应答事件本身中,应立即或几乎立即发现的 ICE 候选(例如 host 类型 candidate)。如能在短时间内收集到服务器反射或中继 candidate,应一并发送。建议初始延迟约 200ms。 + * 之后,客户端应等待一段时间以收集更多候选,实现批量发送,而非每获一个立刻发送。建议在发送邀请后等待 2 秒,或发送应答后等待 500ms(因发送邀请后,客户端本就等待用户接听,可利用此延迟)。 + +#### 结束候选通知(End-of-candidates) +值为空字符串的 ICE 候选表示不会再发送新的 ICE 候选。客户端必须在 `m.call.candidates` 消息中发送此类候选。虽然 WebRTC 规范要求浏览器生成此候选,但截止目前,并非所有浏览器都实现(Chrome 不生成,但会产生 `icegatheringstatechange` 事件)。候选生成结束时,客户端应立即发送全部候选,而不应再等待上文时间间隔。这可方便桥接到不支持逐步 ICE(trickle ICE)协议时对候选的批量处理。 + +#### DTMF +Matrix 客户端可按 WebRTC 规范发送 DTMF。截至 2020 年 8 月,WebRTC 标准尚不支持接收 DTMF,但 Matrix 客户端可接收并解析 RTP 负载中的 DTMF 信号。 + +#### VoIP 标识符的语法 + +`call_id` 和 `party_id` 必须遵循[不透明标识符语法](/appendices#opaque-identifiers)。 + +#### 离开房间时的行为 +若客户端检测到正在通话的用户离开房间,应将其视作所有正在进行中的通话的挂断事件。对于发送邀约而被邀请方离开房间的情形,规范未做硬性规定,但若房间内已无可接听用户,客户端可选择将其视作被拒绝(如仅剩发送方本人,或邀约的 `invitee` 字段被设置后未被接听)。 + +历史通话回溯时亦应如此处理。 + +#### 支持的编解码器 +Matrix 规范未强制指定特定音视频编解码器,完全遵循 WebRTC 规范。兼容的 Matrix VoIP 客户端将像被支持的“浏览器”一样,根据所支持的编解码器及其变体运作。需遵循最新的 WebRTC 规范版本,因此客户端应及时跟进 WebRTC 规范的新版本,无论 Matrix 规范是否变更。 + +#### 事件 + +##### 通用字段 + +{{% event-fields event_type="call_event" %}} + +##### 事件 + +{{% event-group group_name="m.call" %}} + +#### 客户端行为 + +通话建立流程如下,双方通过消息事件进行通信: + +``` + 呼叫方 被叫方 + [发起呼叫] + m.call.invite -----------> + m.call.candidate --------> + [..candidates..] --------> + [接听来电] + <--------------- m.call.answer + m.call.select_answer -----------> + [通话正在进行中] + <--------------- m.call.hangup +``` + +或通话被拒绝时: + +``` + 呼叫方 被叫方 + m.call.invite ------------> + m.call.candidate ---------> + [..candidates..] ---------> + [拒绝通话] + <-------------- m.call.hangup +``` + +通话协商遵循 WebRTC 规范进行。 + +面对来电,客户端可采取多种操作: + * 发送 `m.call.answer`,尝试接听通话。 + * 主动在所有设备上拒绝通话:如上图,发送 `m.call.reject`,则所有用户设备均停止响铃,并通知呼叫方其来电被拒。 + * 忽略通话:不发送任何事件,仅本地停止通话提示。用户的其他设备仍会继续响铃,呼叫方设备继续显示响铃,若无设备响应,通话将自动超时。 + +##### 多流(Streams) + +客户端可在一次 VoIP 通话中发送多路流。应通过在 [`m.call.invite`](/client-server-api/#mcallinvite)、[`m.call.answer`](/client-server-api/#mcallanswer) 以及 [`m.call.negotiate`](/client-server-api/#mcallnegotiate) 事件中加入 `sdp_stream_metadata` 属性来区分流。当元数据发生变更但无需重新协商时,可发送 [`m.call.sdp_stream_metadata_changed`](/client-server-api/#mcallsdp_stream_metadata_changed) 事件。 + +推荐客户端对于带 `audio_muted` 字段且值设为 true 的来流,不要本地关闭 WebRTC 音轨。这是因为当对方取消静音后,客户端发送音频与 [`m.call.sdp_stream_metadata_changed`](/client-server-api/#mcallsdp_stream_metadata_changed) 事件到达之间可能略有延迟,这段音频会被错过。对方静音后将停止发送音频,无需担心无意识的音频发送。 + +对于 `video_muted`,建议仍应本地关闭视频流,避免接收端看到黑屏。 + +如 `sdp_stream_metadata` 存在,但来流未被列在其中,应直接忽略。若某流用途未知(`purpose` 类型未知)也应忽略。 + +为保证兼容性,若对方首次发来的 [`m.call.invite`](/client-server-api/#mcallinvite) 或 [`m.call.answer`](/client-server-api/#mcallanswer) 缺少 `sdp_stream_metadata` 属性,客户端应假定对方不支持此属性,即无法区分多流,客户端仅应使用第一条来流,并勿发送多于一条。 + +实现本规范的客户端应忽略无流的轨道(streamless tracks)。 + +##### 被邀请方 + +若通话仅面向特定用户,`invitee` 字段应被加入,并设置为该用户的 Matrix ID。不含 `invitee` 字段的邀请,默认为面向房间内除发送者以外任何成员。 + +客户端在接收到未过期的邀请,`invitee` 字段缺失或等于本用户 Matrix ID 时,应视为有效来电,但是否响铃需根据与呼叫方关系和来电地点判定。建议客户端默认忽略来自公共房间的呼叫邀请。强烈建议即便未为来电响铃,客户端也应在房间中展示来电并标记其被忽略。 + +##### 通话碰撞(Glare) + +“通话碰撞”指两位用户几乎在同一时间互相呼叫对方,导致已有呼入/呼出通话而无法建立。可使用碰撞解决算法决定应挂断哪个通话,应接听哪个通话。如双方客户端实用相同算法,将会选择同一个通话,通话得以正常建立。 + +因通话目标为房间而非具体用户,以下碰撞解决算法仅适用于同一房间的通话: + +- 若客户端在准备发送 `m.call.invite` 至某房间时,收到了同一房间的 `m.call.invite`: + - 客户端应取消本地外呼,转而自动为用户接听来电。 +- 若客户端已向某房间发送 `m.call.invite` 并在等待响应时收到同房间的 `m.call.invite`: + - 客户端应对两个通话的 call_id 按字典序比较,保留较小者,挂断较大者;如来电为较小者,客户端应代表用户接听之。 + +对用户而言,通话建立过程应如同直接接通,无需察觉背后切换。任何初始化媒体流应当平滑迁移至被采纳的通话。 + +#### 服务器行为 + +Homeserver 可以(可选)向客户端提供 TURN 服务器信息,便于客户端通过 TURN 实现点对点通信。客户端可通过下述 HTTP API 获取 TURN 服务器信息。 + +{{% http-api spec="client-server" api="voip" %}} + +#### 安全性考量 + +通话仅应在仅有两位用户的房间发起。若在多人聊天室发起,其他用户可能会拦截并接听该通话。 \ No newline at end of file diff --git a/locales/zh-Hans/identity-service-api.md b/locales/zh-Hans/identity-service-api.md new file mode 100644 index 00000000..12595ffe --- /dev/null +++ b/locales/zh-Hans/identity-service-api.md @@ -0,0 +1,259 @@ +--- +title: "身份服务 API" +weight: 40 +type: docs +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +Matrix 的客户端-服务器与服务器-服务器 API 主要使用 Matrix 用户标识符。在某些情况下,我们需要以其他(“第三方”)标识符,或“3PID”(如电子邮件地址或电话号码)来引用用户。本身份服务规范描述了如何建立、验证和使用第三方标识符与 Matrix 用户标识符之间的映射。理论上,本规范可适用于任意 3PID,但实际上目前仅针对电子邮件地址和电话号码进行了具体实现。 + +## 基本原则 + +身份服务器的目的是验证、存储并响应有关用户身份的问题。具体来说,它存储如下关联:“标识符 X 与标识符 Y 代表同一用户”,其中这些身份可存在于不同系统(如电子邮件地址、电话号码、Matrix 用户 ID 等)中。 + +身份服务器拥有若干私钥-公钥对。当被查询某项关联时,它会使用其私钥对该关联的详细信息进行签名。客户端可通过验证身份服务器公钥的签名,来校验关于关联的声明。 + +通常情况下,身份服务器被视为可靠的权威。它们并不总能提供已验证关联的证据,但会声称已完成验证。具体信任哪台身份服务器,由客户端自行决定。 + +3PID 类型详见[3PID 类型](/appendices#3pid-types)附录。 + +## API 标准 + +Matrix 身份服务器通信的强制基线是通过 HTTP API 交换 JSON 对象。通信必须使用 HTTPS。 + +所有 `POST` 和 `PUT` 端点(出于历史原因,[`POST /_matrix/identity/v2/account/logout`](#post_matrixidentityv2accountlogout) 除外)都要求客户端在请求体中提交一个(可能为空的)JSON 对象。对于带有 JSON 请求体的请求,客户端应提供 `Content-Type: application/json` 头,但这非强制要求。 + +同样,所有端点都需返回 JSON 对象。服务器返回 JSON 时,必须包括 `Content-Type: application/json` 响应头。 + +所有请求或响应中的 JSON 数据,必须采用 UTF-8 编码。 + +### 标准错误响应 + +若在 Matrix API 层发生错误,必须返回“标准错误响应”。其格式为如下 JSON 对象: + +```json +{ + "errcode": "", + "error": "" +} +``` + +`error` 字符串为人类可读的错误信息,通常描述出错原因。`errcode` 字符串为唯一字符串,便于处理错误信息,如 `M_FORBIDDEN`。依据错误类型,可能含有其他键,但 `error` 和 `errcode` 两个键必须始终存在。 + +部分标准错误码如下: + +`M_NOT_FOUND` +请求的资源无法找到。 + +`M_MISSING_PARAMS` +请求缺少一个或多个参数。 + +`M_INVALID_PARAM` +请求包含一个或多个无效参数。 + +`M_SESSION_NOT_VALIDATED` +Session 尚未验证。 + +`M_NO_VALID_SESSION` +根据提供参数找不到相关 Session。 + +`M_SESSION_EXPIRED` +Session 已过期,需重新创建。 + +`M_INVALID_EMAIL` +提供的电子邮件地址无效。 + +`M_EMAIL_SEND_ERROR` +发送邮件时出错。通常发生在验证给定邮箱所有权时。 + +`M_INVALID_ADDRESS` +提供的第三方地址无效。 + +`M_SEND_ERROR` +发送通知时出错。通常见于验证第三方地址所有权时。 + +`M_UNRECOGNIZED` +请求中包含未识别的值,如未知的 token 或 medium。 + +当服务器无法理解请求时,也会使用此响应。若端点未实现,返回 HTTP 状态码 404;若实现了但使用了错误的 HTTP 方法,返回 405。 + +`M_THREEPID_IN_USE` +第三方标识符已被他人使用。该错误通常会包含额外的 `mxid` 字段,以标明该 3PID 的所有者。 + +`M_UNKNOWN` +发生未知错误。 + +## 隐私 + +身份信息关系隐私敏感。身份服务器存在的目的是提供身份信息,但访问应受到限制,以避免泄露潜在的敏感数据。尤其应避免构建大规模的身份关联网络。因此,API 通常允许将 3PID 映射到 Matrix 用户身份,但禁止反向映射(即不能查询某 Matrix 用户 ID 关联有哪些 3PID,也不能批量获取一个 3PID 关联的全部身份)。 + +## Web 浏览器客户端 + +部分客户端可能在 Web 浏览器或类似环境下运行。此时,身份服务器应响应预检(pre-flight)请求,并在所有请求中返回跨域资源共享(CORS)头。 + +当客户端以 OPTIONS 请求访问服务器时,服务器需返回对应路由的 CORS 头。建议服务器所有请求返回以下 CORS 头: + + Access-Control-Allow-Origin: * + Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS + Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization + +## API 版本检查 + +{{% http-api spec="identity" api="versions" %}} + +## 认证 + +身份服务 API 的大多数端点都要求认证,以确保请求用户已接受所有相关政策,并有权限发起请求。 + +身份服务器采用类似 Client-Server API 的访问令牌方案进行用户认证。身份服务器发放的访问令牌不能用于认证 Client-Server API 请求。 + +访问令牌可通过请求头以 Bearer 方式提供:`Authorization: Bearer TheTokenHere`。 + +客户端也可以(但不推荐)通过查询字符串参数提供访问令牌:`access_token=TheTokenHere`。为避免令牌泄漏到访问日志或 HTTP 日志,不推荐客户端再采用这种方式。 + +身份服务器必须同时支持这两种方式。 + +{{% boxes/note %}} +{{% changed-in v="1.11" %}} +通过查询字符串参数传递访问令牌已被弃用。 +{{% /boxes/note %}} + +若缺少或认证凭据无效,HTTP 响应为 401,错误码为 `M_UNAUTHORIZED`。 + +{{% http-api spec="identity" api="v2_auth" %}} + +## 服务条款 + +身份服务器建议配置服务条款(或类似政策),以确保用户同意服务器处理其数据。为此,身份服务器可以对几乎所有需认证的 API 端点返回 HTTP 403 和错误码 `M_TERMS_NOT_SIGNED`。该状态表明,用户需接受最新服务条款后才能继续操作。 + +所有支持认证的端点都可能返回 `M_TERMS_NOT_SIGNED` 错误。收到此错误后,客户端应调用 `GET /terms` 获取服务器提供的服务条款,并与用户的 `m.accepted_terms` 账号数据(下文介绍)进行比较,再向用户展示尚未接受的服务条款,并提供同意的选项。用户选择后(如适用),客户端调用 `POST /terms` 提交已接受的条款。服务器不可假定客户端会一次性提交所有待同意的条款,客户端也不可假定服务器接收到这些条款后就不会再次响应 `M_TERMS_NOT_SIGNED`。用户刚同意的条款会追加到 `m.accepted_terms`。 + +{{% event event="m.accepted_terms" %}} + +{{% http-api spec="identity" api="v2_terms" %}} + +## 状态检查 + +{{% http-api spec="identity" api="v2_ping" %}} + +## 密钥管理 + +身份服务器拥有若干长期公钥-私钥对。命名方式为 `算法:标识符`,如 `ed25519:0`。签名关联时,遵循标准的[签名 JSON](/appendices#signing-json)算法。 + +身份服务器还可以管理一些短期公私钥对,这些密钥的用途和生命周期可与长期密钥不同。 + +{{% http-api spec="identity" api="v2_pubkey" %}} + +## 关联查询 + +{{% http-api spec="identity" api="v2_lookup" %}} + +### 客户端行为 + +在执行查询前,客户端应优先请求 `/hash_details` 端点,确定服务器支持哪些算法(详见下文)。客户端获取该信息后,形成相应的 `/lookup` 请求以从服务器获取已知绑定关系。 + +客户端必须至少支持 `sha256` 算法。 + +### 服务器行为 + +服务器收到 `/lookup` 请求后,将查询与其已知的绑定比较,必要时对本地存储的标识进行哈希以确定是否与请求完全匹配。 + +服务器必须至少支持 `sha256` 算法。 + +### 算法 + +部分算法在规范中有定义;如有其他需求,客户端和服务器可通过 `/hash_details` 协商格式。 + +#### `sha256` + +客户端与服务器必须至少支持此算法,并且它也是推荐用于查询的算法。 + +采用此算法时,客户端将查询项转换为以空格分隔的字符串,格式为 `
`。`` 取自 `/hash_details`,`` 通常为小写 `email` 或 `msisdn`,`
` 即要查询的 3PID。例如,若客户端要查询 `alice@example.org` 的绑定关系,格式为 `alice@example.org email ThePepperGoesHere`。 + +{{% boxes/rationale %}} +将 medium 与 pepper 附加到 address,可避免每个 3PID 前缀相同,提升哈希函数抗预计算攻击能力。 +{{% /boxes/rationale %}} + +每条格式化字符串经 SHA-256(参见 [RFC 4634](https://tools.ietf.org/html/rfc4634))处理后,结果用 URL-Safe [Unpadded Base64](/appendices#unpadded-base64) 编码(与 [room version 4 的事件 ID 格式](/rooms/v4#event-ids) 类似)。 + +如使用 pepper `matrixrocks`,示例查询如下: + + "alice@example.com email matrixrocks" -> "4kenr7N9drpCJ4AfalmlGQVsOn3o2RHjkADUpXJWZUc" + "bob@example.com email matrixrocks" -> "LJwSazmv46n0hlMlsb_iYxI0_HXEqy_yj6Jm636cdT8" + "18005552067 msisdn matrixrocks" -> "nlo35_T5fzSGZzJApqu8lgIudJvmOQtDaHtr-I4rU7I" + +哈希后的字符串集作为 `/lookup` 请求体内的 `addresses` 数组。注意,使用的 pepper 必须通过 `/lookup` 的 `pepper` 参数一并提交。 + +#### `none` + +此算法在身份服务器上执行明文查询。若因安全原因不宜传播明文标识,一般不推荐用该算法,但在某些场景(如基于 LDAP 的身份服务器)无法使用哈希,因此允许(或可选地,客户端)采用该算法查询。 + +与 `sha256` 类似,客户端将查询项格式化为 `
` 的空格分隔字符串,不含 ``。例如,要查询 `alice@example.org` 的绑定,格式为 `alice@example.org email`。 + +格式化字符串作为 `/lookup` 请求体内的 `addresses`。注意仍需提供 `pepper`(以保证客户端先正确查询了 `/hash_details`)。 + +### 安全性注意事项 + +{{% boxes/note %}} +请参考 [MSC2134](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/2134-identity-hash-lookup.md),其中详细阐述了本节规范的安全考量。此处仅简述规范设计的高层原因。 +{{% /boxes/note %}} + +通常,/lookup 端点用于客户端拥有某 3PID,但希望获取对应的 Matrix 用户 ID 的场景。客户端常在邀请新用户入群或遍历通讯录查找未发现的 Matrix 用户时,用到此接口。恶意身份服务器若能收集到这些明文数据,可能滥用之。为保护未关联 Matrix ID 的 3PID 用户隐私,规范尽量提升批量收集 3PID 的难度。 + +{{% boxes/rationale %}} +虽然哈希不能百分百防止收集,但能显著增加批量收集标识的成本。手机号码通过哈希也难以完全隐匿,但这仍优于不加密。 + +另一种替代方案如 bcrypt 等多轮哈希算法,但考虑到需兼顾移动端与低性能设备,仍须保持加密过程较轻量。 +{{% /boxes/rationale %}} + +客户端应警惕服务器很久不轮换 pepper,或使用弱 pepper,这可能表明服务器试图暴力破解或利用彩虹表反查地址。同样,支持 `none` 算法的客户端,至少应向用户警示明文发送标识给身份服务器存在的风险。 + +某些标识(如手机号、电邮域名、已泄露地址)即使经哈希,仍可通过预计算的彩虹表逆推出原文。例如,手机号一般为 12 位左右,比邮箱更易被攻击。 + +## 建立关联 + +创建关联的流程基于 Session 会话。 + +在 Session 内,用户可证明其拥有某 3PID。一旦验证通过,用户即可将该 3PID 与 Matrix 用户 ID 关联。注意此流程的认证仅为单向,即用户可将任意已验证 3PID 关联到任意 Matrix 用户 ID,例如我可把自有邮箱地址与 @billg:microsoft.com 关联。 + +Session 有时效性:会话初建或发生验证时被认为已修改。只有在距离上次修改 24 小时内,Session 才可检查或执行验证。逾期后须新建 Session。 + +会话发起时,客户端请求对应 `/requestToken` 端点。身份服务器向用户发送验证 token,用户将该 token 提供给客户端,客户端再提交到 `/submitToken` 端点,整个会话结束。此时,客户端可选择 `/bind` 该 3PID,也可以留给其他实体进行绑定。 + +### 验证 token 格式 + +验证 token 的格式由身份服务器自行决定,应适合 3PID 类型(如不宜让用户从短信复制一长串带标点的口令)。 + +身份服务器采用何种格式皆可,但 token 必须不超过 255 个 Unicode 码点。客户端必须保持 token 不变地传递。 + +### 电子邮件关联 + +{{% http-api spec="identity" api="v2_email_associations" %}} + +### 手机号关联 + +{{% http-api spec="identity" api="v2_phone_associations" %}} + +### 通用 + +{{% http-api spec="identity" api="v2_associations" %}} + +## 邀请存储 + +身份服务器可存储针对用户 3PID 的待处理邀请,这些邀请将在 3PID 绑定至 Matrix 用户 ID 后检索到,并可通知用户或供后续查询。 + +稍后,若 3PID 持有者将其绑定到 Matrix 用户 ID,身份服务器会尝试通过 +[/3pid/onbind](/server-server-api#put_matrixfederationv13pidonbind) +端点向该 Matrix 用户的 homeserver 发送 HTTP POST 请求。请求必须由身份服务器某长期私钥签名。 + +{{% http-api spec="identity" api="v2_store_invite" %}} + +## 临时邀请签名 + +为支持无法自行进行加密的客户端,身份服务器可提供部分加密能力,帮助其接受邀请。虽然这不如客户端自有加密安全,但在某些场景下仍有用。 + +{{% http-api spec="identity" api="v2_invitation_signing" %}} diff --git a/locales/zh-Hans/proposals.md b/locales/zh-Hans/proposals.md new file mode 100644 index 00000000..9967c519 --- /dev/null +++ b/locales/zh-Hans/proposals.md @@ -0,0 +1,256 @@ +--- +title: "规范变更提案" +weight: 60 +type: docs +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +如果您有兴趣提交 Matrix 规范的变更,请注意以下指南。 + +大多数对规范的更改都需要正式的提案。漏洞修复、拼写错误,以及对现有行为的澄清不需要提案——详见[贡献指南](https://github.com/matrix-org/matrix-spec/blob/main/CONTRIBUTING.rst)以了解哪些需要、哪些不需要提案。 + +提案流程包括一定的技术写作,由所有人评审,通过后被接受,最终将您的想法作为已提交的更改实现到[规范仓库](https://github.com/matrix-org/matrix-spec)中。 + +欢迎认识[核心团队成员](https://matrix.org/foundation),这是一个负责确保规范流程尽可能顺畅、顺利的专家小组。规范核心团队成员会尽力参与讨论,在讨论变得冗长时进行总结,并总体上推动所有人受益。团队成员可凭多数决定提案状态的变更,并且个人在提案讨论中拥有最终裁决权。 + +## 指导原则 + +提案**必须**着眼于整个 Matrix 生态系统的整体利益,而非仅惠及或优待某个单一参与者或部分参与者,并且不得包含任何受专利限制的知识产权。核心团队成员承诺以中立托管人的身份代表整个 Matrix 生态系统履行职责。 + +为澄清起见:Matrix 生态系统指任何使用 Matrix 协议的人。这包括客户端用户、服务器管理员、客户端开发者、机器人开发者、桥接与应用服务开发者、通过第三方网络间接使用 Matrix 的用户及管理员、服务器开发者、房间版主与管理员、基于 Matrix 构建产品或服务的公司/项目、规范贡献者、翻译人员以及最初的创造者等。 + +“整体利益”可以包括最大化: + +- 可在开放 Matrix 网络上联系到的终端用户数量 +- Matrix 网络上的活跃常用用户数量(例如:30 天留存的联合用户) +- 开放联合体中在线服务器的数量 +- 构建于 Matrix 之上的开发者数量 +- 使用 Matrix 的独立实现数量 +- 可在开放 Matrix 网络上通过桥接可达的终端用户数量 +- 开放 Matrix 网络内容的信噪比(即最小化垃圾信息) +- 用户根据自身意愿发现内容的能力(赋权用户选择看什么或不看什么) +- Matrix 规范的质量与实用性(以开发者实现兼容规范的客户端、服务器、机器人、桥接以及其他集成的难易程度和能力为定义,且无需参考任何其他外部资料) + +此外,提案作者在对 Matrix 协议提出变更时应秉持以下价值观: + +- 支持整个长期生态系统,而非单一利益相关方 +- 开放而非专有锁定 +- 互操作而非碎片化 +- 跨平台而非特定平台 +- 协作胜于竞争 +- 易用胜于精英主义 +- 透明胜于隐蔽 +- 同理心胜于对立 +- 实用主义胜于追求完美 +- 证据胜于猜测 + +完整指导原则详情请参见 [MSC1779](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/1779-open-governance.md)。 + +## 技术说明 + +提案**必须**将 Matrix 发展为分层协议:新特性应建立在共享抽象层之上,而非在协议栈中引入紧密垂直耦合。这样可以确保新功能能够在既有层之上快速演进,替换旧特性也不会影响协议栈中其他组件,也无需整个生态大规模升级。这对于 Matrix 作为联盟协议来说,能迅速演进并有效与中心化系统竞争至关重要。 + +例如,新特性应尽可能在最高抽象层实现(比如新事件类型,可叠加在现有房间语义之上,甚至无需 API 变更)。如果做不到,则退而求其次,对下层做向后兼容的更改(如房间 API);再不行则考虑事件或 DAG 格式的更改等。不依赖现有规范基础设施、反而创建新原语或低层 API 的特性是极少见的。 + +向后兼容对 Matrix 至关重要,但不能以牺牲协议进化为代价。当没有其他方案时,允许对端点作不兼容更改,且必须以 API 新主版本进行版本管理。当没有其他方案时,对房间算法的不兼容更改也允许,且必须以房间算法新版本进行。 + +有时,对于高级功能应纳入哪个层级会有疑问:比如视频会议应在规范中正式定义,还是通过小组件(widget)实现?声誉系统是否应被规范?搜索引擎行为应被规范吗? + +此类问题没有统一答案,但可遵循以下指导: + +1. 如果该功能对整个 Matrix 生态有益且符合上述指导原则,应由规范支持。 +2. 如果无需更改任何实现与规范即已可实现该功能,则不必加入规范中。 +3. 但如果最佳用户体验确实需要自定义实现行为,则应在规范中定义,使所有实现均可采纳。 +4. 规范**绝不能**依赖未规范/未标准化的第三方行为。 + +举例说明: + +1. 视频会议显然对整体生态有益,因此规范应支持其实现方式。 +2. 利用小组件可实现视频会议,无需客户端与服务器强制变更,因此可以不纳入规范。 +3. 若本地集成 Jitsi 客户端体验更佳…… +4. ……但这将依赖未规范、未标准化的第三方行为,因此不能加入规范。 + +故视频会议案例下,具体选择要么为 WebRTC 的 SFU 会议语义制定规范(或引用已有规范),要么仍采用基于小组件的方案(可选配 widget 扩展以更深集成视频会议场景)。 + +另一个例子:“如何在 Matrix 内可视化核磁共振成像(MRI)数据”几乎不会被收纳进 Matrix 规范(顶多成为扩展事件类型注册表中的自定义事件),因为现有文件传输和可扩展事件(MSC1767)等基础已为传输和可视化任意富数据提供了优秀工具。 + +支持公共搜索引擎大概率无需自定义规范特性(顶多需批量接口优化),它们可作为客户端使用现有 CS API。例外的情形是去中心化搜索架构确实需新 API 功能(避免中心化搜索引擎权力过度集中)。 + +诸如回复、线程消息、可编辑消息、垃圾/滥用/内容过滤(及声誉系统)这类功能,对整个 Matrix 生态确有益处,目前规范下无法互操作实现,因此必须引入规范更改。 + +## 流程 + +Matrix 规范变更提案(MSC)的具体提交流程如下: + +- 用 [GitHub-flavored Markdown](https://help.github.com/articles/basic-writing-and-formatting-syntax/) 编写首稿。 + - 在文档中明确说明要解决的问题,以及拟议的多个解决方案及其权衡。 + - 提案文档可由作者自定风格与内容,没有固定模板,目的是尽快迭代设计取得最佳方案。 + - 但可参考[带建议标题模板](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/0000-proposal-template.md)入手。 + - 谨慎撰写提案。明确指定所需更改,并论证其合理性。缺乏理由的变更很可能不会被社区接受。 +- Fork 并向 [matrix-spec-proposals](https://github.com/matrix-org/matrix-spec-proposals) 仓库发起 PR。您的 PR ID 将作为 MSC ID 伴随该提案的整个生命周期。 + - 文件必须放在 `proposals/` 目录下,文件名格式为 `1234-my-new-proposal.md`,其中 `1234` 为 MSC ID。 + - PR 描述中必须包含渲染后的 Markdown 文档链接及提案摘要。 + - 建议链接相关 MSC 或 [matrix-spec issues](https://github.com/matrix-org/matrix-spec/issues) 以提供上下文。 + - 同时,请根据 [CONTRIBUTING.rst](https://github.com/matrix-org/matrix-spec/blob/main/CONTRIBUTING.rst) 要求为您的提案 PR 进行签名(sign off)。 +- 广泛收集反馈。 + - 目标是尽可能就最优解决方案达成最大共识。为此有时需权衡取舍。决策应覆盖所有主要用例。 + - 针对特定提案征询意见的好渠道为 [\#matrix-spec:matrix.org](https://matrix.to/#/#matrix-spec:matrix.org)。若需,可建立另一个房间并在 \#matrix-spec:matrix.org 宣传。在 PR 描述中也应同步列出讨论房间。 + - 其他讨论区域包括:\#matrix-dev:matrix.org(面向使用既有 Matrix API 的开发者),\#matrix:matrix.org(面向运行 Matrix 应用/服务端的用户),以及 \#matrix-architecture:matrix.org(Matrix 架构设计横向讨论)。 + - 规范提案流程以协作为宗旨,而非竞争,目标乃以最优权衡解决相关问题。作者应中立收集各方观点并寻求共识,但这有时耗时(或有作者偏见),此时可指定不偏不倚的“牧羊人(shepherd)”协助推进。牧羊人通常是规范核心团队中立成员或有经验的社区成员,不设正式指派流程。只需提出请求,即会根据空余分配。拥有牧羊人并非被采纳提案的必要条件。 +- 规范核心团队及社区将在 GitHub PR 评论区和 Matrix 相关房间共同评审、讨论。GitHub 之外的讨论应在 PR 评论中总结归档。 +- 当核心团队成员认为讨论无新观点且有足够可行证据(见下文[实施提案](#implementing-a-proposal)),将提出进入最终评论期(FCP)的动议,并附带合并、关闭或延期的结论(*disposition*)。FCP 旨在为各方提供一小段时间,若有疑义可最终发声。在充分理由下,可取消 FCP。通常会先由一则评论综述当前讨论状态及理由。 +- 规范核心团队成员可随时提出关切,阻止 FCP 启动。仅当 75% 的核心团队成员就 FCP 结论达成一致,且所有现有关切都已解决后,FCP 方能启动。 +- FCP 将进行 5 天,为其他关心方留出答复时间。若有充分反对理由,核心团队成员可提出关切阻止 FCP 结束。此举不会重置/暂停 5 天计时,但在所有关切解决前 FCP 不会终结。如需大量调整 MSC 才能解决关切,FCP 可能被取消并重新申请。FCP 完成后,将执行其结论指令。 +- 提案被接受合并后,需提交规范实际变更的 PR(spec PR)。但只有在给出实现证据**且**证明实践可行的情况下 spec PR 才能被采纳。PR 描述需附实现链接。若过程中发现与原方案有重大且意料之外的改变,则需额外提交 MSC。非根本性的小变更允许,但**必须**在原提案文档中注明。此举可避免日后查阅提案者以为旧信息已纳入规范。 + - 规范 PR 亦需参照 [CONTRIBUTING.rst](https://github.com/matrix-org/matrix-spec/blob/main/CONTRIBUTING.rst) 进行签名。 +- 您的 PR 将再次接受评审,若实现充分则有望合并。届时,恭喜您成功为 Matrix 协议、用户及开发者带来了贡献! + +下列流程图以可视化形式说明了提案处理流程。注意,提案各阶段均通过 [matrix-spec-proposals](https://github.com/matrix-org/matrix-spec-proposals) 拉取请求跟踪器上的对应标签追踪状态。 + +``` + + + + Proposals | Spec PRs | Additional States + +-------+ | +------+ | +---------------+ + | | + +----------------------+ | +---------+ | +-----------+ + | | | | | | | | + | Proposal | | +------= Spec PR | | | Postponed | + | Drafting and Initial | | | | Missing | | | | + | Feedback Gathering | | | | | | +-----------+ + | | | | +----+----+ | + +----------+-----------+ | | | | +----------+ + | | | v | | | + v | | +-----------------+ | | Closed | + +-------------------+ | | | | | | | + | | | | | Spec PR Created | | +----------+ + | Proposal PR | | | | and In Review | | + | In Review | | | | | | + | | | | +--------+--------+ | + +---------+---------+ | | | | + | | | v | + v | | +-----------+ | + +----------------------+ | | | | | + | | | | | Spec PR | | + | Proposed Final | | | | Merged! | | + | Comment Period | | | | | | + | | | | +-----------+ | + +----------+-----------+ | | | + | | | | + v | | | + +----------------------+ | | | + | | | | | + | Final Comment Period | | | | + | | | | | + +----------+-----------+ | | | + | | | | + v | | | + +----------------------+ | | | + | | | | | + | Final Comment Period | | | | + | Complete | | | | + | | | | | + +----------+-----------+ | | | + | | | | + +-----------------+ | + | | + + + +``` + +## 生命周期状态 + +**注意:** 所有标签都应加至提案 PR 上。 + +| 名称 | GitHub 标签 | 描述 | +|-----------------------------------|------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 提案撰写与反馈 | [Draft pull request](https://github.com/matrix-org/matrix-spec-proposals/issues?q=is:open+draft:true) | 尚在进行中的提案文档,公开征集反馈。标题请加 `[WIP]` 前缀,便于评审快速筛查。 | +| 提案评审中 | [无标签](https://github.com/matrix-org/matrix-spec-proposals/issues?q=draft:false+label%3Aproposal+-label%3Aabandoned+-label%3Afinal-comment-period+-label%3Afinished-final-comment-period+-label%3Amerged+-label%3Aobsolete+-label%3Aproposal-postponed+-label%3Aproposed-final-comment-period+-label%3Aproposal-in-review+-label%3Aspec-pr-in-review+-label%3Aspec-pr-missing) | 已准备好,等待核心团队与社区评审的提案。 | +| 已提议最终评论期 | [proposed-final-comment-period](https://github.com/matrix-org/matrix-spec-proposals/issues?q=draft:false+label%3Aproposal+label%3Aproposed-final-comment-period+) | 正在等待 75% 多数团队成员签批以进入最终评论期 | +| 最终评论期 | [final-comment-period](https://github.com/matrix-org/matrix-spec-proposals/issues?q=draft:false+label%3Aproposal+label%3Afinal-comment-period+) | 提案已进入最终评论期(合并、关闭或延期) | +| 完成最终评论期 | [finished-final-comment-period](https://github.com/matrix-org/matrix-spec-proposals/issues?q=draft:false+label%3Aproposal+label%3Afinished-final-comment-period+) | 最终评论期已结束,等待实现证明 | +| 规范 PR 待提交 | [spec-pr-missing](https://github.com/matrix-org/matrix-spec-proposals/issues?q=draft:false+label%3Aproposal+label%3Aspec-pr-missing) | 提案已达成一致并通过实现证明,待提交规范的 PR | +| 规范 PR 评审中 | [spec-pr-in-review](https://github.com/matrix-org/matrix-spec-proposals/issues?q=draft:false+label%3Aproposal+label%3Aspec-pr-in-review+) | 规范 PR 已提交,正在评审中 | +| 规范 PR 已合并 | [merged](https://github.com/matrix-org/matrix-spec-proposals/issues?q=draft:false+label%3Aproposal+label%3Amerged) | 已有充分可用实现并合并规范 PR 的提案 | +| 已延期 | [proposal-postponed](https://github.com/matrix-org/matrix-spec-proposals/issues?q=draft:false+label%3Aproposal+label%3Aproposal-postponed+) | 暂时被阻止或暂时无用、但未来或有价值的提案 | +| 已废弃 | [abandoned](https://github.com/matrix-org/matrix-spec-proposals/issues?q=draft:false+label%3Aproposal+label%3Aabandoned) | 作者/牧羊人无回复的提案 | +| 已过时 | [obsolete](https://github.com/matrix-org/matrix-spec-proposals/issues?q=draft:false+label%3Aproposal+label%3Aobsolete+) | 被其他提案或决策取代而失效的提案 | + + +## 分类 + +我们使用分类标签为 MSC 归入工作流轨道。规范核心团队会根据被选工作重心优先处理对应分类的 MSC,并努力推动这些 MSC 提案流转。 + +当前分类如下: + +| 名称 | GitHub 标签 | 描述 | +|-------------|----------------|------------------------------| +| 核心 | kind:core | 协议成败关键特性。 | +| 功能 | kind:feature | 规范的可选新增功能。 | +| 维护 | kind:maintenance| 修正或澄清已存在规范内容。 | + +核心 MSC 例如聚合、交叉签名、群组/社区等,这些若不实现,协议可能失效或沦为二流。功能类如增强媒体 API、新传输方式、收藏夹等,维护类如优化错误码、澄清 API 要求、为 API 添新属性提高易用性。 + +核心团队将根据以上描述为每个 MSC 分类。即使新 MSC 归入暂未聚焦领域,随着重点演变,也可随时调整。我们仍鼓励开放新 MSC,即使暂非当前焦点,也可推进甚至无需核心团队专注即合并。 + +## 实施提案 + +作为提案流程一环,规范核心团队要求有 MSC 实现的证据,方可进入 FCP。这通常是相应实现的分支/PR,证明 MSC 可以在实践中运行,有时 MSC 本身足够小,不需实现即可视为已证明。实现无需合并发布,但须展示 MSC 确实切实可行。若不确定是否需实现证明,请在 [\#matrix-spec:matrix.org](https://matrix.to/#/#matrix-spec:matrix.org) 咨询。提案可能需服务端与客户端共同实现。 + +尚未被实现的提案将被打上 `needs-implementation` 标签。实现后,请在 GitHub issue 评论告知。已实现但尚未审核的,将被打上 `implementation-needs-checking` 标签。 + +### MSC/创意早期发布 + +为便于软依赖正式规范发布的软件提前放行,要求实现采用如下方式,防止官方 Matrix 命名空间堆积开发/测试数据。 + +**注意:** 未发布的实现(包括用于证明 MSC 可行的概念验证)无需遵循本流程。 + +1. 有了新特性的想法。 +1. 利用非稳定端点、厂商前缀及不稳定特性标志实现该特性。 + - 使用非稳定端点时**必须**加厂商前缀。例如:`/_matrix/client/unstable/com.example/login`。Matrix 中厂商前缀始终采用 Java 包命名规范。MSC 应明确早期采用者选用哪个前缀。 + - 注意不稳定命名空间不会自动继承稳定命名空间下的端点:例如,`/_matrix/client/r0/sync` 存在,不意味着 `/_matrix/client/unstable/com.example/sync` 也存在。 + - 若客户端需确认服务器支持此特性,需使用厂商前缀的不稳定特性标志。该标志会显示在 `/versions` 的 `unstable_features` 区段中,如 `com.example.new_login`。MSC 应说明首选使用哪个特性标志。 + - 正确采用该方法时,实现可随时发布此特性,前提是可接受相应的技术债务,即须确保足够的前后兼容。该实现**必须**支持该标志/服务器端实现消失,并对用户一般安全可靠。需注意,如果处于 MSC 评审初期阶段,可能还得兼容早期方案版本。 + - 若无法承担技术债务(或不可能保持前后兼容,比如不可回滚的用户认证变更),就不应尝试实现该特性,应耐心等待规范发布。 + - 若早期发布后,方案出现向后不兼容的重大更动,特性标志也应更换,方便实现随时适配。 +1. 实现前后/并行,按上文流程开放 MSC 并征求意见。 +1. FCP 开启前,核心团队需有 MSC 按提案方式有效实现的证据。典型方法是有实现 PR,无须正式发布业可规避严重的前后兼容风险。 +1. 完成 FCP 流程,如无异议 MSC 合并落地。 +1. 各实现可切换到稳定前缀(如端点由 `/unstable/org.matrix.mscxxxx/frobnicate` 变为 `/v1/frobnicate`),前提要与早期实现兼容。如确实无法兼容且需新规范发布,则应维持用不稳定前缀。 +1. 提交 PR 将更改纳入 Matrix 规范。 +1. 规范发布。 +1. 规范发布后立即起约 2 个月过渡期,期间实现鼓励彼此迁移至稳定端点。例如,服务器端可在规范发布后两个月后敦促客户端切换到稳定端点,反之亦然,若因服务器未支持新规范客户端尚未切换稳定前缀,则应适当反馈上游引起重视。 + +{{% boxes/note %}} +MSC 仍**必须**描述稳定端点/特性的形式,并在末尾注明不稳定特性标志/前缀。例如,MSC 应提议 `/_matrix/client/r0/new/endpoint`,而非 `/_matrix/client/unstable/com.example/new/endpoint`。 +{{% /boxes/note %}} + +总结: + +- 在 MSC 完成 FCP 之前,实现**不得**使用稳定端点。完成后可使用,非强制。 +- 实现可在 MSC 合并进规范前即以默认方式提供用户可见的特性,前提需遵循上述流程。 +- 实现应警惕抢先于规范部署所产生的技术债务。 +- 厂商前缀由特性开发者自选,应使用 Java 包命名风格。基金会首选厂商前缀为 `org.matrix`。 +- 厂商前缀、不稳定标志、不稳定端点均应纳入 MSC,MSC 内容**必须**以提议稳定端点为主。一般末尾表格对照稳定及不稳定值。 + +## 提案跟踪 + +本页为依据 [matrix-spec-proposals](https://github.com/matrix-org/matrix-spec-proposals) 仓库 issue 与 pull request 跟踪器中的提案列表动态生成的文档。 + +我们利用 MSC PR 描述中的标签与部分元数据生成本页面。标签由规范核心团队在分拣提案时根据仓库既有标签进行分配。 + +需额外说明,先前 MSC 流程中曾混用 GitHub issue 与 PR,导致部分 MSC 号取自 issue ID。GitHub 的一项有益特性是,在拉取 URL 中放入 issue ID 时能自动跳转对应 issue。因此, 无论始于 issue 还是 PR,均可正确跳转至对应 MSC。 + +其他元数据: + +- MSC 号取自 GitHub Pull Request ID,贯穿提案全生命周期。该 ID 不一定代表时序先后。 +- GitHub PR 标题即为 MSC 标题。 +- 若有规范 PR,请在 issue 描述添加 "PRs: #1234" 字样链接规范 pr。 +- 创建日期取自 GitHub PR,可通过在 PR 描述增加 "Date: yyyy-mm-dd" 字样覆盖。 +- 更新时间取自 GitHub。 +- 作者为提案 PR 创建人,可在 issue 描述正文以 "Author: @用户名" 指定。请确保 @用户名 为 GitHub 用户名(必须含 @)。 +- 可通过在 issue 描述添加 "Shepherd: @用户名" 指定牧羊人,同样需为真实 GitHub 用户。 + +{{% proposal-tables %}} diff --git a/locales/zh-Hans/push-gateway-api.md b/locales/zh-Hans/push-gateway-api.md new file mode 100644 index 00000000..17414d6f --- /dev/null +++ b/locales/zh-Hans/push-gateway-api.md @@ -0,0 +1,57 @@ +--- +title: "推送网关 API" +weight: 50 +type: docs +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +客户端可能希望在主服务器接收到事件时获得推送通知。对此进行管理的是一个名为推送网关的独立实体。 + +## 概述 + +客户端的主服务器会将接收到的事件信息转发给推送网关。随后,推送网关会向推送通知提供商(如 APNS、GCM)发送推送通知。 + +``` + +--------------------+ +-------------------+ + Matrix HTTP | | | | + Notification Protocol | 应用开发者 | | 设备供应商 | + | | | | + +-------------------+ | +----------------+ | | +---------------+ | + | | | | | | | | | | + | Matrix 主服务器 +-----> 推送网关 +------> 推送提供商 | | + | | | | | | | | | | + +-^-----------------+ | +----------------+ | | +----+----------+ | + | | | | | | + Matrix | | | | | | + 客户端/服务器 API + | | | | | + | | +--------------------+ +-------------------+ + | +--+-+ | + | | <-------------------------------------------+ + +---+ | + | | 提供商推送协议 + +----+ + + 移动设备或客户端 +``` + +## API 标准 + +### 不支持的端点 + +如果收到对不支持(或未知)端点的请求,则服务器必须以 404 `M_UNRECOGNIZED` 错误进行响应。 + +类似地,405 `M_UNRECOGNIZED` 错误用于表示对已知端点使用了不被支持的方法。 + +## 主服务器行为 + +本节描述了“HTTP”推送器用于向推送网关发送事件通知的格式。如果端点返回 HTTP 错误码,主服务器应在合理的时间内采用指数退避机制进行重试。 + +在推送事件通知时,主服务器应在 `/notify` 请求中包含所有与事件相关的字段。当主服务器执行 `format` 为 `"event_id_only"` 的推送时,仅需填写 `event_id`、`room_id`、`counts` 和 `devices` 字段。 + +请注意,本端点的大多数数值和行为已由客户端-服务器 API 的 [推送模块](/client-server-api#push-notifications) 描述。 + +{{% http-api spec="push-gateway" api="push_notifier" %}} diff --git a/locales/zh-Hans/rooms/_index.md b/locales/zh-Hans/rooms/_index.md new file mode 100644 index 00000000..f1d00ec4 --- /dev/null +++ b/locales/zh-Hans/rooms/_index.md @@ -0,0 +1,72 @@ +--- +title: 房间版本 +type: docs +weight: 60 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +房间是 Matrix 运行的核心,并对其内容有严格的规则限制。房间还可以拥有处理不同任务的各种算法,例如当两个或多个事件在底层 DAG 结构中发生冲突时的处理方式。为了便于通过新算法或新规则对房间功能进行改进,Matrix 采用“房间版本”来管理每个房间的一组预期行为。根据需要分配新的房间版本。 + +房间版本之间没有隐式排序或层级关系,并且一旦被纳入规范,其原则不可更改。尽管有一组推荐使用的版本,有些房间可能会受益于其他版本所引入的功能。房间可通过“升级”至所需版本,在不同版本间切换。由于版本不具备排序或层级特性,这意味着房间完全可以从版本 2 “升级”到版本 1,只要有此需求。 + +## 功能矩阵 + +某些功能仅在特定房间版本中可用,比如 knocking(敲门加入)。下表展示了不同版本从客户端视角支持哪些功能。服务器实现同样可以参考该表,但实际开发中,往往会更关心各版本的详细规范。 + + + +| 功能 \ 版本 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | +|----------------------------|---|---|---|---|---|---|---|---|---|----|----| +| **Knocking(敲门加入)** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | +| **受限加入规则** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | +| **`knock_restricted` 加入规则** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | + +## 房间版本完整列表 + +房间版本分为两大类:稳定版(stable)和非稳定版(unstable)。稳定房间版本可安全用于房间创建。非稳定版本则包括所有未在规范中列出或因其他原因被标记为不稳定的版本。各版本状态可能因多种原因(如发现安全漏洞、版本老化等)而定期在稳定与非稳定之间切换。 + +如果房间已在运行稳定版本,客户端不应要求房间管理员升级房间。服务器在新建房间时,**强烈建议默认使用房间版本 11**。 + +可选房间版本如下: + +- [版本 1](/rooms/v1) - **稳定**。初始房间版本。 +- [版本 2](/rooms/v2) - **稳定**。实现了 State Resolution Version 2(状态解析版本 2)。 +- [版本 3](/rooms/v3) - **稳定**。引入事件 ID 即事件哈希值的机制。 +- [版本 4](/rooms/v4) - **稳定**。基于 v3 ,事件 ID 使用 URL 安全的 base64 编码。 +- [版本 5](/rooms/v5) - **稳定**。引入对签名密钥有效期的强制校验。 +- [版本 6](/rooms/v6) - **稳定**。修改了多项事件授权规则。 +- [版本 7](/rooms/v7) - **稳定**。新增 knocking 功能。 +- [版本 8](/rooms/v8) - **稳定**。添加新加入规则,允许其他房间成员无需邀请即可加入。 +- [版本 9](/rooms/v9) - **稳定**。基于 v8,修复了撤回部分成员事件时的问题。 +- [版本 10](/rooms/v10) - **稳定**。仅允许权限等级为整数,并新增 `knock_restricted` 加入规则。 +- [版本 11](/rooms/v11) - **稳定**。进一步明确撤回(redaction)算法。 + +## 房间版本语法规范 + +房间版本用于指定房间属性的变更,这些属性可能无法与其他服务器兼容。例如,更改事件授权规则可能导致旧服务器因无法理解新规则而出现分裂脑(split-brain)状态。 + +一个房间版本被定义为不超过 32 个码点的字符串。房间版本不能为空,且只能包含字符 `a-z`、`0-9`、`.` 和 `-`。 + +房间版本号不应被解析,应视为不透明的标识符。仅包含 `0-9` 和 `.` 的房间版本号,保留给未来 Matrix 协议使用。 + +合法房间版本的完整语法为: + + room_version = 1*room_version_char + room_version_char = DIGIT + / %x61-7A ; a-z + / "-" / "." + +合法房间版本示例: + +- `1`(将由 Matrix 协议保留) +- `1.2`(将由 Matrix 协议保留) +- `1.2-beta` +- `com.example.version` diff --git a/locales/zh-Hans/rooms/fragments/index.md b/locales/zh-Hans/rooms/fragments/index.md new file mode 100644 index 00000000..290e33c8 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/index.md @@ -0,0 +1,8 @@ +--- +headless: true +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + diff --git a/locales/zh-Hans/rooms/fragments/v1-auth-rules.md b/locales/zh-Hans/rooms/fragments/v1-auth-rules.md new file mode 100644 index 00000000..d910317b --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v1-auth-rules.md @@ -0,0 +1,99 @@ +影响授权的状态事件类型包括: + +- [`m.room.create`](/client-server-api#mroomcreate) +- [`m.room.member`](/client-server-api#mroommember) +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) +- [`m.room.power_levels`](/client-server-api#mroompower_levels) +- [`m.room.third_party_invite`](/client-server-api#mroomthird_party_invite) + +{{% boxes/note %}} +如果未明确给出权限等级,则从默认值推断。 +例如,提及 `sender` 的权限等级时,也可指代房间用户的默认权限等级。 +{{% /boxes/note %}} + +规则如下: + +1. 若类型为 `m.room.create`: + 1. 若有任何 `prev_events`,则拒绝。 + 2. 若 `room_id` 的域名与 `sender` 的域名不符,则拒绝。 + 3. 若 `content.room_version` 存在但不是识别的版本,则拒绝。 + 4. 若 `content` 没有 `creator` 属性,则拒绝。 + 5. 否则,允许。 +2. 针对事件的 `auth_events`: + 1. 若某一 `type` 与 `state_key` 组合存在重复,则拒绝。 + 2. 若存在其 `type` 与 `state_key` 不符合 [认证事件选择](/server-server-api#auth-events-selection) 算法(详见服务器规范)的项,则拒绝。 + 3. 若有事件本身因 [接收 PDU 时执行的检查](/server-server-api/#checks-performed-on-receipt-of-a-pdu) 被拒绝,则拒绝。 + 4. 若未能在条目中找到 `m.room.create` 事件,则拒绝。 +3. 若房间状态中的 `m.room.create` 事件的 `content` 包含 `m.federate` 属性且值为 `false`,且此事件的 `sender` 域名不与创建事件的 `sender` 域名一致,则拒绝。 +4. 若类型为 `m.room.aliases`: + 1. 若事件无 `state_key`,则拒绝。 + 2. 若发送者域名与 `state_key` 不符,则拒绝。 + 3. 否则,允许。 +5. 若类型为 `m.room.member`: + 1. 若没有 `state_key` 属性,或 `content` 中无 `membership` 属性,则拒绝。 + 2. 若 `membership` 为 `join`: + 1. 若唯一的前序事件为 `m.room.create` 且 `state_key` 为创建者,则允许。 + 2. 若 `sender` 与 `state_key` 不符,则拒绝。 + 3. 若 `sender` 被封禁,则拒绝。 + 4. 若 `join_rule` 为 `invite`,则当 `membership` 状态是 `invite` 或 `join` 时,允许。 + 5. 若 `join_rule` 为 `public`,则允许。 + 6. 否则,拒绝。 + 3. 若 `membership` 为 `invite`: + 1. 若 `content` 含有 `third_party_invite` 属性: + 1. 若 *目标用户* 被封禁,则拒绝。 + 2. 若 `content.third_party_invite` 无 `signed` 属性,则拒绝。 + 3. 若 `signed` 无 `mxid` 和 `token` 属性,则拒绝。 + 4. 若 `mxid` 与 `state_key` 不符,则拒绝。 + 5. 若当前房间状态中无 `state_key` 为 `token` 的 `m.room.third_party_invite` 事件,则拒绝。 + 6. 若 `sender` 与该 `m.room.third_party_invite` 的 `sender` 不符,则拒绝。 + 7. 若 `signed` 中的任意签名与该 `m.room.third_party_invite` 事件中的任一公钥匹配,则允许。公钥位于 `m.room.third_party_invite` 的 `content` 中: + 1. 单个公钥存于 `public_key` 属性; + 2. 公钥列表存于 `public_keys` 属性。 + 8. 否则,拒绝。 + 2. 若 `sender` 当前成员状态不是 `join`,则拒绝。 + 3. 若 *目标用户* 当前成员状态是 `join` 或 `ban`,则拒绝。 + 4. 若 `sender` 权限等级大于或等于 *邀请等级*,则允许。 + 5. 否则,拒绝。 + 4. 若 `membership` 为 `leave`: + 1. 若 `sender` 与 `state_key` 匹配,则仅当其当前成员状态为 `invite` 或 `join` 时允许。 + 2. 若 `sender` 当前成员状态不是 `join`,则拒绝。 + 3. 若 *目标用户* 当前成员状态为 `ban` 且 `sender` 权限等级低于 *封禁等级*,则拒绝。 + 4. 若 `sender` 权限等级大于等于 *踢人等级*,且 *目标用户* 权限等级小于 `sender` 权限等级,则允许。 + 5. 否则,拒绝。 + 5. 若 `membership` 为 `ban`: + 1. 若 `sender` 当前成员状态不是 `join`,则拒绝。 + 2. 若 `sender` 权限等级大于等于 *封禁等级*,且 *目标用户* 权限等级低于 `sender` 权限等级,则允许。 + 3. 否则,拒绝。 + 6. 其他情况下,未知成员状态。拒绝。 +6. 若 `sender` 当前成员状态不是 `join`,则拒绝。 +7. 若类型为 `m.room.third_party_invite`: + 1. 仅当 `sender` 当前权限等级大于等于 *邀请等级* 时允许。 +8. 若事件类型的 *所需权限等级* 大于 `sender` 权限等级,则拒绝。 +9. 若事件的 `state_key` 以 `@` 开头且与 `sender` 不符,则拒绝。 +10. 若类型为 `m.room.power_levels`: + 1. 若 `content` 中 `users` 属性不是键为有效用户ID且值为整数(或整数字符串)的对象,则拒绝。 + 2. 若房间中没有前序的 `m.room.power_levels` 事件,则允许。 + 3. 针对 `users_default`、`events_default`、`state_default`、`ban`、`redact`、`kick`、`invite` 属性,在添加、更改或移除时,针对每个变动: + 1. 若当前值大于 `sender` 当前权限等级,则拒绝。 + 2. 若新值大于 `sender` 当前权限等级,则拒绝。 + 4. 针对 `events` 属性中被更改或移除的每一项: + 1. 若当前值大于 `sender` 当前权限等级,则拒绝。 + 5. 针对 `events` 属性中被添加或更改的每一项: + 1. 若新值大于 `sender` 当前权限等级,则拒绝。 + 6. 针对 `users` 属性(除 `sender` 本人)的被更改或移除的每一项: + 1. 若当前值大于等于 `sender` 当前权限等级,则拒绝。 + 7. 针对 `users` 属性被添加或更改的每一项: + 1. 若新值大于 `sender` 当前权限等级,则拒绝。 + 8. 否则,允许。 +11. 若类型为 `m.room.redaction`: + 1. 若 `sender` 权限等级大于等于 *撤回等级*,则允许。 + 2. 若被撤回事件的 `event_id` 域名与 `m.room.redaction` 的 `event_id` 域名一致,则允许。 + 3. 否则,拒绝。 +12. 否则,允许。 + +{{% boxes/note %}} +这些规则的部分后果: + +- 除非你是房间成员,否则唯一被允许的操作(除首次创建/加入外)为:加入公共房间、接受或拒绝对房间的邀请。 +- 取消封禁某人,你必须拥有大于等于踢人和封禁等级的权限,且你的权限等级高于目标用户。 +{{% /boxes/note %}} \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v1-canonical-json.md b/locales/zh-Hans/rooms/fragments/v1-canonical-json.md new file mode 100644 index 00000000..d7beae6e --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v1-canonical-json.md @@ -0,0 +1 @@ +出于[附录](/appendices#canonical-json)中所述的原因,服务器不得强制严格遵循所规定的 JSON 格式。 \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v1-deprecated-formatting-off-spec.md b/locales/zh-Hans/rooms/fragments/v1-deprecated-formatting-off-spec.md new file mode 100644 index 00000000..a2ff72aa --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v1-deprecated-formatting-off-spec.md @@ -0,0 +1,5 @@ +发送到此版本房间中的事件,其格式可能与其常规模式不同。此类情况将在此处进行说明。 + +{{% boxes/warning %}} +此处描述的行为仅为严格保留向后兼容性。服务器应采取合理措施,防止用户发送这些所谓的“格式错误”事件,并且绝不能以此处描述的行为作为默认行为。 +{{% /boxes/warning %}} \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v1-event-ids.md b/locales/zh-Hans/rooms/fragments/v1-event-ids.md new file mode 100644 index 00000000..49fff8a5 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v1-event-ids.md @@ -0,0 +1,7 @@ +一个事件只能有一个事件ID。在此房间版本中,事件ID的格式为: + + $opaque_id:domain + +其中,`domain` 是创建该房间的主服务器的[服务器名称](/appendices/#server-name),而 `opaque_id` 是在本地唯一的字符串。 + +domain 仅用于命名空间,以避免不同主服务器之间标识符发生冲突的风险。并不意味着相关房间或事件一定还在对应的主服务器上可用。 \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v1-redactions.md b/locales/zh-Hans/rooms/fragments/v1-redactions.md new file mode 100644 index 00000000..80705a75 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v1-redactions.md @@ -0,0 +1,29 @@ +在接收到删除事件后,服务器必须移除除以下列表外的所有键: + +- `event_id` +- `type` +- `room_id` +- `sender` +- `state_key` +- `content` +- `hashes` +- `signatures` +- `depth` +- `prev_events` +- `prev_state` +- `auth_events` +- `origin` +- `origin_server_ts` +- `membership` + +对于 content 对象,也必须移除除下列类型允许外的所有键: + +- [`m.room.member`](/client-server-api#mroommember) 允许键 `membership`。 +- [`m.room.create`](/client-server-api#mroomcreate) 允许键 `creator`。 +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) 允许键 `join_rule`。 +- [`m.room.power_levels`](/client-server-api#mroompower_levels) 允许的键有 + `ban`、`events`、`events_default`、`kick`、`redact`、`state_default`、`users`、 + `users_default`。 +- [`m.room.aliases`](/client-server-api#historical-events) 允许键 `aliases`。 +- [`m.room.history_visibility`](/client-server-api#mroomhistory_visibility) 允许 + 键 `history_visibility`。 \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v1-stringy-power-levels.md b/locales/zh-Hans/rooms/fragments/v1-stringy-power-levels.md new file mode 100644 index 00000000..883c92e1 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v1-stringy-power-levels.md @@ -0,0 +1,35 @@ +##### `m.room.power_levels` 事件支持以字符串形式传递数值 + +为了与早期实现保持向后兼容, +[`m.room.power_levels`](/client-server-api#mroompower_levels) 事件中的每个整数值属性 +都可以被编码为字符串而非整数。这包括 `events`、`notifications` 和 `users` +属性中的嵌套值。例如,以下是在此房间版本中有效的 +`m.room.power_levels` 事件: + +```json +{ + "content": { + "ban": "50", + "events": { + "m.room.power_levels": "100" + }, + "events_default": "0", + "state_default": "50", + "users": { + "@example:localhost": "100" + }, + "users_default": "0" + }, + "origin_server_ts": 1432735824653, + "room_id": "!jEsUZKDJdhlrceRyVU:example.org", + "sender": "@example:example.org", + "state_key": "", + "type": "m.room.power_levels" +} +``` + +当该值表示整数时,必须符合以下格式: + +* 仅包含一个十进制整数,不允许浮点数或小数点,可以带任意数量的前导零(如 `"100"`、`"000100"`); +* 可选地在整数前面加一个 `-` 或 `+` 字符(如 `"+100"`、`"-100"`); +* 可选地在前后添加任意数量的空白字符(如 `" 100 "`、`" 00100 "`、`" +100 "`、`" -100 "`)。 \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v11-event-format.md b/locales/zh-Hans/rooms/fragments/v11-event-format.md new file mode 100644 index 00000000..7e8a8056 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v11-event-format.md @@ -0,0 +1,3 @@ +本版本房间中的事件结构如下: + +{{% definition path="api/server-server/definitions/pdu_v11" %}} \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v11-redactions.md b/locales/zh-Hans/rooms/fragments/v11-redactions.md new file mode 100644 index 00000000..1365b1b1 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v11-redactions.md @@ -0,0 +1,26 @@ +在收到修订事件(redaction event)后,服务器必须去除除以下列表外的所有字段: + +- `event_id` +- `type` +- `room_id` +- `sender` +- `state_key` +- `content` +- `hashes` +- `signatures` +- `depth` +- `prev_events` +- `auth_events` +- `origin_server_ts` + +content 对象中的所有字段也必须被移除,除非该事件类型属于以下之一: + +- [`m.room.member`](/client-server-api#mroommember) 允许保留字段 `membership`、`join_authorised_via_users_server`,此外允许在 `third_party_invite` 字段下的 `signed` 字段。 +- [`m.room.create`](/client-server-api#mroomcreate) 允许保留所有字段。 +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) 允许保留字段 `join_rule`、`allow`。 +- [`m.room.power_levels`](/client-server-api#mroompower_levels) 允许保留字段 + `ban`、`events`、`events_default`、`invite`、`kick`、`redact`、`state_default`、 + `users`、`users_default`。 +- [`m.room.history_visibility`](/client-server-api#mroomhistory_visibility) + 允许保留字段 `history_visibility`。 +- [`m.room.redaction`](/client-server-api#mroomredaction) 允许保留字段 `redacts`。 \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v2-state-res.md b/locales/zh-Hans/rooms/fragments/v2-state-res.md new file mode 100644 index 00000000..f807801a --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v2-state-res.md @@ -0,0 +1,86 @@ +事件 *E* 之后的房间状态 *S′(E)* 由事件 *E* 之前的房间状态 *S(E)* 定义,并且依赖于 *E* 是状态事件还是消息事件: + +- 如果 *E* 是一条消息事件,则 *S′(E)* = *S(E)*。 +- 如果 *E* 是一条状态事件,则 *S′(E)* 与 *S(E)* 相同,除了其与 *E* 的 `event_type` 和 `state_key` 对应的项被 *E* 的 `event_id` 替换。 + +事件 *E* 之前的房间状态 *S(E)* 是 `prev_event` 集合 {*E*1, *E*2, …} 之后的状态集合 {*S′(E*1*)*, *S′(E*2*)*, …} 的 *合并与决议结果*。如何对一组状态进行合并与决议,见下述算法。 + +#### 定义 + +版本 2 房间的状态合并算法使用如下定义,并以房间状态集 {*S*1, *S*2, …} 为输入: + +**权限事件(Power events)。** +*权限事件* 指具有类型 `m.room.power_levels` 或 `m.room.join_rules` 的状态事件,或者类型为 `m.room.member` 且 `membership` 字段为 `leave` 或 `ban`,且 `sender` 与 `state_key` 不一致的状态事件。其核心思想为:权限事件是那些可能移除某人在房间内某项操作权限的事件。 + +**无冲突状态映射与冲突状态集。** +状态映射 *Si* 的 key 为形如 *(event_type, state_key)* 的字符串二元组 *K*,对应的 value *V* 为一个状态事件。所有 *Si* 的 (K, V) 键值对可划分为两个集合:如果给定 key *K* 在所有 *Si* 出现,且值 *V* 在每个状态映射都一致,则此 (K, V) 属于 *无冲突状态映射*;否则,*V* 属于 *冲突状态集*。 + +注意,无冲突状态映射每个 key *K* 只会有一个事件,而冲突状态集可能因同 key 包含多个事件。 + +**鉴权链(Auth chain)。** +事件 *E* 的 *鉴权链*,是包含 *E* 的所有鉴权事件(auth events)、所有这些事件的鉴权事件,递归回溯直到房间创建为止的集合。换句话说,就是通过事件的 `auth_events` 链接遍历可达的所有事件。 + +**鉴权差集(Auth difference)。** +*鉴权差集* 的计算方式如下:首先对每个状态 *S**i*,计算其完全鉴权链,即该状态中每个事件的鉴权链的并集。然后找出那些未在所有鉴权链中都出现的事件。若 *C**i* 表示 *S**i* 的完全鉴权链,则鉴权差集为 ∪ *C**i* − ∩ *C**i*。 + +**完整冲突集(Full conflicted set)。** +*完整冲突集* 是冲突状态集与鉴权差集的并集。 + +**逆拓扑权限排序(Reverse topological power ordering)。** +一组事件的 *逆拓扑权限排序*,是按鉴权事件形成的有向无环图(DAG)进行拓扑排序,得到字典序最小的排序,并从最早事件到最晚事件排列。比较两个拓扑排序确定哪一个字典序更小时,事件的比较关系如下:对事件 *x* 和 *y*,若 + +1. *x* 的发送者的权限级别 *高于* *y* 的发送者(以各自的 `auth_event` 查得);或 +2. 发送者权限级别相同,但 *x* 的 `origin_server_ts` *小于* *y*;或 +3. 权限级别与 `origin_server_ts` 都相同,但 *x* 的 `event_id` *小于* *y* 的 `event_id`, + +则 *x* < *y*。 + +逆拓扑权限排序可用 Kahn 算法进行拓扑排序,每步从候选顶点中按上述比较关系选择最小顶点。 + +**主链排序(Mainline ordering)。** +令 *P* = *P*0 为某个 `m.room.power_levels` 事件。从 *i* = 0 开始,反复获取 *P**i*+1,即 *Pi* 的 `auth_events` 中类型为 `m.room.power_levels` 的事件。每次自增 *i*,直到 *Pi* 的 `auth_events` 中没有 `m.room.power_levels` 事件为止。*P0* 的 *主链* 为 [*P*0 , *P*1, ... , *Pn*]。 + +若另有事件 *e* = *e0*(可以是另一个 `m.room.power_levels` 事件),可以构造类似事件链 [*e*1, ..., *em*],其中 *ej+1* 为 *ej* 的 `auth_events` 中的 `m.room.power_levels` 事件,*em* 没有再指向任何 `m.room.power_levels` 事件。(注意 *e0* 本身不包含在该列表中,也有可能该列表为空,因为 *e* 可能没有引用过 `m.room.power_levels` 事件。) + +对这两条列表进行如下比较: +* 查找最小的 *j* ≥ 1,使得 *ej* 属于 *P* 的主链; +* 若存在这样的 *j*,则 *ej* = *Pi*,且 *i* 唯一、*i* ≥ 0;否则令 *i* = ∞,其中 ∞ 为一个大于任何整数的特殊标记值; +* 无论哪种情况,*e* 的 *主链位置* 就是 *i*。 + +以 *P* 计算得主链位置后,*基于 P 的主链排序*,就是将一组事件按以下比较关系(从小到大)排序:对事件 *x* 和 *y*,若 + +1. *x* 的主链位置 **大于** *y*(即 *x* 的鉴权链基于主链上的较早事件);或 +2. 主链位置相同,但 *x* 的 `origin_server_ts` *小于* *y*;或 +3. 主链位置、`origin_server_ts` 都相同,但 *x* 的 `event_id` *小于* *y*, + +则 *x* < *y*。 + +**迭代鉴权检查(Iterative auth checks)。** +*迭代鉴权检查算法* 的输入是初始房间状态和已排序的状态事件列表。它通过遍历事件列表,将符合[授权规则](/server-server-api#authorization-rules)的状态事件依次应用到房间状态上。若某状态事件未通过授权规则,则忽略该事件。如果验证授权规则时缺少某个必须的 (event_type, state_key) key,则用事件 `auth_events` 中相应的状态事件(若未被拒绝)替代。 + +#### 算法 + +一组状态的 *合并与决议* 按如下步骤执行: + +1. 选取出现在 *完整冲突集* 内的所有*权限事件*组成集合 *X*。对于每一个权限事件 *P*,将 *P* 的鉴权链中同时属于完整冲突集的事件也加入 *X*。对 *X* 按 *逆拓扑权限排序* 排序为列表。 +2. 从 *无冲突状态映射* 作为起点,对上一步得到的事件列表应用*迭代鉴权检查算法*,得出部分已决议状态。 +3. 将第 1 步未涉及的所有剩余事件按第 2 步已决议状态中的权限等级,用*主链排序*确定顺序。 +4. 对上述部分已决议状态及新排序的事件列表,再次应用*迭代鉴权检查算法*。 +5. 用*无冲突状态映射*中的相同 key 事件(若存在)替换当前结果中对应事件,得出最终合并决议状态。 + +#### 被拒绝的事件 + +由于基于事件当前状态(而非鉴权链)验证授权而被拒绝的事件,除非另有特别说明,在算法中仍按常规方式处理。 + +注意,那些由于无法通过其鉴权链授权而被拒绝的事件不应出现在此流程中,因为他们不会出现在状态集合之内(本算法只使用状态集中的事件,或状态集中事件的鉴权链中的事件)。 + +{{% boxes/rationale %}} +这样做有助于保证不同服务器下房间状态更易收敛,因为事件的被拒绝状态可能不同。如果某服务器在另一个服务器作为中转加入房间时返回了不正确的状态(无论是故障还是恶意),就有可能出现此类差异。状态收敛是重要特性,因为它确保房间中所有用户都看到(基本)一致的房间状态。如果各服务器状态视图分歧,可能导致房间分裂,例如因对成员列表存在分歧。 + +直观来看,使用被拒绝的事件似乎有风险,但实际上: + +1. 服务器无法随意伪造状态,因为它们仍需通过根据事件鉴权链的鉴权检查(例如,若之前没有权限,不能自授权限)。 +2. 若想使一个已被拒绝的事件通过鉴权,必须存在某个状态集允许该事件。恶意服务器可能构造一个分支,声称状态就是该特定状态集,然后复制被拒绝事件指向该分支并发送该事件。复制的事件将通过鉴权检查。因此,忽略被拒绝事件未必能消除潜在攻击路径。 +{{% /boxes/rationale %}} + +被拒绝的鉴权事件(auth events)故意不参与迭代鉴权检查,因为检查过程中不会对鉴权事件重新授权(但非鉴权事件则会被检查)。 \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v3-auth-rules.md b/locales/zh-Hans/rooms/fragments/v3-auth-rules.md new file mode 100644 index 00000000..65ece629 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v3-auth-rules.md @@ -0,0 +1,103 @@ +--- +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + +{{% added-in v=3 %}} 在房间版本1和2中,事件需要来自 `event_id` 域的签名才能被视为有效。此房间版本在联邦过程中并未以相同方式包含 `event_id`,因此不需要该服务器的签名。不过,事件仍然必须由 `sender` 属性标识的服务器签名。 + +影响授权的状态事件类型有: + +- [`m.room.create`](/client-server-api#mroomcreate) +- [`m.room.member`](/client-server-api#mroommember) +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) +- [`m.room.power_levels`](/client-server-api#mroompower_levels) +- [`m.room.third_party_invite`](/client-server-api#mroomthird_party_invite) + +{{% boxes/note %}} +当未显式提供权限等级时,将根据默认值推断。例如,对 `sender` 权限等级的引用,也可以指代房间内用户的默认权限等级。 +{{% /boxes/note %}} + +截至房间版本3,完整的规则列表如下: + +1. 如果类型为 `m.room.create`: + 1. 如果有任何 `prev_events`,则拒绝。 + 2. 如果 `room_id` 的域与 `sender` 的域不匹配,则拒绝。 + 3. 如果存在 `content.room_version` 但不是被识别的版本,则拒绝。 + 4. 如果 `content` 中缺少 `creator` 属性,则拒绝。 + 5. 否则,允许。 +2. 考虑事件的 `auth_events`: + 1. 如果某一对相同 `type` 和 `state_key` 的条目重复,则拒绝。 + 2. 如果存在 `type` 和 `state_key` 不符合[授权事件选择](/server-server-api#auth-events-selection)算法(见服务器规范)要求的条目,则拒绝。 + 3. 如果存在在[PDU接收时执行的检查](/server-server-api/#checks-performed-on-receipt-of-a-pdu)中被拒绝的条目,则拒绝。 + 4. 如果没有 `m.room.create` 事件,则拒绝。 +3. 如果房间状态中的 `m.room.create` 事件的 `content` 属性 `m.federate` 设置为 `false`,且当前事件 `sender` 的域与创建事件的 `sender` 域不匹配,则拒绝。 +4. 如果类型为 `m.room.aliases`: + 1. 如果没有 `state_key`,则拒绝。 + 2. 如果发送者域与 `state_key` 不同,则拒绝。 + 3. 否则,允许。 +5. 如果类型为 `m.room.member`: + 1. 如果没有 `state_key` 属性,或 `content` 中没有 `membership` 属性,则拒绝。 + 2. 如果 `membership` 是 `join`: + 1. 如果唯一的前置事件是 `m.room.create` 并且 `state_key` 是创建者,则允许。 + 2. 如果 `sender` 不等于 `state_key`,则拒绝。 + 3. 如果 `sender` 被封禁,则拒绝。 + 4. 如果 `join_rule` 为 `invite`,则当成员状态为 `invite` 或 `join` 时允许。 + 5. 如果 `join_rule` 为 `public`,则允许。 + 6. 否则,拒绝。 + 3. 如果 `membership` 是 `invite`: + 1. 如果 `content` 包含 `third_party_invite` 属性: + 1. 如果*目标用户*被封禁,则拒绝。 + 2. 如果 `content.third_party_invite` 没有 `signed` 属性,则拒绝。 + 3. 如果 `signed` 没有 `mxid` 和 `token` 属性,则拒绝。 + 4. 如果 `mxid` 与 `state_key` 不一致,则拒绝。 + 5. 如果当前房间状态下没有 `state_key` 与 `token` 匹配的 `m.room.third_party_invite` 事件,则拒绝。 + 6. 如果 `sender` 不等于该 `m.room.third_party_invite` 的 `sender`,则拒绝。 + 7. 如果 `signed` 中任一签名与 `m.room.third_party_invite` 事件中的任意公钥匹配,则允许。公钥可在 `m.room.third_party_invite` 的 `content` 中如下出现: + 1. `public_key` 属性中的单个公钥。 + 2. `public_keys` 属性中的公钥列表。 + 8. 否则,拒绝。 + 2. 如果 `sender` 当前的成员状态不是 `join`,则拒绝。 + 3. 如果*目标用户*当前成员状态为 `join` 或 `ban`,则拒绝。 + 4. 如果 `sender` 的权限等级大于或等于*邀请等级*,则允许。 + 5. 否则,拒绝。 + 4. 如果 `membership` 是 `leave`: + 1. 如果 `sender` 等于 `state_key`,且该用户当前成员状态为 `invite` 或 `join`,则允许,否则拒绝。 + 2. 如果 `sender` 当前成员状态不是 `join`,则拒绝。 + 3. 如果*目标用户*当前成员状态为 `ban`,且 `sender` 权限等级小于*封禁等级*,则拒绝。 + 4. 如果 `sender` 权限等级大于或等于*踢出等级*,且*目标用户*的权限等级小于 `sender`,则允许。 + 5. 否则,拒绝。 + 5. 如果 `membership` 是 `ban`: + 1. 如果 `sender` 当前的成员状态不是 `join`,则拒绝。 + 2. 如果 `sender` 权限等级大于或等于*封禁等级*,且*目标用户*的权限等级小于 `sender`,则允许。 + 3. 否则,拒绝。 + 6. 其他情况下,成员状态未知,拒绝。 +6. 如果 `sender` 当前成员状态不是 `join`,则拒绝。 +7. 如果类型为 `m.room.third_party_invite`: + 1. 仅当 `sender` 当前权限等级大于或等于*邀请等级*时允许。 +8. 如果事件类型的*所需权限等级*大于 `sender` 的权限等级,则拒绝。 +9. 如果事件有以 `@` 开头且与 `sender` 不一致的 `state_key`,则拒绝。 +10. 如果类型为 `m.room.power_levels`: + 1. 如果 `content` 中的 `users` 属性不是一个以有效用户ID为键、值为整数(或整数字符串)的对象,则拒绝。 + 2. 如果房间中没有先前的 `m.room.power_levels` 事件,则允许。 + 3. 检查 `users_default`、`events_default`、`state_default`、`ban`、`redact`、`kick`、`invite` 属性是否被新增、变更或移除。对于每一个变动: + 1. 如果当前值大于 `sender` 当前权限等级,则拒绝。 + 2. 如果新值大于 `sender` 当前权限等级,则拒绝。 + 4. 针对 `events` 属性中被更改或移除的每一项: + 1. 如果当前值大于 `sender` 当前权限等级,则拒绝。 + 5. 针对 `events` 属性中被新增或变更的每一项: + 1. 如果新值大于 `sender` 当前权限等级,则拒绝。 + 6. 针对 `users` 属性中被更改或移除的每一项(除了 `sender` 自己的项): + 1. 如果当前值大于等于 `sender` 当前权限等级,则拒绝。 + 7. 针对 `users` 属性中被新增或变更的每一项: + 1. 如果新值大于 `sender` 当前权限等级,则拒绝。 + 8. 否则,允许。 +11. 其他情况下,允许。 + +{{% boxes/note %}} +这些规则的一些后果: + +- 除非你是房间成员,除了初始化创建/加入外,唯一被允许的操作是:加入公开房间;接受或拒绝房间邀请。 +- 要解除对某人的封禁,你的权限等级必须大于等于踢出*和*封禁等级,并且高于目标用户的权限等级。 +{{% /boxes/note %}} diff --git a/locales/zh-Hans/rooms/fragments/v3-handling-redactions.md b/locales/zh-Hans/rooms/fragments/v3-handling-redactions.md new file mode 100644 index 00000000..9acacb64 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v3-handling-redactions.md @@ -0,0 +1,15 @@ +--- +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + +{{% added-in v=3 %}} 在房间版本1和2中,清除操作(redactions)明确属于[授权规则](/rooms/v1/#authorization-rules)第11条。自房间版本3起,这些条件不再适用,如[本版本的授权规则](#authorization-rules)所示。 + +尽管清除操作始终被事件的授权规则接受,但只有在清除事件和被清除的事件都已被接收并且能够被验证后,才能将其发送给客户端。如果这两个事件都有效并已被服务器看到,那么在满足以下任一条件时,服务器会应用清除操作: + +1. 清除事件的 `sender` 的权限等级大于或等于*清除权限等级*(redact level)。 +2. 清除事件的 `sender` 的域名与原事件的 `sender` 的域名一致。 + +如果服务器将应用清除操作,则该清除事件也会被发送给客户端。否则,服务器只会等待有效的配对事件到来,届时可以重新检查上述条件。 diff --git a/locales/zh-Hans/rooms/fragments/v4-event-format.md b/locales/zh-Hans/rooms/fragments/v4-event-format.md new file mode 100644 index 00000000..34ac595e --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v4-event-format.md @@ -0,0 +1,3 @@ +此版本中房间内的事件结构如下: + +{{% definition path="api/server-server/definitions/pdu_v4" %}} \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v4-event-ids.md b/locales/zh-Hans/rooms/fragments/v4-event-ids.md new file mode 100644 index 00000000..c656b8e3 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v4-event-ids.md @@ -0,0 +1,10 @@ +--- +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + +{{% added-in v=4 %}} 事件 ID 是事件的[参考哈希](/server-server-api#calculating-the-reference-hash-for-an-event),其采用一种变体的[无填充 Base64 编码](/appendices#unpadded-base64),将第 62 和第 63 个字符分别替换为 `-` 和 `_`,而不是使用 `+` 和 `/`。这与 [RFC4648 URL 安全型 base64 的定义](https://tools.ietf.org/html/rfc4648#section-5)一致。 + +事件 ID 仍以前缀 `$` 开头,最终可能类似于 `$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg`。 diff --git a/locales/zh-Hans/rooms/fragments/v5-signing-requirements.md b/locales/zh-Hans/rooms/fragments/v5-signing-requirements.md new file mode 100644 index 00000000..1f525760 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v5-signing-requirements.md @@ -0,0 +1,3 @@ +在验证事件签名时,服务器必须强制要求密钥请求中的 `valid_until_ts` 属性至少与所验证事件的 `origin_server_ts` 相同或更大。缺少签名密钥副本的服务器必须尝试通过 [GET /\_matrix/key/v2/server](/server-server-api#get_matrixkeyv2server) 或 [POST /\_matrix/key/v2/query](/server-server-api#post_matrixkeyv2query) API 获取密钥。当使用 `/query` 端点时,服务器必须设置 `minimum_valid_until_ts` 属性,以提示公证服务器在适当情况下尝试刷新密钥。 + +在确定密钥是否有效时,服务器必须采用 `valid_until_ts` 和当前时间起未来 7 天中的较小值。这是为了避免攻击者发布一个在较长时间内有效而无法被主服务器所有者撤销的密钥的情况。 \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v6-canonical-json.md b/locales/zh-Hans/rooms/fragments/v6-canonical-json.md new file mode 100644 index 00000000..19639179 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v6-canonical-json.md @@ -0,0 +1 @@ +服务器必须严格执行 [附录](/appendices#canonical-json) 中规定的 JSON 格式。这意味着在大多数端点会返回 400 `M_BAD_JSON` 错误,或者在联邦通信中丢弃事件。例如,Federation API 的 `/send` 端点会丢弃该事件,而 Client Server API 的 `/send/{eventType}` 端点则会返回 `M_BAD_JSON` 错误。 \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v6-event-format.md b/locales/zh-Hans/rooms/fragments/v6-event-format.md new file mode 100644 index 00000000..c81ef1af --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v6-event-format.md @@ -0,0 +1,3 @@ +本版本中房间内的事件具有以下结构: + +{{% definition path="api/server-server/definitions/pdu_v6" %}} \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v6-redactions.md b/locales/zh-Hans/rooms/fragments/v6-redactions.md new file mode 100644 index 00000000..745870f1 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v6-redactions.md @@ -0,0 +1,27 @@ +在收到编辑事件时,服务器必须移除不在以下列表中的任何键: + +- `event_id` +- `type` +- `room_id` +- `sender` +- `state_key` +- `content` +- `hashes` +- `signatures` +- `depth` +- `prev_events` +- `prev_state` +- `auth_events` +- `origin` +- `origin_server_ts` +- `membership` + +content 对象也必须移除除下列情况外的所有键: + +- [`m.room.member`](/client-server-api#mroommember) 事件类型允许保留 `membership` 键。 +- [`m.room.create`](/client-server-api#mroomcreate) 事件类型允许保留 `creator` 键。 +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) 事件类型允许保留 `join_rule` 键。 +- [`m.room.power_levels`](/client-server-api#mroompower_levels) 事件类型允许保留以下键: + `ban`、`events`、`events_default`、`kick`、`redact`、`state_default`、`users`、 + `users_default`。 +- [`m.room.history_visibility`](/client-server-api#mroomhistory_visibility) 事件类型允许保留 `history_visibility` 键。 \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v8-auth-rules.md b/locales/zh-Hans/rooms/fragments/v8-auth-rules.md new file mode 100644 index 00000000..f3d867b1 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v8-auth-rules.md @@ -0,0 +1,111 @@ +事件必须由 `sender` 属性指示的服务器进行签名。 + +影响授权的状态事件类型包括: + +- [`m.room.create`](/client-server-api#mroomcreate) +- [`m.room.member`](/client-server-api#mroommember) +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) +- [`m.room.power_levels`](/client-server-api#mroompower_levels) +- [`m.room.third_party_invite`](/client-server-api#mroomthird_party_invite) + +{{% boxes/note %}} +当未明确提供时,权限级别将从默认值推断。例如,提及 `sender` 的权限级别也可以指房间中用户的默认权限级别。 +{{% /boxes/note %}} + +{{% boxes/note %}} +`m.room.redaction` 事件与其他事件一样需遵守授权规则。实际上,这意味着除非 `m.room.power_levels` 事件通过 `events` 或 `events_default` 属性为 `m.room.redaction` 事件设置了权限级别要求,否则通常会被授权规则允许。特别地,_redact level_ **不会**被授权规则考虑在内。 + +能够发送撤回事件并不意味着应执行撤回。接收服务器必须执行额外的检查,详见[处理撤回](#handling-redactions)章节。 +{{% /boxes/note %}} + +规则如下: + +1. 如果类型为 `m.room.create`: + 1. 如果存在任何 `prev_events`,则拒绝。 + 2. 如果 `room_id` 的域与 `sender` 的域不匹配,则拒绝。 + 3. 如果存在 `content.room_version` 且不是已识别的版本,则拒绝。 + 4. 如果 `content` 中没有 `creator` 属性,则拒绝。 + 5. 否则,允许。 +2. 考虑事件的 `auth_events`: + 1. 如果对于某个 `type` 和 `state_key` 对存在重复条目,则拒绝。 + 2. 如果存在条目的 `type` 和 `state_key` 与[授权事件选择](/server-server-api#auth-events-selection)算法(按服务器规范描述)指定的不符,则拒绝。 + 3. 如果存在条目本身按[接收 PDU 时执行的检查](/server-server-api/#checks-performed-on-receipt-of-a-pdu)被拒绝,则拒绝。 + 4. 如果条目中没有 `m.room.create` 事件,则拒绝。 +3. 如果房间状态中的 `m.room.create` 事件的 `content` 属性 `m.federate` 为 `false`,并且该事件的 `sender` 域与创建事件的 `sender` 域不匹配,则拒绝。 +4. 如果类型为 `m.room.member`: + 1. 如果没有 `state_key` 属性,或 `content` 中没有 `membership` 属性,则拒绝。 + 2. {{% added-in v=8 %}} + 如果 `content` 中有 `join_authorised_via_users_server` 属性: + 1. 如果事件未被该 key 标识的用户 ID 的 homeserver 有效签名,则拒绝。 + 3. 如果 `membership` 为 `join`: + 1. 如果唯一先前事件为 `m.room.create` 且 `state_key` 为创建者,则允许。 + 2. 如果 `sender` 与 `state_key` 不匹配,则拒绝。 + 3. 如果 `sender` 被封禁,则拒绝。 + 4. 如果 `join_rule` 为 `invite` 或 `knock`,当成员状态为 `invite` 或 `join` 时允许。 + 5. {{% added-in v=8 %}} + 如果 `join_rule` 为 `restricted`: + 1. 如果成员状态为 `join` 或 `invite`,则允许。 + 2. 如果 `content` 中的 `join_authorised_via_users_server` key 不是有足够权限邀请其它用户的用户,则拒绝。 + 3. 否则,允许。 + 6. 如果 `join_rule` 为 `public`,允许。 + 7. 否则,拒绝。 + 4. 如果 `membership` 为 `invite`: + 1. 如果 `content` 包含 `third_party_invite` 属性: + 1. 如果*目标用户*被封禁,则拒绝。 + 2. 如果 `content.third_party_invite` 没有 `signed` 属性,则拒绝。 + 3. 如果 `signed` 没有 `mxid` 和 `token` 属性,则拒绝。 + 4. 如果 `mxid` 不等于 `state_key`,则拒绝。 + 5. 如果当前房间状态中没有 `state_key` 与 `token` 匹配的 `m.room.third_party_invite` 事件,则拒绝。 + 6. 如果 `sender` 与 `m.room.third_party_invite` 的 `sender` 不匹配,则拒绝。 + 7. 如果 `signed` 中的任一签名与 `m.room.third_party_invite` 事件中的任何公钥匹配,则允许。公钥位于 `m.room.third_party_invite` 的 `content` 中: + 1. 在 `public_key` 属性中为单个公钥。 + 2. 在 `public_keys` 属性中为公钥列表。 + 8. 否则,拒绝。 + 2. 如果 `sender` 当前成员状态不是 `join`,则拒绝。 + 3. 如果*目标用户*的当前成员状态为 `join` 或 `ban`,则拒绝。 + 4. 如果 `sender` 的权限级别大于或等于*邀请级别*,允许。 + 5. 否则,拒绝。 + 5. 如果 `membership` 为 `leave`: + 1. 如果 `sender` 与 `state_key` 匹配,且该用户当前的成员状态为 `invite`、`join` 或 `knock` 时允许,否则拒绝。 + 2. 如果 `sender` 当前成员状态不是 `join`,则拒绝。 + 3. 如果*目标用户*的当前成员状态为 `ban` 且 `sender` 的权限级别低于*封禁级别*,则拒绝。 + 4. 如果 `sender` 的权限级别大于或等于*踢出级别*,且*目标用户*的权限级别低于 `sender`,则允许。 + 5. 否则,拒绝。 + 6. 如果 `membership` 为 `ban`: + 1. 如果 `sender` 当前成员状态不是 `join`,则拒绝。 + 2. 如果 `sender` 的权限级别大于或等于*封禁级别*,且*目标用户*的权限级别低于 `sender`,则允许。 + 3. 否则,拒绝。 + 7. 如果 `membership` 为 `knock`: + 1. 如果 `join_rule` 不是 `knock`,则拒绝。 + 2. 如果 `sender` 与 `state_key` 不匹配,则拒绝。 + 3. 如果 `sender` 当前的成员状态不是 `ban`、`invite` 或 `join`,则允许。 + 4. 否则,拒绝。 + 8. 否则,成员状态未知。拒绝。 +5. 如果 `sender` 当前的成员状态不是 `join`,拒绝。 +6. 如果类型为 `m.room.third_party_invite`: + 1. 只有当 `sender` 当前的权限级别大于或等于*邀请级别*时,允许。 +7. 如果事件类型的*所需权限级别*大于 `sender` 的权限级别,拒绝。 +8. 如果事件含有以 `@` 开头的 `state_key` 且与 `sender` 不匹配,则拒绝。 +9. 如果类型为 `m.room.power_levels`: + 1. 如果 `content` 中 `users` 属性不是一个有效的对象(主键为合法用户 ID,值为整数或可转为整数的字符串),则拒绝。 + 2. 如果房间中没有之前的 `m.room.power_levels` 事件,允许。 + 3. 对于 `users_default`、`events_default`、`state_default`、`ban`、`redact`、`kick`、`invite` 属性,检查它们是否有新增、更改或移除。对每个更改项: + 1. 如果当前值高于 `sender` 当前权限级别,则拒绝。 + 2. 如果新值高于 `sender` 当前权限级别,则拒绝。 + 4. 针对 `events` 或 `notifications` 属性中被更改或移除的每个条目: + 1. 如果当前值大于 `sender` 当前权限级别,则拒绝。 + 5. 对于向 `events` 或 `notifications` 属性新增或更改的每个条目: + 1. 如果新值大于 `sender` 当前权限级别,则拒绝。 + 6. 除了 `sender` 自身的条目外,对 `users` 属性被更改或移除的每个条目: + 1. 如果当前值大于等于 `sender` 当前权限级别,则拒绝。 + 7. 对于向 `users` 属性新增或更改的每个条目: + 1. 如果新值大于 `sender` 当前权限级别,则拒绝。 + 8. 否则,允许。 +10. 否则,允许。 + +{{% boxes/note %}} +这些规则的一些结果: + +- 除非你是房间成员,否则唯一被允许的操作(除初始创建/加入外)为:加入公开房间、接受或拒绝房间邀请。 +- 要解除某人的封禁,你必须拥有大于等于踢出*和*封禁级别的权限级别,*且*比目标用户的权限级别高。 +{{% /boxes/note %}} \ No newline at end of file diff --git a/locales/zh-Hans/rooms/fragments/v9-redactions.md b/locales/zh-Hans/rooms/fragments/v9-redactions.md new file mode 100644 index 00000000..0a046ef7 --- /dev/null +++ b/locales/zh-Hans/rooms/fragments/v9-redactions.md @@ -0,0 +1,25 @@ +收到编辑事件时,服务器必须移除所有不在以下列表中的键: + +- `event_id` +- `type` +- `room_id` +- `sender` +- `state_key` +- `content` +- `hashes` +- `signatures` +- `depth` +- `prev_events` +- `prev_state` +- `auth_events` +- `origin` +- `origin_server_ts` +- `membership` + +对于内容(content)对象,也必须移除其所有键,除非该事件类型属于以下之一: + +- [`m.room.member`](/client-server-api#mroommember) 允许的键为 `membership`、`join_authorised_via_users_server`。 +- [`m.room.create`](/client-server-api#mroomcreate) 允许的键为 `creator`。 +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) 允许的键为 `join_rule`、`allow`。 +- [`m.room.power_levels`](/client-server-api#mroompower_levels) 允许的键为 `ban`、`events`、`events_default`、`kick`、`redact`、`state_default`、`users`、`users_default`。 +- [`m.room.history_visibility`](/client-server-api#mroomhistory_visibility) 允许的键为 `history_visibility`。 \ No newline at end of file diff --git a/locales/zh-Hans/rooms/v1.md b/locales/zh-Hans/rooms/v1.md new file mode 100644 index 00000000..2fc6ae20 --- /dev/null +++ b/locales/zh-Hans/rooms/v1.md @@ -0,0 +1,90 @@ +--- +title: 房间版本 1 +type: docs +weight: 10 +version: 1 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +此房间版本是房间的第一个版本,包含了其他房间版本的构建基础。 + +## 客户端注意事项 + +本地实现删除算法的客户端应参考下方的[删除](#redactions)部分。 + +### 删除 + +{{% rver-fragment name="v1-redactions" %}} + +## 服务器实现组成部分 + +{{% boxes/warning %}} +本节信息仅供服务器实现者参考。使用客户端-服务器 API 的应用通常不受此处细节的影响。针对客户端注意事项的上一节才是客户端-服务器 API 相关用例应参考的资源。 +{{% /boxes/warning %}} + +此处定义的算法仅适用于版本 1 的房间。其他房间版本可能会采用其他算法,因此服务器在执行相关算法前应先确认所处理的是哪一版本的房间。 + +{{% boxes/warning %}} +尽管目前有许多房间在使用房间版本 1,但已知其会出现一些不理想的效果。支持房间版本 1 的服务器应注意,其限制通常应当更为宽松,同时可能会出现不一致的情况。 +{{% /boxes/warning %}} + +### 删除 + +[见上文](#redactions)。 + +### 事件 ID + +{{% rver-fragment name="v1-event-ids" %}} + +### 事件格式 + +版本 1 房间中的事件结构如下: + +{{% definition path="api/server-server/definitions/pdu_v1" %}} + +#### 已弃用的事件内容 schema + +{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}} + +{{% rver-fragment name="v1-stringy-power-levels" %}} + +### 授权规则 + +{{% rver-fragment name="v1-auth-rules" %}} + +### 状态解析 + +{{% boxes/warning %}} +已知房间版本 1 存在一些 bug 可能导致房间状态回滚到之前的旧版本。例如,这可能导致已加入房间的用户被移除,管理员和版主丢失其权限,甚至被封禁的用户能够重新加入。其它状态事件,如房间名称或主题,也可能会回滚到之前的版本。 + +这些问题在房间版本 2 引入的状态解析算法中已被修复。 +{{% /boxes/warning %}} + +事件 *E* 之后的房间状态 *S′*(*E*),以 *E* 之前的房间状态 *S*(*E*) 为基础定义,并且取决于 *E* 是状态事件还是消息事件: + +- 如果 *E* 是消息事件,则 *S′(E)* = *S(E)*。 +- 如果 *E* 是状态事件,则 *S′(E)* 等于 *S(E)*,但将对应于 *E* 的 `event_type` 和 `state_key` 的条目替换为 *E* 的 `event_id`。 + +事件 *E* 之前的房间状态 *S(E)*,等于 *E* 的所有 `prev_events` {*E′*, *E″*, …} 之后生成的状态集 {*S′(E′)*, *S′(E″)*, …} 的*解析*结果。 + +多状态的*解析*规则如下。最终解析出的状态通过多轮遍历构建;我们以 *R* 表示当前已解析的中间结果。 + +- 首先,将 *R* 设为所有需要解析的状态的并集,排除任何*冲突*事件。 +- 第一步先解决 `m.room.power_levels` 相关事件的冲突。如果没有冲突,则跳过此步骤;否则: + - 把要解析的状态中的所有 `m.room.power_levels` 事件收集成一个列表。 + - 按照 `depth` 升序、`sha1(event_id)` 降序排序。 + - 将列表中的第一个事件加入 *R*。 + - 对于列表后续每个事件,检查该事件是否被授权在状态 *R* 的房间中触发。如果允许,则用该事件更新 *R*,继续处理下一个事件;如不允许,则终止,跳过到下一步解决 `m.room.join_rules` 事件。 +- 针对 `m.room.join_rules` 事件的冲突,重复上述过程。 +- 针对 `m.room.member` 事件的冲突,也同样重复上述过程。 +- 其余事件对授权规则没有影响,因此对于其它所有冲突,只需选择通过 *R* 中的身份验证、且拥有最大 depth 和最小 `sha1(event_id)` 的事件,将其加入 *R*。 + +*冲突*指的是两个状态针对同一 `(event_type, state_key)` 拥有不同 `event_id`。因此受影响的事件被称为*冲突*事件。 + +### 标准 JSON + +{{% rver-fragment name="v1-canonical-json" %}} diff --git a/locales/zh-Hans/rooms/v10.md b/locales/zh-Hans/rooms/v10.md new file mode 100644 index 00000000..d01071e4 --- /dev/null +++ b/locales/zh-Hans/rooms/v10.md @@ -0,0 +1,207 @@ +--- +title: 房间版本 10 +type: docs +weight: 100 +version: 10 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +该房间版本基于[版本 9](/rooms/v9),强制要求权限等级(power level)值为整数,并引入了新的 `knock_restricted` 加入规则,使潜在成员更容易加入此类房间。 + +## 客户端注意事项 + +此房间版本增加了新的 `knock_restricted` 加入规则,允许房间的潜在成员通过敲门(在[房间版本 7](/rooms/v7)中引入)或“加入限制”(在[房间版本 8](/rooms/v8)中引入并在[房间版本 9](/rooms/v9)中细化)两种方式加入房间。 + +客户端应针对具备该规则的房间做出相应渲染。例如: + +``` +该房间为: +[ ] 公开 +[x] 私有 + +加入规则(公开时禁用): +[x] 允许 `#space:example.org` 的成员加入 +[x] 允许敲门 +``` + +本地实现事件修订(redaction)算法的客户端,应参考下文的[修订](#redactions)章节以获得完整概览。 + +## 服务器实现要素 + +{{% boxes/warning %}} +本节内容仅适用于服务器实现者。使用客户端-服务器 API 的应用通常不受此处细节影响。有关客户端注意事项的部分才是客户端-服务器 API 用例应参考的资料。 +{{% /boxes/warning %}} + +[房间版本 7](/rooms/v7) 增加了“敲门”,[房间版本 8](/rooms/v8) 增加了“加入限制”(并被 [房间版本 9](/rooms/v9) 进一步细化)——两者都为潜在成员提供了加入方式,但过去无法将两种机制结合使用。该房间版本引入了一种新的 `knock_restricted` 加入规则,混合了两种行为,允许用户只要满足 `restricted` 或 `knock` 加入规则之一即可加入房间。 + +此外,该房间版本还要求权限等级事件中的数值必须为整数类型,而不能是其它房间版本为兼容性允许的字符串表示形式。 + +房间版本 10 基于房间版本 9,具体变化如下所述。 + +### 事件格式 + +该房间版本未对事件格式进行修改。详见[下文](#event-format-1)当前事件格式的详细信息。 + +#### 已弃用事件内容模式 + +虽然本房间版本未专门改变事件格式,但某些已弃用行为被严格禁止支持。 + +##### `m.room.power_levels` 事件的值必须为整数 + +在其它房间版本中,例如 [v9](/rooms/v9/#mroompower_levels-events-accept-values-as-strings),权限等级可以为兼容性目的用字符串表示。 + +本房间版本移除了此项兼容——权限等级在本版本中**不得**用字符串表示。结构不正确的权限等级将按照下述授权规则被拒绝。 + +### 授权规则 + +事件必须由 `sender` 属性所标记的服务器签名。 + +影响授权的状态事件类型有: + +- [`m.room.create`](/client-server-api#mroomcreate) +- [`m.room.member`](/client-server-api#mroommember) +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) +- [`m.room.power_levels`](/client-server-api#mroompower_levels) +- [`m.room.third_party_invite`](/client-server-api#mroomthird_party_invite) + +{{% boxes/note %}} +如果没有明确指定权限等级,将采用默认值。例如,对 `sender` 权限等级的引用也可视为房间用户的默认权限等级。 +{{% /boxes/note %}} + +{{% boxes/note %}} +`m.room.redaction` 事件在授权规则上的处理与其他事件一致。实际上,除非 `m.room.power_levels` 通过 `events` 或 `events_default` 属性要求 `m.room.redaction` 事件具有特定权限等级,否则通常是被授权规则所允许。需要注意的是,“修订等级”**不会**被授权规则考虑。 + +可以发送修订事件的权限,并不意味着修订应该被执行。接收服务器必须按照[处理修订](#handling-redactions)章节所述进行额外检查。 +{{% /boxes/note %}} + +规则如下: + +1. 若类型为 `m.room.create`: + 1. 若存在任何 `prev_events`,则拒绝。 + 2. 若 `room_id` 的域名与 `sender` 的域名不符,则拒绝。 + 3. 若 `content.room_version` 存在且不是已识别的版本,则拒绝。 + 4. 若 `content` 没有 `creator` 属性,则拒绝。 + 5. 否则,允许。 +2. 针对事件的 `auth_events`: + 1. 若对某一 `type` 和 `state_key` 对有重复条目,则拒绝。 + 2. 若存在其 `type` 和 `state_key` 不符合[授权事件选择](/server-server-api#auth-events-selection)算法的条目,则拒绝。 + 3. 若存在在[接收 PDU 时的检查](/server-server-api/#checks-performed-on-receipt-of-a-pdu)中已被拒绝的条目,则拒绝。 + 4. 若未包含一个 `m.room.create` 事件,则拒绝。 +3. 若房间状态中的 `m.room.create` 事件的 `content.m.federate` 属性被设为 `false`,且该事件的 `sender` 域名与创建事件的 `sender` 域名不符,则拒绝。 +4. 若类型为 `m.room.member`: + 1. 若没有 `state_key` 属性,或 `content` 中没有 `membership` 属性,则拒绝。 + 2. 若 `content` 有 `join_authorised_via_users_server` 键: + 1. 若事件未由该键指向的用户的 homeserver 有效签名,则拒绝。 + 3. 若 `membership` 为 `join`: + 1. 如果唯一的先前事件为 `m.room.create` 且 `state_key` 为创建者,则允许。 + 2. 若 `sender` 不等于 `state_key`,则拒绝。 + 3. 若 `sender` 被封禁,则拒绝。 + 4. 若 `join_rule` 为 `invite` 或 `knock`,且成员状态为 `invite` 或 `join`,则允许。 + 5. {{% changed-in v=10 %}} + 若 `join_rule` 为 `restricted` 或 `knock_restricted`: + 1. 若成员状态为 `join` 或 `invite`,则允许。 + 2. 若 `content` 中的 `join_authorised_via_users_server` 不是有足够权限邀请其它用户的用户,则拒绝。 + 3. 否则,允许。 + 6. 若 `join_rule` 为 `public`,则允许。 + 7. 否则,拒绝。 + 4. 若 `membership` 为 `invite`: + 1. 若 `content` 中有 `third_party_invite` 属性: + 1. 若目标用户已被封禁,则拒绝。 + 2. 若 `content.third_party_invite` 没有 `signed` 属性,则拒绝。 + 3. 若 `signed` 没有 `mxid` 和 `token` 属性,则拒绝。 + 4. 若 `mxid` 不等于 `state_key`,则拒绝。 + 5. 若当前房间状态下没有 `state_key` 等于 `token` 的 `m.room.third_party_invite` 事件,则拒绝。 + 6. 若 `sender` 不等于 `m.room.third_party_invite` 的 `sender`,则拒绝。 + 7. 若 `signed` 中的任何签名与 `m.room.third_party_invite` 事件中的任何公钥匹配,则允许。公钥包含于 `m.room.third_party_invite` 的 `content` 中: + 1. 属性 `public_key` 的单个公钥。 + 2. 属性 `public_keys` 的公钥列表。 + 8. 否则,拒绝。 + 2. 若 `sender` 当前成员状态不是 `join`,则拒绝。 + 3. 若目标用户当前状态为 `join` 或 `ban`,则拒绝。 + 4. 若 `sender` 权限等级大于等于邀请等级,允许。 + 5. 否则,拒绝。 + 5. 若 `membership` 为 `leave`: + 1. 若 `sender` 匹配 `state_key`,则仅当用户当前状态为 `invite`、`join` 或 `knock` 时允许。 + 2. 若 `sender` 的当前成员状态不是 `join`,则拒绝。 + 3. 若目标用户当前成员状态为 `ban` 且 `sender` 权限等级低于封禁等级,则拒绝。 + 4. 若 `sender` 权限等级大于等于踢人等级且目标用户权限等级小于 `sender`,则允许。 + 5. 否则,拒绝。 + 6. 若 `membership` 为 `ban`: + 1. 若 `sender` 当前成员状态不是 `join`,则拒绝。 + 2. 若 `sender` 权限等级大于等于封禁等级且目标用户权限等级小于 `sender`,则允许。 + 3. 否则,拒绝。 + 7. 若 `membership` 为 `knock`: + 1. {{% changed-in v=10 %}} + 若 `join_rule` 非 `knock` 或 `knock_restricted`,则拒绝。 + 2. 若 `sender` 不等于 `state_key`,则拒绝。 + 3. 若 `sender` 当前成员状态不是 `ban`、`invite` 或 `join`,则允许。 + 4. 否则,拒绝。 + 8. 否则,成员状态未知,拒绝。 +5. 若 `sender` 当前成员状态不是 `join`,则拒绝。 +6. 若类型为 `m.room.third_party_invite`: + 1. 仅当 `sender` 权限等级大于等于邀请等级时允许。 +7. 若该事件类型所需权限等级大于 `sender` 权限等级,则拒绝。 +8. 若事件的 `state_key` 以 `@` 开头且与 `sender` 不一致,则拒绝。 +9. 若类型为 `m.room.power_levels`: + 1. {{% added-in v=10 %}} + 若 `content` 中 `users_default`、`events_default`、`state_default`、`ban`、`redact`、`kick` 或 `invite` 属性存在且类型不是整数,则拒绝。 + 2. {{% added-in v=10 %}} + 若 `content` 中 `events` 或 `notifications` 属性存在,且不是值为整数的对象,则拒绝。 + 3. 若 `content` 中的 `users` 属性不是 key 为有效用户ID、值为整数的对象,则拒绝。 + 4. 若房间中没有先前的 `m.room.power_levels` 事件,则允许。 + 5. 对 `users_default`、`events_default`、`state_default`、`ban`、`redact`、`kick`、`invite` 属性,检查它们是否被添加、更改或移除。对于每一个变化项: + 1. 若当前值大于 `sender` 的当前权限等级,则拒绝。 + 2. 若新值大于 `sender` 当前权限等级,则拒绝。 + 6. 对于变更或移除的 `events` 或 `notifications` 属性的每个条目: + 1. 若当前值大于 `sender` 当前权限等级,则拒绝。 + 7. 对于新增或变更的 `events` 或 `notifications` 属性的每个条目: + 1. 若新值大于 `sender` 当前权限等级,则拒绝。 + 8. 对于除 `sender` 自身外,变更或移除的 `users` 属性每个条目: + 1. 若当前值大于等于 `sender` 当前权限等级,则拒绝。 + 9. 对于新增或变更的 `users` 属性每个条目: + 1. 若新值大于 `sender` 当前权限等级,则拒绝。 + 10. 否则,允许。 +10. 否则,允许。 + +{{% boxes/note %}} +这些规则的一些后果: + +- 除非你是该房间的成员,否则仅允许的操作(除初始创建/加入外)为:加入公开房间;接受或拒绝房间邀请。 +- 若想为某人解除封禁,你必须拥有大于等于踢人和封禁等级的权限,并且高于目标用户的权限等级。 +{{% /boxes/note %}} + +## 与 v9 保持一致内容 + +以下章节自 v9 起未改动,为资料完整起见在此列出。 + +### 修订(Redactions) + +{{% rver-fragment name="v9-redactions" %}} + +### 处理修订 + +{{% rver-fragment name="v3-handling-redactions" %}} + +### 事件ID + +{{% rver-fragment name="v4-event-ids" %}} + +### 事件格式 + +{{% rver-fragment name="v6-event-format" %}} + +### 状态解析 + +{{% rver-fragment name="v2-state-res" %}} + +### 规范 JSON + +{{% rver-fragment name="v6-canonical-json" %}} + +### 签名密钥有效期 + +{{% rver-fragment name="v5-signing-requirements" %}} diff --git a/locales/zh-Hans/rooms/v11.md b/locales/zh-Hans/rooms/v11.md new file mode 100644 index 00000000..e8e879c8 --- /dev/null +++ b/locales/zh-Hans/rooms/v11.md @@ -0,0 +1,202 @@ +--- +title: 房间版本 11 +type: docs +weight: 100 +version: 11 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +本房间版本基于[版本 10](/rooms/v10) ,并进一步明确了撤回(redaction)规则。 + +## 客户端注意事项 + +### 撤回 + +{{% added-in v=11 %}} 顶层的 `origin`、`membership` 和 `prev_state` 属性不再受到撤回保护。[`m.room.create`](/client-server-api#mroomcreate) 事件现在会保留整个 `content` 属性。[`m.room.redaction`](/client-server-api#mroomredaction) 事件保留 `content` 下的 `redacts` 属性。[`m.room.power_levels`](/client-server-api#mroompower_levels) 事件保留 `content` 下的 `invite` 属性。 + +完整的撤回算法如下。 + +{{% rver-fragment name="v11-redactions" %}} + +### 事件格式 + +客户端不应再依赖 [`m.room.create`](/client-server-api#mroomcreate) 事件的 `content` 中的 `creator` 属性。在所有房间版本中,客户端可以通过 `sender` 属性来确定房间的创建者。 + +[`m.room.redaction`](/client-server-api#mroomredaction) 事件的格式已被修改。客户端应当在 `content` 下查找 `redacts` 键,而不是顶层属性。 + +[`m.room.member`](/client-server-api#mroommember) 事件的 `third_party_invite` 键不再被撤回,但撤回后仅包含 `signed` 键。 + +## 服务端实现组件 + +{{% boxes/warning %}} +本部分内容仅供服务端实现者参考。使用 Client-Server API 的应用通常不受此处细节影响。上面“客户端注意事项”部分才是 Client-Server API 使用场景应关注的内容。 +{{% /boxes/warning %}} + +本房间版本更新了撤回算法,并修改了服务端应如何创建 `m.room.create` 和 `m.room.redaction` 事件。 + +房间版本 11 以版本 10 为基础,并有以下要点。 + +### 撤回 + +[见上文](#redactions)。 + +### 事件格式 + +核心事件格式与[房间版本 10](/rooms/v10#event-format) 相同。不过,该房间版本改变了某些事件类型的部分属性。 + +{{% rver-fragment name="v11-event-format" %}} + +#### 移除 `m.room.create` 事件的 `creator` 属性 + +`m.room.create` 事件的 `content` 不再包含 `creator` 属性,此前它总是与事件的 `sender` 属性等同。 + +#### 将 `m.room.redaction` 事件的 `redacts` 属性移入 `content` + +`m.room.redaction` 事件的 `redacts` 属性已从事件的顶层属性移到事件的 `content` 属性下。 + +为向后兼容旧版客户端,服务端在通过 Client-Server API 提供此类事件时,应在顶层添加 `redacts` 属性。 + +为更好兼容新版客户端,服务端在向*旧版*房间版本提供此类事件时,应在 `content` 下添加 `redacts` 属性。 + +### 授权规则 + +事件必须由 `sender` 属性指定的服务器签名。 + +影响授权的状态事件类型有: + +- [`m.room.create`](/client-server-api#mroomcreate) +- [`m.room.member`](/client-server-api#mroommember) +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) +- [`m.room.power_levels`](/client-server-api#mroompower_levels) +- [`m.room.third_party_invite`](/client-server-api#mroomthird_party_invite) + +{{% boxes/note %}} +未显式设置时,权限级别会采用默认值。例如,提及 `sender` 的权限级别,也可以指代房间内用户的默认权限级别。 +{{% /boxes/note %}} + +{{% boxes/note %}} +`m.room.redaction` 事件与其它事件一样受到授权规则约束。实际上,除非 `m.room.power_levels` 事件通过 `events` 或 `events_default` 属性对 `m.room.redaction` 事件设置了权限要求,否则这些事件通常会被允许。特别注意,撤回权限(_redact level_)**不会**被授权规则考虑。 + +具有发送撤回事件的能力,并不意味着该撤回一定会被执行。接收服务器必须按[撤回处理](#handling-redactions)部分所述进行额外检查。 +{{% /boxes/note %}} + +规则如下: + +1. {{% changed-in v=11 %}} + 如果类型为 `m.room.create`: + 1. 如果有任何 `prev_events`,则拒绝。 + 2. 如果 `room_id` 的域名与 `sender` 的域名不一致,则拒绝。 + 3. 如果 `content.room_version` 存在且不是已知版本,则拒绝。 + 4. 其他情况,允许。 +2. 针对事件的 `auth_events`: + 1. 如果某一对 `type` 和 `state_key` 存在重复项,则拒绝。 + 2. 如果有 `type` 和 `state_key` 未按[授权事件选择](/server-server-api#auth-events-selection)算法选取,拒绝。 + 3. 如果有条目在[PDU接收时的检查](/server-server-api/#checks-performed-on-receipt-of-a-pdu)中被拒绝,则拒绝。 + 4. 如果没有 `m.room.create` 事件,被拒绝。 +3. 如果房间状态下 `m.room.create` 事件的 `content` 的 `m.federate` 属性为 `false`,且当前事件的 `sender` 域与创建事件的 `sender` 域不一致,则拒绝。 +4. 如果类型为 `m.room.member`: + 1. 如果没有 `state_key` 属性,或 `content` 中没有 `membership` 属性,拒绝。 + 2. 如果 `content` 包含 `join_authorised_via_users_server`: + 1. 如果事件未被该属性指定用户的 homeserver 合法签名,则拒绝。 + 3. 如果 `membership` 为 `join`: + 1. {{% changed-in v=11 %}} + 若唯一的前序事件是 `m.room.create` 且 `state_key` 为 `m.room.create` 的 sender,则允许。 + 2. 如果 `sender` 不等于 `state_key`,拒绝。 + 3. 如果 `sender` 被禁言,拒绝。 + 4. 若 `join_rule` 为 `invite` 或 `knock`,且会员状态为 `invite` 或 `join`,则允许。 + 5. 若 `join_rule` 为 `restricted` 或 `knock_restricted`: + 1. 若会员状态为 `join` 或 `invite`,允许。 + 2. 如果 `content` 中的 `join_authorised_via_users_server` 不是有权邀请用户的用户,拒绝。 + 3. 其他情况,允许。 + 6. 若 `join_rule` 为 `public`,允许。 + 7. 其他情况,拒绝。 + 4. 如果 `membership` 为 `invite`: + 1. 如果 `content` 有 `third_party_invite` 属性: + 1. 如目标用户已被禁言,拒绝。 + 2. 如果 `content.third_party_invite` 缺少 `signed` 属性,拒绝。 + 3. 如果 `signed` 不包含 `mxid` 和 `token` 属性,拒绝。 + 4. 如果 `mxid` 不等于 `state_key`,拒绝。 + 5. 若当前房间状态没有 `state_key` 匹配 `token` 的 `m.room.third_party_invite` 事件,拒绝。 + 6. 如果 `sender` 不等于 `m.room.third_party_invite` 的 sender,拒绝。 + 7. 若 `signed` 中任何签名匹配 `m.room.third_party_invite` 事件中的公钥,则允许。公钥位于 `content` 的如下属性中: + 1. `public_key` 属性内的单个公钥; + 2. `public_keys` 属性内的公钥列表。 + 8. 否则,拒绝。 + 2. 如果 `sender` 当前会员状态不是 `join`,拒绝。 + 3. 如果目标用户当前会员状态为 `join` 或 `ban`,拒绝。 + 4. 如果 `sender` 的权限级别大于等于邀请级别,允许。 + 5. 否则,拒绝。 + 5. 如果 `membership` 为 `leave`: + 1. 若 `sender` 等于 `state_key`,仅当此用户当前会员状态为 `invite`、`join` 或 `knock` 时允许。 + 2. 如果 `sender` 的当前会员状态不是 `join`,拒绝。 + 3. 若目标用户当前会员状态为 `ban`,且 `sender` 权限小于禁言级别,拒绝。 + 4. 若 `sender` 权限大于等于踢出级别,且目标用户权限低于 `sender` 权限,允许。 + 5. 否则,拒绝。 + 6. 如果 `membership` 为 `ban`: + 1. 若 `sender` 当前会员状态不是 `join`,拒绝。 + 2. 若 `sender` 权限大于等于禁言级别,且目标用户权限低于 `sender` 权限,允许。 + 3. 否则,拒绝。 + 7. 如果 `membership` 为 `knock`: + 1. 若 `join_rule` 不是 `knock` 或 `knock_restricted`,拒绝。 + 2. 若 `sender` 不等于 `state_key`,拒绝。 + 3. 若 `sender` 当前会员状态不是 `ban`、`invite` 或 `join`,允许。 + 4. 否则,拒绝。 + 8. 其他未知会员状态,拒绝。 +5. 如果 `sender` 当前会员状态不是 `join`,拒绝。 +6. 若类型为 `m.room.third_party_invite`: + 1. 仅当 `sender` 当前权限大于等于邀请级别时允许。 +7. 如事件类型所需权限级别大于 `sender` 权限级别,拒绝。 +8. 如果事件有 `state_key` 以 `@` 开头,且不等于 `sender`,拒绝。 +9. 若类型为 `m.room.power_levels`: + 1. 如果 `content` 内的 `users_default`、`events_default`、`state_default`、`ban`、`redact`、`kick` 或 `invite` 属性存在且不是整数,拒绝。 + 2. 如果 `content` 内的 `events` 或 `notifications` 属性存在,且不是值为整数的对象,拒绝。 + 3. 如果 `content` 内的 `users` 属性不是键为合法用户ID、值为整数的对象,拒绝。 + 4. 如果房间中不存在先前的 `m.room.power_levels` 事件,允许。 + 5. 对于 `users_default`、`events_default`、`state_default`、`ban`、`redact`、`kick`、`invite`,如有添加、变更或删除,每项需检查: + 1. 当前值大于 `sender` 当前权限,拒绝。 + 2. 新值大于 `sender` 当前权限,拒绝。 + 6. 对于 `events` 或 `notifications` 属性中被更改或移除的每一项: + 1. 当前值大于 `sender` 当前权限,拒绝。 + 7. 对于 `events` 或 `notifications` 中被添加或更改的每一项: + 1. 新值大于 `sender` 当前权限,拒绝。 + 8. 对于除自身外的 `users` 属性中被更改或移除的每一项: + 1. 当前值大于等于 `sender` 当前权限,拒绝。 + 9. 对于 `users` 属性中被添加或更改的每一项: + 1. 新值大于 `sender` 当前权限,拒绝。 + 10. 其他情况,允许。 +10. 其他情况,允许。 + +{{% boxes/note %}} +这些规则的部分结果: + +- 除非你是房间成员,唯一允许的操作(除初始创建/加入外)只有加入公开房间,以及接受或拒绝房间邀请。 +- 取消禁言某人,你必须同时具有不小于踢出和禁言级别的权限,且权限要高于目标用户。 +{{% /boxes/note %}} + +## 与 v10 一致 + +以下章节自 v10 起未修改,为完整性而保留。 + +### 撤回处理 + +{{% rver-fragment name="v3-handling-redactions" %}} + +### 事件 ID + +{{% rver-fragment name="v4-event-ids" %}} + +### 状态解析 + +{{% rver-fragment name="v2-state-res" %}} + +### 规范化 JSON + +{{% rver-fragment name="v6-canonical-json" %}} + +### 签名密钥有效期 + +{{% rver-fragment name="v5-signing-requirements" %}} diff --git a/locales/zh-Hans/rooms/v2.md b/locales/zh-Hans/rooms/v2.md new file mode 100644 index 00000000..40f3eb24 --- /dev/null +++ b/locales/zh-Hans/rooms/v2.md @@ -0,0 +1,63 @@ +--- +title: 房间版本 2 +type: docs +weight: 20 +version: 2 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +本房间版本在 [版本 1](/rooms/v1) 的基础上进行了改进,采用了更优的状态解析算法。 + +## 客户端注意事项 + +本房间版本未引入与客户端相关的新注意事项。本地实现消息删除算法的客户端应参考下方的 [消息删除](#redactions) 部分,全面了解该算法。 + +## 服务器实现要素 + +{{% boxes/warning %}} +本节的信息仅供服务器实现者参考。依赖于客户端-服务器 API 的应用通常不受本节内容影响,可以放心忽略。 +{{% /boxes/warning %}} + +房间版本 2 采用了 [房间版本 1](/rooms/v1) 的基础组件,仅更改了状态解析算法。 + +### 状态解析 + +{{% added-in v=2 %}} + +{{% rver-fragment name="v2-state-res" %}} + +## 与 v1 保持一致的内容 + +以下部分自 v1 起未作修改,仅为内容完整性保留在此。 + +### 消息删除 + +{{% rver-fragment name="v1-redactions" %}} + +### 事件 ID + +{{% rver-fragment name="v1-event-ids" %}} + +### 事件格式 + +本版本房间中的事件具有如下结构: + +{{% definition path="api/server-server/definitions/pdu_v1" %}} + +#### 已弃用的事件内容模式 + +{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}} + +{{% rver-fragment name="v1-stringy-power-levels" %}} + +### 授权规则 + +{{% rver-fragment name="v1-auth-rules" %}} + +### 规范 JSON + +{{% rver-fragment name="v1-canonical-json" %}} diff --git a/locales/zh-Hans/rooms/v3.md b/locales/zh-Hans/rooms/v3.md new file mode 100644 index 00000000..28c7a15a --- /dev/null +++ b/locales/zh-Hans/rooms/v3.md @@ -0,0 +1,85 @@ +--- +title: 房间版本 3 +type: docs +weight: 30 +version: 3 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +该房间版本在 [版本 2](/rooms/v2) 的基础上,改进了事件格式。 + +## 客户端注意事项 + +此房间版本更改了发送给客户端的事件 ID 格式。客户端应注意,这些事件 ID 可能包含斜杠和其他潜在有问题的字符。客户端应将事件 ID 视为不透明标识符,不应尝试对其进行解析或转换(这一点与其他房间版本相同)。 + +客户端应预期事件 ID 的格式将由 `$randomstring:example.org` 变为类似 `$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk`(注意没有域名,且可能出现斜杠等特殊字符)。 + +虽然在本房间版本中未作更改,但实现本地化脱敏算法的客户端应参阅下文 [脱敏](#redactions) 部分获取完整说明。 + +## 服务器实现组件 + +{{% boxes/warning %}} +本节所含信息仅供服务器开发者参考。使用 Client-Server API 的应用通常不受这里涉及的细节影响。上面关于客户端注意事项的部分才是 Client-Server API 相关用例应参考的资源。 +{{% /boxes/warning %}} + +房间版本 3 除采用此处描述的事件格式外,也遵循了 [房间版本 2](/rooms/v2) 的其余行为规范。 + +### 处理脱敏 + +{{% rver-fragment name="v3-handling-redactions" %}} + +### 事件 ID + +{{% boxes/rationale %}} +在其他房间版本(即版本 1 和 2)中,事件 ID 是与事件其他内容分离的独立字段,必须单独进行追踪。这样会导致服务器在收到多个具有相同 ID 的事件时(无论是在同一房间还是不同房间),很难区分应当采用哪一个事件。通过移除专有事件 ID,服务器需通过事件的哈希值来确定其 ID。 +{{% /boxes/rationale %}} + +{{% added-in v=3 %}} 事件 ID 是该事件的[引用哈希](/server-server-api#calculating-the-reference-hash-for-an-event),采用[无填充 Base64](/appendices#unpadded-base64) 编码,并以 `$` 前缀。采用此方式生成的事件 ID 形如 `$CD66HAED5npg6074c6pDtLKalHjVfYb2q4Q3LZgrW6o`。 + +### 事件格式 + +当事件通过联邦协议传递时,将不再包含 `event_id` 字段。接收服务器应自行计算相应的事件 ID。 + +此外,`auth_events` 和 `prev_events` 字段的格式也被更改:不再是 `(event_id, hash)` 对的列表,而是直接为事件 ID 的普通列表。 + +事件格式的这些更改意味着服务器必须识别所收到事件所在房间的版本,以便能正确解析和处理事件。通过对服务器-服务器 API 的调整(例如在 [`GET /_matrix/federation/v1/make_join/{roomId}/{userId}`](/server-server-api/#get_matrixfederationv1make_joinroomiduserid) 响应中包含 `room_version` 字段),此要求得以实现。 + +v3 房间内事件的完整结构如下所示。 + +{{% definition path="api/server-server/definitions/pdu_v3" %}} + +#### 已弃用的事件内容模式 + +{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}} + +{{% rver-fragment name="v1-stringy-power-levels" %}} + +### 授权规则 + +{{% boxes/note %}} +{{% added-in v=3 %}} `m.room.redaction` 事件与其他事件一样,受授权规则约束。实际上,这通常意味着授权规则会允许其通过,除非 `m.room.power_levels` 事件在其 `events` 或 `events_default` 属性中对 `m.room.redaction` 事件设置了权限要求。特别注意,_脱敏权限等级_(redact level)**不**被授权规则考虑。 + +能够发送脱敏事件并不意味着该脱敏操作就应该被执行。接收服务器必须进行额外的检查,详见[处理脱敏](#handling-redactions)部分。 +{{% /boxes/note %}} + +{{% rver-fragment name="v3-auth-rules" %}} + +## 与 v2 保持一致的部分 + +以下部分自 v2 起未做修改,现为保证完整性仍予以保留。 + +### 脱敏 + +{{% rver-fragment name="v1-redactions" %}} + +### 状态解析 + +{{% rver-fragment name="v2-state-res" %}} + +### 规范化 JSON + +{{% rver-fragment name="v1-canonical-json" %}} diff --git a/locales/zh-Hans/rooms/v4.md b/locales/zh-Hans/rooms/v4.md new file mode 100644 index 00000000..6c819063 --- /dev/null +++ b/locales/zh-Hans/rooms/v4.md @@ -0,0 +1,73 @@ +--- +title: 房间版本 4 +type: docs +weight: 40 +version: 4 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +本房间版本在 [版本 3](/rooms/v3) 的基础上,采用了不同的事件 ID 编码方式。 + +## 客户端注意事项 + +本房间版本更改了发送给客户端的事件 ID 格式。客户端应始终将事件 ID 视为不可理解的标识符,而不应关心其具体格式。在将事件 ID 包含在请求路径中时,客户端仍需对其进行编码。 + +客户端应做好事件 ID 的格式已从 `$randomstring:example.org` 更改为类似 `$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg`(请注意没有域名部分)的准备。 + +虽然本房间版本对此未作更改,但如客户端在本地实现了修订算法,应参考下文的 [修订](#redactions) 部分,了解完整内容。 + +## 服务器实现要点 + +{{% boxes/warning %}} +本节内容仅供服务器实现者参考。使用 Client-Server API 的应用通常不会受到此处细节的影响。上述关于客户端注意事项的部分,才是 Client-Server API 用例应参考的内容。 +{{% /boxes/warning %}} + +房间版本 4 使用了 [房间版本 3](/rooms/v3) 中定义的相同算法,不过在生成事件 ID 时采用了 URL 安全的 base64 编码方式。 + +### 事件 ID + +{{% boxes/rationale %}} +房间版本 3 生成的事件 ID,对于未对事件 ID 编码的客户端实现来说难以正常使用。此外,由于 `/` 字符在某些反向代理软件中会被区别对待,也引发了相关担忧,并在一般管理上带来了不便。 +{{% /boxes/rationale %}} + +{{% rver-fragment name="v4-event-ids" %}} + +## 与 v3 保持一致的部分 + +以下内容自 v3 起未作修改,为保证完整性予以收录。 + +### 修订 + +{{% rver-fragment name="v1-redactions" %}} + +### 处理修订 + +{{% rver-fragment name="v3-handling-redactions" %}} + +### 事件格式 + +事件格式与 [房间版本 3](/rooms/v3#event-format) 相同,但以下示例中的事件 ID 已根据本房间版本的更改进行了更新。 + +{{% rver-fragment name="v4-event-format" %}} + +#### 已废弃的事件内容模式 + +{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}} + +{{% rver-fragment name="v1-stringy-power-levels" %}} + +### 授权规则 + +{{% rver-fragment name="v3-auth-rules" %}} + +### 状态解析 + +{{% rver-fragment name="v2-state-res" %}} + +### 规范化 JSON + +{{% rver-fragment name="v1-canonical-json" %}} diff --git a/locales/zh-Hans/rooms/v5.md b/locales/zh-Hans/rooms/v5.md new file mode 100644 index 00000000..7fcebb2d --- /dev/null +++ b/locales/zh-Hans/rooms/v5.md @@ -0,0 +1,67 @@ +--- +title: 房间版本 5 +type: docs +weight: 50 +version: 5 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +本房间版本基于 [版本 4](/rooms/v4) 构建,同时对事件的签名密钥有效期进行了强制要求。 + +## 客户端注意事项 + +本房间版本未引入任何新的客户端注意事项。如客户端需要本地实现撤回算法,请参阅下方的 [撤回](#撤回) 部分,了解完整的算法概述。 + +## 服务器实现组件 + +{{% boxes/warning %}} +本节内容仅供服务器实现者参考。使用客户端-服务器 API 的应用通常不受此处相关细节的影响。针对客户端-服务器 API 的用例,应以上方客户端注意事项作为参考资源。 +{{% /boxes/warning %}} + +房间版本 5 采用了与 [房间版本 4](/rooms/v4) 定义的相同算法,并确保签名密钥的有效性得到尊重。 + +### 签名密钥有效期 + +{{% rver-fragment name="v5-signing-requirements" %}} + +## 与 v4 保持一致 + +下列部分自 v4 以来未做任何修改,此处为完整性而收录。 + +### 撤回 + +{{% rver-fragment name="v1-redactions" %}} + +### 撤回处理 + +{{% rver-fragment name="v3-handling-redactions" %}} + +### 事件 ID + +{{% rver-fragment name="v4-event-ids" %}} + +### 事件格式 + +{{% rver-fragment name="v4-event-format" %}} + +#### 已弃用的事件内容结构 + +{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}} + +{{% rver-fragment name="v1-stringy-power-levels" %}} + +### 授权规则 + +{{% rver-fragment name="v3-auth-rules" %}} + +### 状态解析 + +{{% rver-fragment name="v2-state-res" %}} + +### 规范化 JSON + +{{% rver-fragment name="v1-canonical-json" %}} diff --git a/locales/zh-Hans/rooms/v6.md b/locales/zh-Hans/rooms/v6.md new file mode 100644 index 00000000..89acac4c --- /dev/null +++ b/locales/zh-Hans/rooms/v6.md @@ -0,0 +1,178 @@ +--- +title: 房间版本 6 +type: docs +weight: 60 +version: 6 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +本房间版本基于 [版本 5](/rooms/v5) 进行构建,同时对事件执行的多项授权规则进行了变更。 + +## 客户端注意事项 + +本房间版本未引入任何新的客户端注意事项。实现本地化撤回算法的客户端,应参考下方 [撤回](#撤回) 章节了解完整算法。 + +### 撤回 + +{{% added-in v=6 %}} `m.room.aliases` 的所有重要意义已从撤回算法中移除。其余规则与以往房间版本保持一致。 + +{{% rver-fragment name="v6-redactions" %}} + +## 服务器实现组件 + +{{% boxes/warning %}} +本节内容仅供服务器实现者参考。使用客户端-服务器 API 的应用通常不会受此处细节影响。上述客户端注意事项章节才是客户端-服务器 API 用例应当参考的资源。 +{{% /boxes/warning %}} + +房间版本 6 对 [房间版本 5](/rooms/v5) 中描述的算法进行了如下更改。 + +### 撤回 + +[见上](#撤回)。 + +### 事件格式 + +{{% added-in v=6 %}} 通过强制执行 [规范化 JSON](#canonical-json),本房间版本降低了 `depth` 限制。 + +{{% rver-fragment name="v6-event-format" %}} + +### 授权规则 + +{{% added-in v=6 %}} 与 `m.room.aliases` 类型事件相关的规则 4 被移除。`m.room.aliases` 事件仍需通过与状态事件相关的授权检查。 + +{{% added-in v=6 %}} 此外,`m.room.power_levels` 类型事件的授权规则现在在 `content` 下包含了 `notifications` 属性。这对规则 10.4 和 10.5(现为 9.4 和 9.5)进行了更新,以同时检查 `events` 属性。 + +事件必须由 `sender` 属性指示的服务器进行签名。 + +影响授权的状态事件类型包括: + +- [`m.room.create`](/client-server-api#mroomcreate) +- [`m.room.member`](/client-server-api#mroommember) +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) +- [`m.room.power_levels`](/client-server-api#mroompower_levels) +- [`m.room.third_party_invite`](/client-server-api#mroomthird_party_invite) + +{{% boxes/note %}} +如未被明确指定,权限等级将按默认值推断。例如,提及 `sender` 权限等级时,也可能指房间中用户的默认权限等级。 +{{% /boxes/note %}} + +{{% boxes/note %}} +`m.room.redaction` 事件与其他事件一样受授权规则约束。实际上,这意味着除非 `m.room.power_levels` 事件通过 `events` 或 `events_default` 属性对 `m.room.redaction` 事件设置了权限要求,否则通常会被授权规则允许。需要注意的是,_redact level_ **不会**被授权规则采纳考虑。 + +能否发送撤回事件,并不意味着撤回操作本身应当被执行。接收服务器必须执行额外检查,详细说明见 [处理撤回](#handling-redactions) 章节。 +{{% /boxes/note %}} + +规则如下: + +1. 若事件类型为 `m.room.create`: + 1. 若包含任何 `prev_events`,则拒绝。 + 2. 若 `room_id` 的域名与 `sender` 的域名不匹配,则拒绝。 + 3. 若 `content.room_version` 存在且不是已识别的版本,则拒绝。 + 4. 若 `content` 未包含 `creator` 属性,则拒绝。 + 5. 否则,允许。 +2. 针对事件的 `auth_events` 考虑如下: + 1. 若同一 `type` 与 `state_key` 对有重复条目,则拒绝。 + 2. 若条目的 `type` 和 `state_key` 未与服务器规范中[授权事件选择](/server-server-api#auth-events-selection)算法规定的一致,则拒绝。 + 3. 若存在在[接收 PDU 时执行检查](/server-server-api/#checks-performed-on-receipt-of-a-pdu)中被拒绝的条目,则拒绝。 + 4. 若条目中无 `m.room.create` 事件,则拒绝。 +3. 若房间状态下 `m.room.create` 事件的 `content` 含有 `m.federate` 属性且值为 `false`,且事件的 `sender` 域名与创建事件的 `sender` 域名不一致,则拒绝。 +4. 若事件类型为 `m.room.member`: + 1. 若无 `state_key` 属性,或 `content` 中无 `membership` 属性,则拒绝。 + 2. 若 `membership` 为 `join`: + 1. 若仅有的前序事件为 `m.room.create` 且 `state_key` 等于 creator,则允许。 + 2. 若 `sender` 不等于 `state_key`,则拒绝。 + 3. 若 `sender` 已被封禁,则拒绝。 + 4. 若 `join_rule` 为 `invite`,则当 membership 状态为 `invite` 或 `join` 时允许。 + 5. 若 `join_rule` 为 `public`,允许。 + 6. 否则,拒绝。 + 3. 若 `membership` 为 `invite`: + 1. 若 `content` 包含 `third_party_invite` 属性: + 1. 若*目标用户*被封禁,则拒绝。 + 2. 若 `content.third_party_invite` 不含 `signed` 属性,则拒绝。 + 3. 若 `signed` 不含 `mxid` 和 `token` 属性,则拒绝。 + 4. 若 `mxid` 不等于 `state_key`,则拒绝。 + 5. 若当前房间状态中对应 `token` 的 `state_key` 无 `m.room.third_party_invite` 事件,则拒绝。 + 6. 若 `sender` 不等于 `m.room.third_party_invite` 事件的 `sender`,则拒绝。 + 7. 若 `signed` 中任意签名与 `m.room.third_party_invite` 事件中的任一公钥匹配,则允许。公钥可在 `m.room.third_party_invite` 的 `content` 中如下获取: + 1. `public_key` 属性中的单个公钥。 + 2. `public_keys` 属性中的公钥列表。 + 8. 否则,拒绝。 + 2. 若 `sender` 当前的 membership 状态不是 `join`,则拒绝。 + 3. 若*目标用户*当前的 membership 状态是 `join` 或 `ban`,则拒绝。 + 4. 若 `sender` 权限等级大于或等于*邀请权限*,则允许。 + 5. 否则,拒绝。 + 4. 若 `membership` 为 `leave`: + 1. 若 `sender` 与 `state_key` 相同,仅当该用户当前 membership 状态为 `invite` 或 `join` 时允许。 + 2. 若 `sender` 当前的 membership 状态不是 `join`,则拒绝。 + 3. 若*目标用户*当前 membership 状态为 `ban`,且 `sender` 权限等级低于*封禁权限*,则拒绝。 + 4. 若 `sender` 权限等级大于或等于*踢人权限*,且*目标用户*权限等级低于 `sender`,允许。 + 5. 否则,拒绝。 + 5. 若 `membership` 为 `ban`: + 1. 若 `sender` 当前的 membership 状态不是 `join`,则拒绝。 + 2. 若 `sender` 权限等级大于或等于*封禁权限*,且*目标用户*权限等级低于 `sender`,允许。 + 3. 否则,拒绝。 + 6. 否则,成员状态未知。拒绝。 +5. 若 `sender` 当前的 membership 状态不是 `join`,则拒绝。 +6. 若事件类型为 `m.room.third_party_invite`: + 1. 仅当 `sender` 当前权限等级大于或等于*邀请权限*时允许。 +7. 若事件类型所需的*权限等级*高于 `sender` 当前权限等级,则拒绝。 +8. 若事件的 `state_key` 以 `@` 开头且与 `sender` 不一致,则拒绝。 +9. 若事件类型为 `m.room.power_levels`: + 1. 若 `content` 中的 `users` 属性不是以有效用户 ID 为键且值为整数(或整数字符串)的对象,则拒绝。 + 2. 若房间中不存在先前的 `m.room.power_levels` 事件,则允许。 + 3. 对于 `users_default`、`events_default`、`state_default`、`ban`、`redact`、`kick`、`invite` 属性,检查是否有新增、变更或移除。对每项变更: + 1. 若当前值高于 `sender` 当前权限等级,则拒绝。 + 2. 若新值高于 `sender` 当前权限等级,则拒绝。 + 4. {{% changed-in v=6 %}} + 针对 `events` 或 `notifications` 属性中被变更或移除的每一项: + 1. 若当前值大于 `sender` 当前权限等级,则拒绝。 + 5. {{% changed-in v=6 %}} + 针对 `events` 或 `notifications` 属性中新增加或变更的每一项: + 1. 若新值大于 `sender` 当前权限等级,则拒绝。 + 6. 针对 `users` 属性中被变更或移除的每一项,除 `sender` 自身以外: + 1. 若当前值大于等于 `sender` 当前权限等级,则拒绝。 + 7. 针对 `users` 属性中新增加或变更的每一项: + 1. 若新值大于 `sender` 当前权限等级,则拒绝。 + 8. 否则,允许。 +10. 否则,允许。 + +{{% boxes/note %}} +这些规则带来以下后果: + +- 除非您已是房间成员,否则唯一被允许的操作(除最初的创建/加入外)为:加入公开房间,或接受或拒绝房间邀请。 +- 取消封禁某人时,您必须拥有大于等于踢人权限*且*封禁权限,*并且*高于目标用户的权限等级。 +{{% /boxes/note %}} + +### 规范化 JSON + +{{% rver-fragment name="v6-canonical-json" %}} + +## 与 v5 保持一致 + +以下章节自 v5 起未被修改,仅为保持完整性而收录。 + +### 处理撤回 + +{{% rver-fragment name="v3-handling-redactions" %}} + +### 事件 ID + +{{% rver-fragment name="v4-event-ids" %}} + +#### 已废弃的事件内容模式 + +{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}} + +{{% rver-fragment name="v1-stringy-power-levels" %}} + +### 状态解析 + +{{% rver-fragment name="v2-state-res" %}} + +### 签名密钥有效期 + +{{% rver-fragment name="v5-signing-requirements" %}} diff --git a/locales/zh-Hans/rooms/v7.md b/locales/zh-Hans/rooms/v7.md new file mode 100644 index 00000000..71209f57 --- /dev/null +++ b/locales/zh-Hans/rooms/v7.md @@ -0,0 +1,176 @@ +--- +title: 房间版本 7 +type: docs +weight: 70 +version: 7 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +本房间版本在 [版本 6](/rooms/v6) 的基础上,新增了敲门作为一种可选的加入规则和成员状态。 + +## 客户端注意事项 + +这是首个完全支持敲门(knocking)的房间版本。因此,用户无法在非 v7 版本为基础的房间发起敲门请求。 + +虽然本房间版本相关的部分没有变动,实现本地化撤回算法的客户端应参考下方的[撤回](#redactions)章节了解完整细节。 + +## 服务器实现要点 + +{{% boxes/warning %}} +本节内容仅面向服务器实现者。使用客户端-服务器 API 的应用一般无需关心此处的细节。关于客户端应注意事项,请参考前文相关章节。 +{{% /boxes/warning %}} + +房间版本 7 新增了支持敲门的事件认证规则。[房间版本 6](/rooms/v6) 及其所基于的版本中包含了其他认证规则变更的细节。 + +### 认证规则 + +{{% added-in v=7 %}} 对于对 `m.room.member` 事件执行的检查,新增了针对 `membership=knock` 的处理分支。 + +事件必须由其 `sender` 属性所指服务器签名。 + +影响认证过程的状态事件类型有: + +- [`m.room.create`](/client-server-api#mroomcreate) +- [`m.room.member`](/client-server-api#mroommember) +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) +- [`m.room.power_levels`](/client-server-api#mroompower_levels) +- [`m.room.third_party_invite`](/client-server-api#mroomthird_party_invite) + +{{% boxes/note %}} +未显式提供时,权限等级将推断为默认值。例如,对 `sender` 权限等级的描述,也可指代该房间内用户的默认权限等级。 +{{% /boxes/note %}} + +{{% boxes/note %}} +`m.room.redaction` 事件与其他事件一样,受认证规则约束。实际上,除非 `m.room.power_levels` 事件以 `events` 或 `events_default` 属性对 `m.room.redaction` 事件设定了权限要求,否则一般都允许撤回事件参与验证。需要特别注意,_撤回等级_ **不会**被认证规则使用。 + +有权发送撤回事件并不意味着撤回操作会被执行。接收端服务器还必须执行额外检查,详见[撤回处理](#handling-redactions)章节。 +{{% /boxes/note %}} + +认证规则如下: + +1. 若事件类型为 `m.room.create`: + 1. 若存在任何 `prev_events`,拒绝。 + 2. 若 `room_id` 的域名与 `sender` 域名不一致,拒绝。 + 3. 若 `content.room_version` 存在且不为已知版本,拒绝。 + 4. 若 `content` 无 `creator` 属性,拒绝。 + 5. 其他情况,允许。 +2. 针对事件的 `auth_events`: + 1. 对于任意给定的 `type` 和 `state_key`,若有重复条目,拒绝。 + 2. 若有 `type` 和 `state_key` 不符合[认证事件选择](/server-server-api#auth-events-selection)算法的条目,拒绝。 + 3. 若有条目本身在[接收 PDU 时执行的检查](/server-server-api/#checks-performed-on-receipt-of-a-pdu)中被拒,拒绝。 + 4. 若条目中没有 `m.room.create` 事件,拒绝。 +3. 若房间状态中的 `m.room.create` 事件的 `content` 存在 `m.federate` 且为 `false`,且事件的 `sender` 域与创建事件的 `sender` 域不同,拒绝。 +4. 若事件类型为 `m.room.member`: + 1. 若无 `state_key` 属性,或 `content` 无 `membership` 属性,拒绝。 + 2. 若 `membership` 为 `join`: + 1. 如仅有的上一个事件为 `m.room.create` 且 `state_key` 为创建者,允许。 + 2. 若 `sender` 与 `state_key` 不同,拒绝。 + 3. 若 `sender` 已被禁言(banned),拒绝。 + 4. {{% changed-in v=7 %}} + 若 `join_rule` 为 `invite` 或 `knock`,则当成员状态为 `invite` 或 `join` 时允许。 + 5. 若 `join_rule` 为 `public`,允许。 + 6. 其他情况,拒绝。 + 3. 若 `membership` 为 `invite`: + 1. 如果 `content` 有 `third_party_invite` 属性: + 1. 若*目标用户*被 ban,拒绝。 + 2. 若 `content.third_party_invite` 无 `signed` 属性,拒绝。 + 3. 若 `signed` 无 `mxid` 和 `token` 属性,拒绝。 + 4. 若 `mxid` 与 `state_key` 不一致,拒绝。 + 5. 若当前房间状态中无 `state_key` 为 `token` 的 `m.room.third_party_invite` 事件,拒绝。 + 6. 若 `sender` 不一致于 `m.room.third_party_invite` 事件的 `sender`,拒绝。 + 7. 若 `signed` 中任意签名与 `m.room.third_party_invite` 事件中的任一公钥匹配,允许。公钥位于 `m.room.third_party_invite` 事件的 `content` 中: + 1. `public_key` 属性中的单个公钥; + 2. `public_keys` 属性中的公钥列表。 + 8. 其他情况,拒绝。 + 2. 若 `sender` 当前成员状态不是 `join`,拒绝。 + 3. 若*目标用户*当前成员状态为 `join` 或 `ban`,拒绝。 + 4. 若 `sender` 权限等级大于等于 *invite level*,允许。 + 5. 其他情况,拒绝。 + 4. 若 `membership` 为 `leave`: + 1. {{% changed-in v=7 %}} + 若 `sender` 等于 `state_key`,仅当该用户当前成员状态为 `invite`、`join` 或 `knock` 时允许。 + 2. 若 `sender` 当前成员状态不是 `join`,拒绝。 + 3. 若*目标用户*当前成员状态为 `ban`,且 `sender` 权限小于 *ban level*,拒绝。 + 4. 若 `sender` 权限等级大于等于 *kick level*,并且 *目标用户* 权限低于 `sender`,允许。 + 5. 其他情况,拒绝。 + 5. 若 `membership` 为 `ban`: + 1. 若 `sender` 当前成员状态不是 `join`,拒绝。 + 2. 若 `sender` 权限等级大于等于 *ban level*,且*目标用户*权限等级低于 `sender`,允许。 + 3. 其他情况,拒绝。 + 6. {{% added-in v=7 %}} + 若 `membership` 为 `knock`: + 1. 若 `join_rule` 不为 `knock`,拒绝。 + 2. 若 `sender` 与 `state_key` 不同,拒绝。 + 3. 若 `sender` 当前成员状态不是 `ban`、`invite` 或 `join`,允许。 + 4. 其他情况,拒绝。 + 7. 其他未知成员状态,拒绝。 +5. 若 `sender` 当前成员状态不是 `join`,拒绝。 +6. 若事件类型为 `m.room.third_party_invite`: + 1. 仅当 `sender` 当前权限等级大于等于 *invite level* 时允许。 +7. 若事件类型所需*权限等级*大于 `sender` 的当前权限等级,拒绝。 +8. 若事件有以 `@` 开头的 `state_key` 且不等于 `sender`,拒绝。 +9. 若事件类型为 `m.room.power_levels`: + 1. 若 `content` 的 `users` 属性不是仅包含有效用户 ID 的对象,值为整数(或可解释为整数的字符串),拒绝。 + 2. 若房间内无之前的 `m.room.power_levels` 事件,允许。 + 3. 对 `users_default`、`events_default`、`state_default`、`ban`、`redact`、`kick`、`invite` 这些属性,如有新增、变更或移除,逐项检查: + 1. 若当前值高于 `sender` 的当前权限等级,拒绝。 + 2. 若新值高于 `sender` 当前权限等级,拒绝。 + 4. 对 `events` 或 `notifications` 属性中被变更或移除的条目逐项检查: + 1. 若当前值高于 `sender` 当前权限等级,拒绝。 + 5. 对 `events` 或 `notifications` 属性中被新增或变更的条目逐项检查: + 1. 若新值高于 `sender` 当前权限等级,拒绝。 + 6. 对除 `sender` 自己以外的、`users` 属性中被变更或移除的条目逐项检查: + 1. 若当前值大于等于 `sender` 当前权限等级,拒绝。 + 7. 对 `users` 属性中被新增或变更的条目逐项检查: + 1. 若新值高于 `sender` 当前权限等级,拒绝。 + 8. 其他情况,允许。 +10. 其他情况,允许。 + +{{% boxes/note %}} +这些规则的部分后果如下: + +- 除非你是房间成员,否则仅允许的操作(除首次创建/加入外)有:加公共房、接受或拒绝邀请。 +- 若要解除对某人的封禁(unban),你必须拥有大于等于踢人(kick)*和*禁言(ban)等级的权限,*且*高于目标用户的权限等级。 +{{% /boxes/note %}} + +## 与 v6 保持一致的内容 + +下列章节自 v6 起未做更改,为保障文档完整性此处附上。 + +### 撤回 + +{{% rver-fragment name="v6-redactions" %}} + +### 撤回处理 + +{{% rver-fragment name="v3-handling-redactions" %}} + +### 事件 ID + +{{% rver-fragment name="v4-event-ids" %}} + +### 事件格式 + +{{% rver-fragment name="v6-event-format" %}} + +#### 已弃用事件内容模式 + +{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}} + +{{% rver-fragment name="v1-stringy-power-levels" %}} + +### 状态解析 + +{{% rver-fragment name="v2-state-res" %}} + +### 规范化 JSON + +{{% rver-fragment name="v6-canonical-json" %}} + +### 签名密钥有效期 + +{{% rver-fragment name="v5-signing-requirements" %}} diff --git a/locales/zh-Hans/rooms/v8.md b/locales/zh-Hans/rooms/v8.md new file mode 100644 index 00000000..f9bd678c --- /dev/null +++ b/locales/zh-Hans/rooms/v8.md @@ -0,0 +1,115 @@ +--- +title: 房间版本 8 +type: docs +weight: 80 +version: 8 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +本房间版本在[版本 7](/rooms/v7)的基础上,新增了一种加入规则,允许成员基于在另一个房间的成员身份加入该房间。 + +{{% boxes/warning %}} +已知此房间版本存在有关成员加入事件撤回的问题。[房间版本 9](/rooms/v9)在创建房间时应优先选择,而不是 v8。 +{{% /boxes/warning %}} + +## 客户端注意事项 + +建议客户端在其用户界面中为支持的房间版本提供该加入规则的选项。 + +新的加入规则 `restricted` 的详细信息请参考 +[客户端-服务器 API](/client-server-api/#restricted-rooms)。 + +在本地实现撤回事务算法的客户端应参考下方[撤回](#redactions)章节了解完整内容。 + +### 撤回 + +{{% added-in v=8 %}} `m.room.join_rules` 事件现在在被撤回时,除了其他 +`content` 键外,仍会保留 `allow`。 + +{{% boxes/warning %}} +[房间版本 9](/rooms/v9)增加了“受保护属性”更多的情形,以应对 v8 引入的受限房间功能。当创建新房间时,应优先选择 v9。 +{{% /boxes/warning %}} + +完整的撤回事务算法如下: + +收到撤回事务事件时,服务器必须移除以下列表外的任何键: + +- `event_id` +- `type` +- `room_id` +- `sender` +- `state_key` +- `content` +- `hashes` +- `signatures` +- `depth` +- `prev_events` +- `prev_state` +- `auth_events` +- `origin` +- `origin_server_ts` +- `membership` + +content 对象的所有键也必须被移除,除非该事件类型属于以下之一: + +- `m.room.member` 允许键 `membership`。 +- `m.room.create` 允许键 `creator`。 +- `m.room.join_rules` 允许键 `join_rule`、`allow`。 +- `m.room.power_levels` 允许键 `ban`、`events`、`events_default`、`kick`、`redact`、`state_default`、`users`、`users_default`。 +- `m.room.history_visibility` 允许键 `history_visibility`。 + +## 服务器实现组件 + +{{% boxes/warning %}} +本节信息仅面向服务器实现者。采用客户端-服务器 API 的应用通常不受此处详细内容的影响。客户端-服务器 API 用例应以上方客户端注意事项为准。 +{{% /boxes/warning %}} + +房间版本 8 新增了一种加入规则,允许某个房间的成员无需邀请即可加入另一个房间。除此以外,房间版本继承了[房间版本 7](/rooms/v7)的所有属性。 + +### 鉴权规则 + +{{% added-in v=8 %}} 在 `m.room.member` 事件执行检查时,新增了处理 `content.join_authorised_via_users_server` 的要点(规则 4.2 和 4.3.5)。 + +{{% rver-fragment name="v8-auth-rules" %}} + +### 撤回 + +[见上文](#redactions)。 + +## 与 v7 保持一致 + +下列章节自 v7 起未做修改,这里为保证文档完整性一并列出。 + +### 撤回事件处理 + +{{% rver-fragment name="v3-handling-redactions" %}} + +### 事件 ID + +{{% rver-fragment name="v4-event-ids" %}} + +### 事件格式 + +{{% rver-fragment name="v6-event-format" %}} + +#### 已弃用的事件内容模式 + +{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}} + +{{% rver-fragment name="v1-stringy-power-levels" %}} + +### 状态解析 + +{{% rver-fragment name="v2-state-res" %}} + +### 标准 JSON + +{{% rver-fragment name="v6-canonical-json" %}} + +### 签名密钥有效期 + +{{% rver-fragment name="v5-signing-requirements" %}} diff --git a/locales/zh-Hans/rooms/v9.md b/locales/zh-Hans/rooms/v9.md new file mode 100644 index 00000000..2c971eab --- /dev/null +++ b/locales/zh-Hans/rooms/v9.md @@ -0,0 +1,86 @@ +--- +title: 房间版本 9 +type: docs +weight: 90 +version: 9 +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +此房间版本是在 [版本 8](/rooms/v8) 的基础上,新增了在合并 v8 时意外遗漏的额外撤回(redaction)规则。 + +## 客户端注意事项 + +有关受限房间(restricted rooms)的具体新增细节,请参考 [房间版本 8](/rooms/v8)。 + +在本地实现撤回算法的客户端,应参考下文的 [撤回](#redactions) 部分以获得全面概述。 + +### 撤回 + +{{% added-in v=9 %}} [`m.room.member`](/client-server-api#mroommember) 事件在被撤回时,除了保留原有的 `content` 键外,现在还会保留 `join_authorised_via_users_server`。 + +{{% boxes/rationale %}} +如果没有 `join_authorised_via_users_server` 属性,被撤回的加入事件在验证事件授权链时可能变得无效,从而导致“脑裂”现象,即用户从某一服务器视角可以发言,但大多数其他服务器会持续拒绝其事件。 + +理论上可以通过重新加入大厅来规避该问题,前提是不要将出错的事件作为 `prev_events` 使用,不过建议优先选用 v9 房间来彻底避免此类情况。 + +更多信息请见 [Issue #3373](https://github.com/matrix-org/matrix-doc/issues/3373)。 +{{% /boxes/rationale %}} + +完整的撤回算法如下: + + +{{% rver-fragment name="v9-redactions" %}} + +## 服务器实现组成部分 + +{{% boxes/warning %}} +本节信息仅面向服务器实现者。使用 Client-Server API 的应用通常不受此处细节影响。有关注意客户端实现的用例请参考前文关于客户端注意事项的部分。 +{{% /boxes/warning %}} + +房间版本 8 引入了一种新的 `restricted` 加入规则,允许一个房间的成员无需邀请即可加入另一个房间。房间版本 9 以 v8 为基础,并有以下补充说明。 + +### 撤回 + +[见上文](#redactions)。 + +## 保持与 v8 一致 + +下列部分自 v8 起未做修改,现为文档完整性起见一并收录。 + +### 处理撤回 + +{{% rver-fragment name="v3-handling-redactions" %}} + +### 事件 ID + +{{% rver-fragment name="v4-event-ids" %}} + +### 事件格式 + +{{% rver-fragment name="v6-event-format" %}} + +#### 已废弃的事件内容格式 + +{{% rver-fragment name="v1-deprecated-formatting-off-spec" %}} + +{{% rver-fragment name="v1-stringy-power-levels" %}} + +### 授权规则 + +{{% rver-fragment name="v8-auth-rules" %}} + +### 状态解析 + +{{% rver-fragment name="v2-state-res" %}} + +### 标准 JSON + +{{% rver-fragment name="v6-canonical-json" %}} + +### 签名密钥有效期 + +{{% rver-fragment name="v5-signing-requirements" %}} diff --git a/locales/zh-Hans/server-server-api.md b/locales/zh-Hans/server-server-api.md new file mode 100644 index 00000000..535f67e9 --- /dev/null +++ b/locales/zh-Hans/server-server-api.md @@ -0,0 +1,762 @@ +--- +title: "服务器-服务器 API" +weight: 20 +type: docs +--- + +{{< boxes/warning >}} +本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 +{{< /boxes/warning >}} + + +Matrix 家服务器(homeservers)之间通过联邦 API(亦称为服务器-服务器 API)进行通信。家服务器利用这些 API 实时互投消息、检索彼此的历史消息,并查询关于对方服务器上用户的资料和在线状态等信息。 + +这些 API 通过各服务器之间的 HTTPS 请求实现。HTTPS 请求在 TLS 传输层和 HTTP 层的 Authorization 头内均需使用公钥签名进行强认证。 + +家服务器之间主要有三种通信方式: + +持久化数据单元(PDU): +这些事件会从一个家服务器广播到加入同一房间(由房间 ID 标识)的其他任意服务器。它们会被持久化用于记录房间消息和状态的历史。 + +类似电子邮件,PDU 的原始服务器负责将该事件传递给目标服务器。然而,PDU 使用原始服务器的私钥签名,因此可以通过第三方服务器进行传递。 + +短暂数据单元(EDU): +这些事件在家服务器对之间点对点推送。它们不会被持久化,也不是房间历史的一部分,接收的家服务器也无需回复。 + +查询请求(Queries): +这是由一方发起、向另一方发送 HTTPS GET 请求以获取某些信息,并由对方应答的单次请求/响应交互。不会被持久化,也不包含任何长期历史,仅请求查询发起瞬间的快照状态。 + +EDU 和 PDU 进一步被封装在一个称为事务(Transaction)的信封中,通过 HTTPS PUT 请求从源服务器传送至目标家服务器。 + +## API 标准 + +Matrix 服务器-服务器通信的强制基准是通过 HTTPS API 交换 JSON 对象。未来可能会指定更高效的传输方式作为可选扩展。 + +所有的 `POST` 和 `PUT` 端点要求请求服务器在请求体中提供一个(可能为空的)JSON 对象。请求服务器应为所有带有 JSON 请求体的请求提供 `Content-Type: application/json` 头,但不是强制性的。 + +同理,本规范中的所有端点要求目标服务器返回一个 JSON 对象。服务器必须在所有 JSON 响应中包含 `Content-Type: application/json` 头。 + +所有请求和响应中的 JSON 数据都必须使用 UTF-8 编码。 + +### TLS + +服务器-服务器通信必须通过 HTTPS 实现。 + +目标服务器必须提供由已知证书机构签署的 TLS 证书。 + +请求服务器最终负责确定信任的证书机构,强烈建议依赖操作系统的判断。服务器可以为管理员提供覆盖信任机构列表的方法。服务器还可以针对白名单中的域名或网段跳过证书验证,用于测试或在其他地方完成验证(如 `.onion` 地址)的网络环境下。 + +在发起请求时,服务器应尽可能遵守 SNI(服务器名称指示):发送期望证书的 SNI,除非证书预期是 IP 地址(IP 地址不支持 SNI,不应发送)。 + +建议服务器利用 [证书透明计划](https://www.certificate-transparency.org/)。 + +### 不支持的端点 + +若收到对不支持(或未知)端点的请求,服务器必须返回 404 `M_UNRECOGNIZED` 错误。 + +同样,405 `M_UNRECOGNIZED` 错误用于指示对已知端点的不支持 HTTP 方法。 + +## 服务器发现 + +### 解析服务器名称 + +每个 Matrix 家服务器通过一个包含主机名和可选端口的服务器名称唯一标识,详见 [语法说明](/appendices#server-name)。如适用,委托服务器名采用相同语法。 + +服务器名需解析为可连接的 IP 地址与端口,解析过程中涉及不同证书和 `Host` 头的设置。整体流程如下: + +1. 如果主机名是 IP 字面量,则应直接使用该 IP 与指定端口(未指定则为 8448)。目标服务器必须呈现对应 IP 地址的有效证书。请求中的 `Host` 头应设为服务器名称(若含端口也需带端口)。 +2. 若主机名不是 IP 字面量,且服务器名称中包含明确端口,需通过 CNAME、AAAA 或 A 记录解析主机名为 IP 地址;请求将发至解析得到的 IP 和端口,`Host` 头为原始服务器名称(含端口)。目标服务器必须呈现该主机名的有效证书。 +3. 若主机名非 IP 字面量,无明确端口,则向 `https:///.well-known/matrix/server` 发起常规 HTTPS 请求,期望返回本节后续定义的模式。须跟随 30x 跳转,但需避免重定向循环。`/.well-known` 端点的响应(无论成功与否)应由请求服务器进行缓存。服务器应遵守响应内的缓存控制头,如无则使用合理默认值(建议 24 小时)。另外应限制响应最大缓存时间,建议为 48 小时。错误建议缓存最多一小时,并对重复失败采用指数退避。`/.well-known` 返回的响应模式详见本节后续。若响应无效(JSON 无效、字段缺失、返回非 200 等)则跳转到步骤 4。若响应有效,解析 `m.server` 字段(格式 `[:]`)并按如下处理: + 1. 若 `` 为 IP 字面量,则用该 IP 和 ``(未提供则 8448)。目标服务器必须有对应 IP 的有效 TLS 证书。请求 `Host` 头为该 IP(若含端口亦包含端口)。 + 2. 若 `` 非 IP 字面量,且 `` 存在,查找其 CNAME、AAAA 或 A 记录,得出 IP,连同 `` 使用。请求 `Host` 头为 `:`。目标服务器需有 `` 的有效证书。 + 3. {{% added-in v="1.8" %}} 若 `` 不是 IP 字面量,且未指定 ``,则查找 `_matrix-fed._tcp.` 的 SRV 记录,可能带来新的主机名(需 AAAA 或 A 记录解析)及端口。请求应发往解析出的 IP 与端口,`Host` 头为 ``。目标服务器需有 `` 的有效证书。 + 4. **[已废弃]** 若 `` 不是 IP 字面量,未指定 ``,且找不到 `_matrix-fed._tcp.` SRV 记录,则查 `_matrix._tcp.`,同样可能得到主机名和端口。请求应发往解析到的 IP 和端口,`Host` 头为 ``。目标服务器需有 `` 的有效证书。 + 5. 若未找到 SRV 记录,通过 CNAME、AAAA 或 A 记录解析 IP,之后用 8448 端口发请求,`Host` 头为 ``。目标服务器须有 `` 的有效证书。 +4. {{% added-in v="1.8" %}} 若 `/.well-known` 请求返回错误,则尝试解析 `_matrix-fed._tcp.` 的 SRV 记录,或得主机名和端口。请求发往解析到的 IP 与端口,`Host` 头为 ``,目标服务器需有 `` 的有效证书。 +5. **[已废弃]** 若 `/.well-known` 请求错误且找不到 `_matrix-fed._tcp.` SRV 记录,则解析 `_matrix._tcp.` SRV 记录,同样可能获主机名和端口。请求发往解析到的 IP 和端口,`Host` 头为 ``,目标服务器需有 `` 的有效证书。 +6. 若 `/.well-known` 返回错误,且未找到 SRV 记录,则用 CNAME、AAAA、A 记录解析 IP,发往 8448 端口,`Host` 头为 ``,目标服务器需有 `` 有效证书。 + +{{% boxes/note %}} +我们强制要求 SRV 委托使用 `` 而非 `` 的原因: + 1. DNS 并不安全(并非所有域名都部署 DNSSEC),因此委托目标必须通过 TLS 证明自己是 `` 的合法代理。 + 2. 与 [RFC6125](https://datatracker.ietf.org/doc/html/rfc6125#section-6.2.1) 以及 XMPP 等其他使用 SRV 记录的应用保持一致。 +{{% /boxes/note %}} + +{{% boxes/note %}} +注意,根据 [RFC2782](https://www.rfc-editor.org/rfc/rfc2782.html) 要求,SRV 记录的目标不能是 CNAME: + +> the name MUST NOT be an alias (in the sense of RFC 1034 or RFC 2181) +{{% /boxes/note %}} + +{{% boxes/note %}} +步骤 3.4 与 5 已废弃,因为采用了 IANA 未注册的服务名,未来可能被规范移除。鼓励服务器管理员优先使用 `.well-known`,不要依赖任何形式的 SRV 记录。 + +关于 8448 端口与 `matrix-fed` 的 IANA 注册见 [此处](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=matrix-fed)。 +{{% /boxes/note %}} + +{{% http-api spec="server-server" api="wellknown" %}} + +### 服务器实现 + +{{% http-api spec="server-server" api="version" %}} + +### 获取服务器公钥 + +{{% boxes/note %}} +曾经存在“版本 1”密钥交换,已因意义不大被规范移除。可在 [历史草案](https://github.com/matrix-org/matrix-doc/blob/51faf8ed2e4a63d4cfd6d23183698ed169956cc0/specification/server_server_api.rst#232version-1) 查阅。 +{{% /boxes/note %}} + +每个家服务器通过 `/_matrix/key/v2/server` 发布自身公钥。家服务器可直接请求 `/_matrix/key/v2/server` 获取公钥,也可借助中间公证服务器通过 `/_matrix/key/v2/query/{serverName}` API 查询。公证服务器会代表其他服务器查询目标服务器的 `/_matrix/key/v2/server` API,然后用自己的密钥为响应签名。服务器可同时查询多个公证服务器,确保它们返回的公钥一致。 + +该方法借鉴了 [Perspectives Project](https://web.archive.org/web/20170702024706/https://perspectives-project.org/),但增加了 NACL 密钥并采用 JSON 而非 XML。其优势是不依赖单一信任根,每台服务器可自由选择信任哪些公证,且能通过交叉查询验证密钥一致性。 + +#### 公钥发布 + +家服务器在 `/_matrix/key/v2/server` 以 JSON 对象发布其签名密钥。响应包含一组 `verify_keys`,用于签名联邦请求以及事件。还包含一组仅可用于事件签名的 `old_verify_keys`。 + +{{% http-api spec="server-server" api="keys_server" %}} + +#### 通过其他服务器查询密钥 + +服务器可通过公证服务器查询目标服务器公钥。公证服务器可能也是别的家服务器。其会使用 `/_matrix/key/v2/server` 从目标服务器取得密钥,并在响应前对结果再签名。 + +对于离线或无法提供密钥的服务器,公证服务器可利用缓存返回密钥。为防止 DNS 欺骗,可同时向多台服务器查询密钥。 + +{{% http-api spec="server-server" api="keys_query" %}} + +## 认证 + +### 请求认证 + +家服务器发起的每个 HTTP 请求都需使用公钥数字签名进行认证。请求方法、目标和体被封装进 JSON 对象后签名,签名采用 JSON 签名算法,最终以 `X-Matrix` 认证方式添加至 Authorization 头。注意,target 字段需包含以 `/_matrix/...` 为首的全路径(包括 `?` 和各参数),不含前导 `https:` 与目标服务器主机名。 + +步骤 1,签名 JSON: + +``` +{ + "method": "POST", + "uri": "/target", + "origin": "origin.hs.example.com", + "destination": "destination.hs.example.com", + "content": , + "signatures": { + "origin.hs.example.com": { + "ed25519:key1": "ABCDEF..." + } + } +} +``` + +上例中的服务器名称是相关家服务器的服务器名,不受 [服务器名称解析](#resolving-server-names) 中委托影响,始终用委托前的名称。此规则在后续签名流程中也适用。 + +步骤 2,添加 Authorization 头: + + POST /target HTTP/1.1 + Authorization: X-Matrix origin="origin.hs.example.com",destination="destination.hs.example.com",key="ed25519:key1",sig="ABCDEF..." + Content-Type: application/json + + + +Python 示例代码: + +```py +def authorization_headers(origin_name, origin_signing_key, + destination_name, request_method, request_target, + content=None): + request_json = { + "method": request_method, + "uri": request_target, + "origin": origin_name, + "destination": destination_name, + } + + if content is not None: + # 假定内容已为解析好的 JSON + request_json["content"] = content + + signed_json = sign_json(request_json, origin_name, origin_signing_key) + + authorization_headers = [] + + for key, sig in signed_json["signatures"][origin_name].items(): + authorization_headers.append(bytes( + "X-Matrix origin=\"%s\",destination=\"%s\",key=\"%s\",sig=\"%s\"" % ( + origin_name, destination_name, key, sig, + ) + )) + + return ("Authorization", authorization_headers[0]) +``` + +Authorization 头格式见 [RFC 9110 第 11.4 节](https://datatracker.ietf.org/doc/html/rfc9110#section-11.4)。简言之,头以授权机制 `X-Matrix` 开始,后跟一或多空格,再跟一组用逗号隔开的 name=value 参数对。各参数对两侧允许有零个或多个空格及制表符。名称大小写不敏感,顺序无关。value 含非法 token 字符时必须加引号,若合法可省略引号。用引号的 value 可包含反斜杠转义字符。解析时须将转义字符还原。 + +为兼容旧服务器,发送端应: +- 只在 `X-Matrix` 后加一个空格; +- 只用小写参数名; +- 避免值中含反斜杠; +- 避免参数对间有额外空白字符。 + +兼容旧服务器的接收端应允许参数值中含冒号,无需加引号。 + +可用的授权参数包含: + +- `origin`:发送服务器的服务器名,与上文 JSON 的 `origin` 字段一致。 +- `destination`:{{% added-in v="1.3" %}} 接收服务器名,与 JSON 的 `destination` 字段一致。为兼容旧服务器,允许无此参数,但必须始终发送;若有且值与接收服务器名不符,接收端须以 401 Unauthorized 拒绝请求。 +- `key`:用于签名请求的发送服务器密钥 ID(含算法名)。 +- `signature`:步骤 1 中 JSON 的签名。 + +未知参数应被忽略。 + +{{% boxes/note %}} +{{% changed-in v="1.11" %}} +本节原引用了 [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-2.1) 和 [RFC 7230](https://datatracker.ietf.org/doc/html/rfc9110#section-5.6.2),已被 RFC 9110 替代,但相关内容未变。 +{{% /boxes/note %}} + +### 响应认证 + +响应通过 TLS 服务器证书认证。家服务器不应在确认已认证对方服务器前发送请求,以防消息泄漏。 + +### 客户端 TLS 证书 + +因如 Matrix 这样的 HTTP 服务常部署在负责 TLS 的负载均衡器之后,因此建议在 HTTP 层而非 TLS 层进行请求认证,这样 TLS 客户端证书难以校验。 + +家服务器可提供 TLS 客户端证书,接收方可校验是否与原始服务器证书一致。 + +## 事务 + +家服务器之间通过事务消息(Transaction)交换 EDU 和 PDU。这些事务以 JSON 对象编码,通过 HTTP PUT 请求传输。事务仅对交换的两台服务器有意义,不具备全局意义。 + +事务有限制:每个最多可含 50 个 PDU 和 100 个 EDU。 + +{{% http-api spec="server-server" api="transactions" %}} + +## PDUs + +每个 PDU 包含一个房间事件,原服务器希望将其发送至目标服务器。 + +PDU 中的 `prev_events` 字段标识事件的“父事件”,并通过将事件链接为有向无环图(DAG)在房间内建立事件的部分顺序。发送服务器应填充所有自己尚未看到其子事件的事件,从而表明此事件紧随所有已知事件之后。 + +例如,设房间事件形成下述 DAG。新事件应以 `E4` 和 `E6` 作为 `prev_events`,因为两者尚无子事件: + + E1 + ^ + | + E2 <--- E5 + ^ ^ + | | + E3 E6 + ^ + | + E4 + +完整的 PDU 模式见 [房间版本规范](/rooms)。 + +### PDU 接收时的校验 + +服务器接收到远端事件时,必须确保该事件: + +1. 是一个有效事件,否则直接丢弃。有效事件必须含有 `room_id`,并符合该 [房间版本](/rooms) 的事件格式。 +2. 签名校验通过,否则丢弃。 +3. 哈希校验通过,否则事件被裁剪(redacted)后再继续处理。 +4. 基于认证事件(auth events)的授权规则校验通过,否则拒绝。 +5. 基于事件前状态的授权规则校验通过,否则拒绝。 +6. 基于房间当前状态的授权规则校验通过,否则“软失败”(soft failed)。 + +各项校验及失败处理详述如下。 + +关于事件需要包含哪些哈希及签名及其计算,详见 [事件签名](#signing-events)。 + +#### 定义 + +所需权限等级(Required Power Level) + +:每类事件类型对应一个 *权限等级*,由当前 [`m.room.power_levels`](/client-server-api/#mroompower_levels) 事件指定。若事件类型在 `events` 块未显式列出,则根据是否为状态事件,分别使用 `state_default` 或 `events_default`。 + +邀请/踢出/封禁/撤回等级(Invite Level, Kick Level, Ban Level, Redact Level) + +:由当前 [`m.room.power_levels`](/client-server-api/#mroompower_levels) 状态内的 `invite`、`kick`、`ban`、`redact` 指定。邀请默认为 0,踢出、封禁、撤回均默认为 50。 + +目标用户(Target User) + +:对于 [`m.room.member`](/client-server-api/#mroommember) 状态事件,由事件的 `state_key` 指定的用户。 + +{{% boxes/warning %}} +部分 [房间版本](/rooms) 允许权限等级为字符串,仅为向后兼容。家服务器应合理防止用户发送带字符串值权限事件(如直接拒绝 API 请求),且默认权限值绝不可为字符串。 + +详情见 [房间版本规范](/rooms)。 +{{% /boxes/warning %}} + +#### 授权规则 + +授权与状态有关。单个事件需多次用不同状态集校验,具体规则和适用算法由房间版本决定。详细内容见 [房间版本规范](/rooms)。 + +##### 认证事件选择(Auth events selection) + +PDU 的 `auth_events` 字段标识允许发起发送的事件集。房间中的 `m.room.create` 事件无 `auth_events`;其他事件应按照以下房间状态子集选取: + +- `m.room.create` 事件 +- 当前的 `m.room.power_levels` 事件(如有) +- 发送方当前的 `m.room.member` 事件(如有) +- 若类型为 `m.room.member`: + - 目标用户当前的 `m.room.member` 事件(如有) + - 若 `membership` 为 `join`、`invite` 或 `knock`,则为当前 `m.room.join_rules` + - 若 `membership` 为 `invite` 且 `content` 含 `third_party_invite`,则加入当前 `m.room.third_party_invite` 事件,其 `state_key` 匹配 `content.third_party_invite.signed.token` + - 如 `content.join_authorised_via_users_server` 存在,且 [房间版本支持受限房间](/rooms/#feature-matrix),则加入 `state_key` 匹配 `content.join_authorised_via_users_server` 的 `m.room.member` 事件 + +#### 拒绝(Rejection) + +被拒绝事件不应下发给客户端,也不可作为新事件的前序事件。后续如有其他服务器发出的引用被拒绝事件的新事件,只要其授权校验通过也可被接受。授权校验状态正常更新,除针对被拒绝事件(若为状态事件)不更新。 + +若事务中的事件被拒绝,不应以错误码响应整个事务请求。 + +{{% boxes/note %}} +这意味着某些被拒绝事件依然可出现在房间事件 DAG 中。 +{{% /boxes/note %}} + +{{% boxes/note %}} +区别于裁剪事件(redacted event),裁剪事件依然可影响房间状态。如,取消内容的 `join` 事件依然会使用户视为已加入房间。 +{{% /boxes/note %}} + +#### 软失败(Soft failure) + +{{% boxes/rationale %}} +为防止用户通过指向旧 DAG 分支的事件规避封禁或其他权限限制,例如被封禁用户通过发送引用被封禁前分支的事件继续发言。此类事件本身合法,不应单纯以拒绝处理,因为无法区分延迟事件和规避事件。因此,此类事件需正常参与状态解析与联邦协议,但服务器可选择不将其下发至客户端。 + +通常服务器会发现此类事件基于“当前状态”无法授权(即综合所有前沿节点的解析状态),此时服务器可选择不通知客户端。 + +这样可阻止恶意服务器向客户端投递规避事件,因最终用户不会看到。例如: + + A + / + B + +`B` 为用户 `X` 的封禁事件。若 `X` 试图通过发送事件 `C` 修改话题以规避封禁,则 + + A + / \ + B C + +若服务器先见到 `B` 后见到 `C`,应对 `C` 软失败,即不通知客户端,也不再引用 `C`。 + +若后来有服务器发送同时引用 `B` 和 `C` 的事件 `D`(如其先见到了 `C` 后到的 `B`): + + A + / \ + B C + \ / + D + +则 `D` 可正常处理(前提授权通过)。`D` 处的状态可能包含 `C`,客户端应当收到包含 `C` 的新状态。(*注意*:实际取决于具体状态解析算法,对应 `C` 或 `B` 优先。) + +若所有服务器都先收到 `B`,所有对 `C` 软失败,则后续新事件 `D'` 不再引用 `C`: + + A + / \ + B C + | + D' +{{% /boxes/rationale %}} + +通过联邦收到新事件后,应在基于事件自身状态校验通过后,再以房间当前状态校验。不通过时则“软失败”。 + +“软失败”事件不应下发至客户端,也不应被新事件引用或加入到前沿事件集中。其余处理同常规事件。 + +{{% boxes/note %}} +如有其他事件引用该软失败事件,则其可照常参与状态解析;状态解析算法须防止此机制下恶意事件注入房间状态。 +{{% /boxes/note %}} + +{{% boxes/note %}} +软失败的状态事件如在状态解析中被选为当前状态,客户端应常规方式收到该事件(例如在 sync 响应的 `state` 部分推送)。 +{{% /boxes/note %}} + +{{% boxes/note %}} +若联邦请求需返回软失败事件(如 `/event/`),应正常返回。`/backfill` 和 `/get_missing_events` 仅当请求中包含引用该软失败事件的事件时才会返回。 +{{% /boxes/note %}} + +#### 检索事件授权信息 + +家服务器可能缺失事件授权信息,或需从其他服务器验证授权链。通过以下 API 获取所需信息。 + +{{% http-api spec="server-server" api="event_auth" %}} + +## EDUs + +EDU 相比 PDU 没有事件 ID、房间 ID 或“前序事件”列表。通常用于非持久化数据,如用户在线状态、正在输入提示等。 + +{{% definition path="api/server-server/definitions/edu_with_example" %}} + +## 房间状态解析 + +*状态* 是 `(event_type, state_key)` 到 `event_id` 的映射。每个房间初始状态为空,每有状态事件加入即更新房间状态。 + +若每个事件只有一个 `prev_event`,其后状态唯一;若事件图分支合并,可能存在不同状态,此时需用 *状态解析算法* 决定合并结果。 + +如下事件图(顶部为最早的 E0): + + E0 + | + E1 + / \ + E2 E4 + | | + E3 | + \ / + E5 + +若 E3 和 E4 都是 `m.room.name` 事件,E5 处房间名称如何确定? + +状态解析算法由房间版本决定,详见 [房间版本规范](/rooms)。 + +## 回溯填充与缺失事件获取 + +家服务器加入房间后,会收到所有在房间内其他家服务器产生的事件,因此近期历史不会丢失。用户可通过 `/messages` 客户端 API 端点查历史,如倒退到加入房间前,其服务器本地无历史。 + +为此,联邦 API 提供类似 `/messages` 的服务器-服务器历史获取接口 `/backfill`。 + +如需历史,家服务器可选一已存有最早历史用户的家服务器发起 `/backfill` 请求。 + +类似回溯,服务器可能缺失某些事件,可通过 `/get_missing_events` 获取缺失事件。 + +{{% http-api spec="server-server" api="backfill" %}} + +## 检索事件 + +在某些情况下,家服务器可能缺失特定事件或无法简单通过回溯获取的房间信息。相关 API 允许家服务器获取指定时间点的事件及状态。 + +{{% http-api spec="server-server" api="events" %}} + +## 加入房间 + +当新用户想加入本服务器已知的房间时,服务器可直接检查房间状态判断能否加入。若可以,则生成签名并发出新的 `m.room.member` 状态事件加入用户。若服务器尚未知该房间,则需通过更长的多阶段握手流程,先选定一个已在该房间的远程家服务器协助加入,即远程加入握手。 + +握手涉及三个角色:发起加入用户的家服务器(“加入服务器”)、托管用户请求别名的目录服务器,以及房间中已有成员所属家服务器(“常驻服务器”)。 + +概述如下,加入服务器先向目录服务器查询别名,获取房间 ID 及加入候选服务器,继而请求其中一个常驻服务器查询房间信息,再用这些资料构建并签名 `m.room.member` 加入事件,最终发往常驻服务器。 + +概念上为三个家服务器角色,实际通常目录服务器本身即为房间成员;实际流程也常只有两台服务器参与。 + +``` ++---------+ +---------------+ +-----------------+ +-----------------+ +| Client | | JoiningServer | | DirectoryServer | | ResidentServer | ++---------+ +---------------+ +-----------------+ +-----------------+ + | | | | + | join request | | | + |---------------------->| | | + | | | | + | | directory request | | + | |---------------------------->| | + | | | | + | | directory response | | + | |<----------------------------| | + | | | | + | | make_join request | | + | |------------------------------------------------>| + | | | | + | | |make_join response | + | |<------------------------------------------------| + | | | | + | | send_join request | | + | |------------------------------------------------>| + | | | | + | | |send_join response | + | |<------------------------------------------------| + | | | | + | join response | | | + |<----------------------| | | + | | | | +``` + +第一步,通常通过目录服务器的 [`/query/directory`](/server-server-api/#get_matrixfederationv1querydirectory) 端点查询房间 ID 与加入候选服务器。若为被邀请后加入,则可直接选用邀请事件源服务器为候选,提高效率。但需考虑邀请服务器可能已不再是房间成员,因此失败时须回退到通常流程。 + +获得房间 ID 和候选服务器后,加入服务器选一常驻服务器,通过 `GET /make_join` 获取房间事件模板。常驻服务器返回填充事件各项所需信息。 + +加入服务器需补充完善 `origin`、`origin_server_ts`、`event_id`,然后签名。 + +最后,加入服务器通过 `PUT /send_join` 将新事件送往常驻服务器。 + +常驻服务器为事件加签,接受并将其写入房间事件图,并将新事件及房间全状态(含刚签出的事件)发送给房间内其他服务器。 + +{{% http-api spec="server-server" api="joins-v1" %}} + +{{% http-api spec="server-server" api="joins-v2" %}} + +### 受限房间 + +受限房间详细描述见 [客户端-服务器 API](/client-server-api/#restricted-rooms),仅在 [支持受限加入的房间版本](/rooms/#feature-matrix) 下启用。 + +处理请求加入受限房间时,常驻服务器需确保加入服务器满足 `m.room.join_rules` 所定义的至少一项条件。若无条件、或者无条件符合所需模式,则视为全部校验失败。 + +校验条件失败时,`/make_join` 及 `/send_join` 应返回 400 `M_UNABLE_TO_AUTHORISE_JOIN`(通常因无法获知所需房间的状态信息)。 + +若加入用户满足某些条件,但常驻服务器自身不满足生成 `join_authorised_via_users_server` 所需的权限,则返回 400 `M_UNABLE_TO_GRANT_JOIN`,表明需换服务器尝试。 + +所有条件均未满足时,常驻服务器返回 403 `M_FORBIDDEN`。 + +## 敲门加入房间 {#knocking-rooms} + +房间可通过 join rules 允许敲门。允许时,用户可请求加入房间(即被邀请)。本地已在房间服务器可直接发送敲门事件,否则需如 [加入房间](/server-server-api/#joining-rooms) 一样,通过握手流程让远端协助发送。 + +敲门握手同加入握手基本一致,区别在于角色变为“敲门服务器”,API 包括 `/make_knock` 与 `/send_knock`。 + +服务器间敲门可通过离开房间取消,见下述邀请拒绝相关说明。 + +{{% http-api spec="server-server" api="knocks" %}} + +## 房间邀请 + +同一服务器用户间发起邀请时,服务器可直接签署并跳过此处流程。跨服务器邀请时,必须向被邀服务器请求事件签名和校验。 + +邀请事件同样用于通知之前的敲门请求被接受。因此,接收服务器应准备好将此前敲门事件与邀请事件关联(即使邀请未直接引用敲门)。 + +{{% http-api spec="server-server" api="invites-v1" %}} + +{{% http-api spec="server-server" api="invites-v2" %}} + +## 离开房间(拒绝邀请) + +家服务器可主动发送 `m.room.member` 事件令用户离开房间、拒绝本地邀请或撤销敲门。针对其他家服务器发出的远程邀请或敲门,由于图谱中未参与,需采用特殊方式拒绝邀请。直接先加入再离开并不可取,因为客户端会认为用户先接受邀请再主动退出,这和拒绝邀请有本质区别。 + +与 [加入房间](#joining-rooms) 握手类似,发起离开的服务器需先向常驻服务器发 `/make_leave`。拒绝邀请时,常驻服务器可为邀请发起方。收到 `/make_leave` 模板事件后,发起服务器签名并设置自己的 `event_id`,通过 `/send_leave` 发送给常驻服务器,常驻服务器再下发给房间内其他服务器。 + +{{% http-api spec="server-server" api="leaving-v1" %}} + +{{% http-api spec="server-server" api="leaving-v2" %}} + +## 第三方邀请 + +{{% boxes/note %}} +有关第三方邀请的更多信息请见 [客户端-服务器 API](/client-server-api) 的对应模块。 +{{% /boxes/note %}} + +用户欲邀请不知道 Matrix ID 的用户进房间时,可使用第三方标识(如邮箱或手机号)发起邀请。 + +此标识及其与 Matrix ID 的绑定由实现 [身份服务 API](/identity-service-api) 的身份服务器验证。 + +### 第三方标识已有绑定时 + +若标识已绑定 Matrix ID,身份服务器查询会返回。邀请将作为普通 `m.room.member` 事件处理。 + +### 第三方标识尚无绑定时 + +若标识尚未绑定 Matrix ID,则邀请服务器将请求身份服务器存储并待有人绑定该标识后推送。邀请服务器还需在房间发 `m.room.third_party_invite` 事件,写入显示名、令牌及身份服务器返回的公钥。 + +当某个 Matrix ID 绑定此标识后,身份服务器会按 [邀请存储](/identity-service-api#invitation-storage) 的说明 POST 至对应家服务器。 + +每次邀请,家服务器会创建携带特殊 `third_party_invite` 节点的 `m.room.member` 事件,内含令牌及签名对象。 + +如接收家服务器已在房间,可直接授权发事件;否则需向房间家服务器发授权请求。 + +{{% http-api spec="server-server" api="third_party_invite" %}} + +#### 邀请校验 + +家服务器收到带 `third_party_invite` 对象的 `m.room.member` 邀请事件后,须在无需第三方服务器的情况下验证受邀 Matrix ID 与标识已有验证关系。 + +需从房间状态取出 `m.room.third_party_invite` 事件,其 `state_key` 与 `m.room.member` 事件内容内 `third_party_invite` 里的 `token` 字段匹配,获得身份服务器提供的公钥。 + +用该公钥校验 `m.room.member` 事件 `content.third_party_invite.signed` 对象的签名,保证创建邀请事件的确为拥有此第三方标识的用户。 + +鉴于该签名对象仅能在绑定标识与 Matrix ID 时由身份服务器发送一次,且内含指明 Matrix ID 及令牌,因此能保证为真实所有者。 + +## 公共房间目录 + +为配合 [客户端-服务器 API](/client-server-api) 的房间目录,家服务器需要可从远端查询目标服务器的公共房间。请求目标服务器的 `/publicRooms` 端点即可。 + +{{% http-api spec="server-server" api="public_rooms" %}} + +## 空间(Spaces) + +为配合 [客户端-服务器 API Spaces 模块](/client-server-api/#spaces),家服务器需可从远端服务器查询空间信息。 + +{{% http-api spec="server-server" api="space_hierarchy" %}} + +## 正在输入通知 + +当服务器用户发正在输入通知时,需将该通知同步到房间内其他服务器,令其用户获得同样状态。接收服务器应确保用户确已在房间,且为发送方服务器的用户。 + +{{% definition path="api/server-server/definitions/event-schemas/m.typing" %}} + +## 在线状态(Presence) + +服务器 API 的在线状态完全基于下述 EDU 交换。不涉及 PDU 或联邦查询。 + +服务器应仅为对方感兴趣的用户发送在线状态更新,例如对方正与本地用户共处一房间。 + +{{% definition path="api/server-server/definitions/event-schemas/m.presence" %}} + +## 回执 + +回执为 EDU,用于指示对某事件的操作“标记”。目前仅支持“已读回执“(read receipt,表示用户已读到事件处)。 + +本用户自己发的事件不必发送读回执,因发事件即视为已读。 + +{{% definition path="api/server-server/definitions/event-schemas/m.receipt" %}} + +## 信息查询 + +查询是指向家服务器检索资源(如用户或房间)的信息。常与客户端向客户端-服务器 API 发起请求配合实现。 + +可进行多种查询。下文先是通用查询端点,后跟具体类型。 + +{{% http-api spec="server-server" api="query" %}} + +## OpenID + +第三方服务可用由 客户端-服务器 API 预生成的访问令牌交换获取用户信息。"OpenID" 可用于验证用户身份而无需授予账户全部访问权限。 + +由 OpenID API 生成的访问令牌仅对 OpenID API 有效,在其他用途无效。 + +{{% http-api spec="server-server" api="openid" %}} + +## 设备管理 + +用户设备详情需高效公开并及时更新,以保证端到端加密可靠,让用户知晓房间内涉及的设备;同时设备间消息需要筛选并分发。下述内容补充 [客户端-服务器 API 设备管理模块](/client-server-api#device-management)。 + +Matrix 目前采用自定义的发布/订阅机制同步用户设备列表(联邦同步)。服务器首次获取远端用户设备列表时,通过 `/user/keys/query` 接口结果填本地缓存。后续通过 `m.device_list_update` EDU 增量更新。每次新 EDU 针对给定用户的一台设备(含唯一 `stream_id`),并在 `prev_id` 字段指向增量更新参考。为便于多实例并发,`prev_id` 可包含所有当前尚未被引用的 key,若依次发送一条记录,`prev_id` 仅有一个。 + +这样形成了 `m.device_list_update` EDU 的有向无环图,指明更新某用户设备列表前必须已接收哪些 EDU。若引用了本地未知的 `prev_id`,服务器需重新调用 `/user/keys/query` API 后继续处理。响应返回 `stream_id`,供后续同步使用。 + +{{% http-api spec="server-server" api="user_devices" %}} + +{{% definition path="api/server-server/definitions/event-schemas/m.device_list_update" %}} + +## 端到端加密 + +本节补充 [客户端-服务器 API 端到端加密模块](/client-server-api#end-to-end-encryption)。详细加密流程可见该模块。 + +此处 API 主要用于代客户端通过联邦转发请求,并原样转发响应。 + +{{% http-api spec="server-server" api="user_keys" %}} + +{{% definition path="api/server-server/definitions/event-schemas/m.signing_key_update" %}} + +## 发送到设备消息 + +发送到设备的消息通过 `m.direct_to_device` EDU 实现,不涉及 PDU 或联邦查询。 + +每条“发给设备”消息须以以下 EDU 发送到目标服务器: + +{{% definition path="api/server-server/definitions/event-schemas/m.direct_to_device" %}} + +## 内容仓库 + +事件附件(图片、文件等)通过 [客户端-服务器 API 的内容仓库](/client-server-api/#content-repository) 上传至家服务器。当服务器需获取远端服务器存储的媒体数据时,需从远端下载。 + +服务器必须基于 [Matrix 内容 URI](/client-server-api/#matrix-content-mxc-uris) 的服务地址(格式 `mxc://{ServerName}/{MediaID}`),始终应从 `{ServerName}` 服务器下载,利用下述端点。 + +{{% changed-in v="1.11" %}} 之前推荐使用 [/client-server-api/#content-repository](/client-server-api/#content-repository) 内描述的 `/_matrix/media/*` 端点,如今这些端点已废弃,新端点需认证。服务器(而非用户)无法提供所需访问令牌。因此服务器应优先尝试新端点,遇到 404 `M_UNRECOGNIZED` 时再尝试废弃端点,并确保设置 `allow_remote` 为 `false`。 + +{{% http-api spec="server-server" api="content_repository" %}} + +## 服务器访问控制列表(ACL) + +服务器 ACL 及其用途详见 [客户端-服务器 API 的服务器 ACL 部分](/client-server-api#server-access-control-lists-acls-for-rooms)。 + +远端服务器发起请求时,必须验证其是否有权限访问指定房间。被拒绝的服务器必须以 403 HTTP 状态码及 `errcode: M_FORBIDDEN` 响应。 + +以下端点前缀必须受保护: + +- `/_matrix/federation/v1/make_join` +- `/_matrix/federation/v1/make_leave` +- `/_matrix/federation/v1/send_join` +- `/_matrix/federation/v2/send_join` +- `/_matrix/federation/v1/send_leave` +- `/_matrix/federation/v2/send_leave` +- `/_matrix/federation/v1/invite` +- `/_matrix/federation/v2/invite` +- `/_matrix/federation/v1/make_knock` +- `/_matrix/federation/v1/send_knock` +- `/_matrix/federation/v1/state` +- `/_matrix/federation/v1/state_ids` +- `/_matrix/federation/v1/backfill` +- `/_matrix/federation/v1/event_auth` +- `/_matrix/federation/v1/get_missing_events` + +此外,[`/_matrix/federation/v1/send/{txnId}`](#put_matrixfederationv1sendtxnid) 端点必须按以下规则保护: + +- 对所有 PDU 逐个应用 ACL,若发送服务器被拒绝访问 `room_id` 房间,则应忽略该 PDU,并在各自事件 ID 对应响应项中注明错误。 +- 所有房间相关的 EDU 也须应用 ACL: + + - 对 [输入状态通知 (`m.typing`)](#typing-notifications),发送服务器被拒绝访问相应 `room_id` 时忽略其 EDU。 + - 对 [已读回执 (`m.receipt`)](#receipts),若发送服务器被拒绝访问某房间,则对应该房间的所有回执均应忽略。 + +## 事件签名 + +事件签名过程受事件被裁剪(redact)带来的复杂性影响。 + +### 为出站事件添加哈希和签名 + +签名前,需先计算事件的*内容哈希*(content hash),使用 [Unpadded Base64](/appendices#unpadded-base64) 编码,放入事件 `hashes.sha256` 字段。 + +随后,执行*裁剪*(redaction)算法(见 [裁剪规则](/client-server-api#redactions)),再用 [JSON 签名](/appendices#signing-json) 算法及服务器签名密钥签名,生成的签名再拷贝回原事件对象。 + +签名事件范例见 [房间版本规范](/rooms)。 + +### 校验接收事件的哈希和签名 + +服务器收到联邦事件后,应立即校验哈希及签名。 + +首查签名,先裁剪事件,然后按 [校验签名流程](/appendices#checking-for-a-signature) 检查签名(可接受完整或已裁剪事件)。 + +期望签名包括: + +- `sender` 服务器(如为第三方邀请则例外。否则 sender 要与第三方邀请吻合,而实际发事件或为不同服务器)。 +- 若为房间版本 1/2,还包括事件 ID 创建方服务器。其他房间版本事件 ID 不在联邦传递,因此无需额外签名。 + +签名正确后,计算期望的内容哈希。`hashes` 字段的内容解码后与期望值比对。 + +如哈希校验失败,表明只收到裁剪后事件,故直接用裁剪结果。 + +### 计算事件引用哈希(Reference Hash) + +*引用哈希*(reference hash)覆盖事件重要字段,包括内容哈希。部分房间版本用于事件标识符,具体见[房间版本规范](/rooms)。计算过程如下: + +1. 事件经过裁剪算法处理。 +2. 移除 `signatures` 和 `unsigned` 字段。 +3. 转为 [规范化 JSON](/appendices#canonical-json)。 +4. 计算 sha256 哈希。 + +### 计算事件内容哈希(Content Hash) + +*内容哈希* 覆盖原始未裁剪的完整事件。计算步骤: + +1. 移除已有的 `unsigned`、`signatures` 和 `hashes` 字段。 +2. 用 [规范化 JSON](/appendices#canonical-json) 编码后做 SHA-256 哈希。 + +### 示例代码 + +```py +def hash_and_sign_event(event_object, signing_key, signing_name): + # 首先计算事件内容哈希 + content_hash = compute_content_hash(event_object) + event_object["hashes"] = {"sha256": encode_unpadded_base64(content_hash)} + + # 裁剪事件,移除非必要字段 + stripped_object = strip_non_essential_keys(event_object) + + # 对裁剪后的 JSON 做签名(只签关键字段和哈希) + signed_object = sign_json(stripped_object, signing_key, signing_name) + + # 把签名从裁剪后事件拷贝回原事件 + event_object["signatures"] = signed_object["signatures"] + +def compute_content_hash(event_object): + # 复制事件对象 + event_object = dict(event_object) + + # "unsigned" 字段可由他服务器更改,需排除 + event_object.pop("unsigned", None) + + # 签名相关依赖当下 "hashes",因此须排除 + event_object.pop("signatures", None) + event_object.pop("hashes", None) + + # 编码为规范化 JSON 取得一致字节输出 + event_json_bytes = encode_canonical_json(event_object) + + return hashlib.sha256(event_json_bytes) +``` + +## 安全注意事项 + +当域名所有权变更,接手人可冒充前任所有者接收消息(类似邮件)并请求其他服务器转发历史。未来,如 [MSC1228](https://github.com/matrix-org/matrix-spec-proposals/issues/1228) 方案将解决此类问题。