# 成员资格与访问控制

[群组托管协议](../README.md) · [核心对象](../core-objects.md)

群组请求的校验遵循[方法公共约定](../methods/conventions.md#校验与错误处理规则)。历史事件的签名和授权按 [`group.sync`](../methods/lifecycle-and-sync.md#groupsync) 的规则验证。各角色的操作权限见[角色权限表](model-and-keys.md#角色权限)。

## 入群邀请、申请与容量限制

### 邀请规则

邀请的创建权限见 [`GroupState`](../core-objects.md#groupstate) 中的邀请策略定义。签发权限在创建邀请时检查；后续使用邀请时，沿用中继接受邀请时已经完成的授权判断。

定向邀请只能由指定账户使用一次；公开邀请可以被多个账户使用，成功次数受 `max_uses` 约束。邀请在到期、撤销或用尽前仍可用于提交申请，签发者后来离群、降级或邀请策略改变不会自动撤销已经创建的邀请。

申请沿用所引用邀请的有效期，不另设独立到期时间；邀请用尽、到期或被撤销后，引用它的待审批申请立即失效，不能再被批准。申请提交、失效和拒绝不消耗使用次数，只有批准成功增加成员时才原子消耗。

中继至少保留仍被有效待审批申请引用的完整邀请、签发设备证书和使用次数，使管理员能按申请的 `invite_id` 验证原始邀请。

### 申请与审批

申请者可以先凭适用于自己的有效邀请调用 `group.resolve` 查看当前状态，不消耗邀请，也不取得事件或密钥访问权。

申请者按 [`group.application.submit`](../methods/admission.md#groupapplicationsubmit) 提交由申请设备签署的入群申请。中继保存完整申请和接受时验证的设备证书，供批准者独立验证。同账户的新申请替换旧待审批申请；提交不改变成员或管理链。

owner 或 administrator 可以一次批准一份或多份申请。成功后，中继原子增加成员、生成新中继秘密、推进一次密钥版本并追加一个批准事件。请求及处理规则见 [`group.application.approve`](../methods/admission.md#groupapplicationapprove)。新成员必须依据已验证管理历史，按[客户端秘密盒](model-and-keys.md#客户端秘密盒)的规定验证取得的盒。

### 容量限制

`member_capacity` 可以降低到当前成员数以下，既有成员仍然有效；只要当前成员数不小于容量，新的批准就必须失败。待审批申请不预留容量，多个管理员并发批准时以首先成功生效的批准为准。

中继后来降低自身 `max_group_members` 不会使既有成员或容量失效；保持或降低既有容量仍可执行，即使目标容量仍高于新上限。新建群和增加容量必须满足操作生效时中继允许的上限。

## 成员变更与封禁

### 成员变更

`group.member.leave` 使调用账户的当前成员资格立即结束并追加事件；owner 必须先转让所有权。`group.member.remove` 由 owner 或 administrator 按账户移除一名或多名当前成员。

加入、离开和移除只轮换中继秘密，不自动更换客户端秘密。操作成功时必须同时更新成员投影、生成新中继秘密、推进密钥版本并追加事件。已离开或被移除的账户此后不能读取事件或密钥。

### 封禁与解除

封禁将目标加入封禁集合并删除这些账户的待审批入群申请，同时按移除规则处理其中的当前成员，包括关闭设备访问区间、清理待审批密钥重置请求，以及删除相关暂存盒。整批只要移除了成员，就生成一份新中继秘密并推进一次密钥版本；仅封禁非成员时不推进密钥。完整签名的封禁请求作为一个管理事件，同时证明封禁和成员移除，不额外产生移除事件。

被封禁的账户不能调用群接口或重新加入。解除封禁只移除封禁状态并追加管理事件，不恢复已删除的入群申请、成员资格、角色或旧访问区间，也不推进密钥；重新入群必须重新申请并获批。封禁不自动更换客户端秘密；若该秘密可能已经泄露，建议 owner 轮换客户端秘密。

## 成员密钥重置

当前成员失去成员加密私钥时，可以用当前有效设备签署并提交成员密钥重置请求。中继保存请求及设备证书，批准者独立验证请求的账户绑定及签名后，签署批准决定并构造客户端秘密盒。

### 请求管理

每个账户最多保留一份当前请求，新请求替换旧请求。请求具有有限有效期，到期后不能撤回、批准或拒绝；到期时间规则见 [`group.member.recovery.submit`](../methods/member-recovery.md#groupmemberrecoverysubmit)。成员离开、被移除或请求获批时删除当前请求；重入不恢复旧请求。

请求所属成员可以在请求获批前按自己的账户撤回当前请求。owner 可以拒绝其他成员的请求；administrator 只能拒绝其他普通成员的请求。撤回和拒绝不改变成员公钥、设备访问区间、密钥版本或群时间线。

### 批准与候选材料处理

owner 可以批准包括自己在内的任意当前成员；administrator 只能批准其他普通成员。批准成功后，中继原子替换目标成员公钥、重建设备访问区间并推进一次密钥版本。批量请求和具体处理规则见 [`group.member.recovery.approve`](../methods/member-recovery.md#groupmemberrecoveryapprove)。密钥盒的构造与验证遵循[客户端秘密盒](model-and-keys.md#客户端秘密盒)规则。

候选材料的保存遵循 [`group.member.recovery.submit`](../methods/member-recovery.md#groupmemberrecoverysubmit) 的规定；候选私钥的启用、丢弃及所需验证必须遵循 [`group.member.recovery.list`](../methods/member-recovery.md#groupmemberrecoverylist) 的规定。

## 设备访问区间

设备访问区间限定消息事件和中继提供的密钥材料。管理事件不受这些区间的起止位置限制；当前具有群读取权限的设备，可以从创建事件开始读取全部管理历史。有多个访问区间时，消息访问范围取各授权区间的并集。

### 区间建立与变更

- 创建者设备从创建事件开始；申请设备和密钥重置请求设备分别从相应批准事件开始建立消息区间，包含该位置；密钥从该事件使用的版本开始，包含该版本。
- 其他新设备成功调用 `group.subscribe`、`group.sync` 或 `group.key.sync` 时建立消息和密钥访问起点。消息仅包含建立时的时间线头之后的位置；密钥包含当时当前版本。后续调用保留原起点。首次管理同步仍从 -1 开始。
- 同一设备 ID 连续续期保留既有区间。失效设备重新启用时按普通新设备建立新区间，不补齐失效期间的消息或密钥，但可补齐全部管理事件。
- 成员密钥重置关闭该账户全部旧区间，并使这些区间不再授权消息和密钥读取；请求设备从批准事件建立新区间。其他仍获账户授权的设备再次成功调用 `group.subscribe`、`group.sync` 或 `group.key.sync` 时，按普通新设备规则建立新区间，不恢复旧区间的读取权限。设备撤销仍按账户设备状态处理。

收到 `device.status.changed` 后，中继必须按[缓存失效与补查规则](../../../relay-rpc/notifications/README.md#处理规则)重新查询并核验设备状态。确认设备 `inactive` 时关闭其当前区间；只有曾向其返回当前中继秘密时才生成新中继秘密并推进 `epoch`。会话到期本身不关闭设备区间。中继秘密轮换事件不推进管理链头。

### 读取权限与历史边界

仍获授权的原有区间内尚保留的消息和密钥可按权限读取。离群、移除或设备当前失效时拒绝全部群读取。被封禁期间也拒绝读取。

事件和密钥的保留遵循[群组数据保留与访问规则](timeline-and-sync.md#群组数据保留与访问规则)。管理历史可读不授予过去的消息解密能力。

访问区间是中继实施的历史边界，不提供同一密钥版本内的密码学历史隔离。事件及密钥分别按 [`group.sync`](../methods/lifecycle-and-sync.md#groupsync) 和 [`group.key.sync`](../methods/keys.md#groupkeysync) 校验。
