184 lines
6.8 KiB
Markdown
184 lines
6.8 KiB
Markdown
# SuperGroup (GroupType=1) 使用限制分析
|
||
|
||
## 一、核心问题
|
||
|
||
如果绕过创建限制,创建了 `GroupType=1` (SuperGroup) 的群组,在使用上会有以下**关键差异和潜在问题**:
|
||
|
||
## 二、关键差异点
|
||
|
||
### 2.1 消息验证逻辑差异 ⚠️ **重要**
|
||
|
||
**位置**: `internal/rpc/msg/verify.go:187-220`
|
||
|
||
**SuperGroup (GroupType=1) 的特殊处理**:
|
||
```go
|
||
if groupInfo.GroupType == constant.SuperGroup {
|
||
// SuperGroup 跳过大部分检查,但仍需检查文件权限
|
||
if data.MsgData.ContentType == constant.File {
|
||
// 只检查文件发送权限
|
||
}
|
||
return nil // 直接返回,跳过后续所有检查
|
||
}
|
||
```
|
||
|
||
**WorkingGroup (GroupType=2) 的完整验证**:
|
||
- ✅ 检查用户是否在群内
|
||
- ✅ 检查文件发送权限(群主/管理员/userType=1)
|
||
- ✅ 检查链接发送权限(userType=1/群主/管理员可发送链接)
|
||
- ✅ 检查二维码图片(userType=0 普通成员不能发送包含二维码的图片)
|
||
- ✅ 检查禁言状态(MuteEndTime)
|
||
- ✅ 检查群组是否被禁言(GroupStatusMuted)
|
||
|
||
**差异总结**:
|
||
| 检查项 | SuperGroup | WorkingGroup |
|
||
|--------|-----------|--------------|
|
||
| 文件发送权限 | ✅ 检查 | ✅ 检查 |
|
||
| 链接检测 | ❌ **跳过** | ✅ 检查 |
|
||
| 二维码检测 | ❌ **跳过** | ✅ 检查 |
|
||
| 禁言检查 | ❌ **跳过** | ✅ 检查 |
|
||
| 群组禁言检查 | ❌ **跳过** | ✅ 检查 |
|
||
|
||
**⚠️ 风险**:
|
||
- SuperGroup 可以发送包含链接的消息,即使 userType=0
|
||
- SuperGroup 可以发送包含二维码的图片,即使 userType=0
|
||
- SuperGroup 成员即使被禁言也可以发送消息
|
||
- SuperGroup 即使群组被禁言,成员仍可发送消息
|
||
|
||
### 2.2 消息推送机制
|
||
|
||
**位置**: `internal/push/push_handler.go:104-116`
|
||
|
||
**推送逻辑**:
|
||
```go
|
||
switch msgFromMQ.MsgData.SessionType {
|
||
case constant.ReadGroupChatType:
|
||
err = c.Push2Group(ctx, msgFromMQ.MsgData.GroupID, msgFromMQ.MsgData)
|
||
default:
|
||
err = c.Push2User(ctx, pushUserIDList, msgFromMQ.MsgData)
|
||
}
|
||
```
|
||
|
||
**关键发现**:
|
||
- 推送逻辑**不依赖 GroupType**,而是依赖 **SessionType**
|
||
- `SessionType` 是客户端发送消息时指定的,**不是根据 GroupType 自动确定的**
|
||
- 如果客户端发送消息时 `SessionType != ReadGroupChatType`,会走 `Push2User` 而不是 `Push2Group`
|
||
|
||
**⚠️ 潜在问题**:
|
||
- 如果创建了 `GroupType=1` 的群组,但客户端发送消息时使用 `SessionType=WriteGroupChatType`(值为2),消息会按单聊方式推送,可能导致推送逻辑异常
|
||
- `Push2Group` 和 `Push2User` 的推送机制不同,可能影响消息分发
|
||
|
||
### 2.3 会话ID生成差异
|
||
|
||
**位置**: `pkg/msgprocessor/conversation.go:68-97`
|
||
|
||
**会话ID生成规则**:
|
||
```go
|
||
case constant.WriteGroupChatType:
|
||
return "g_" + msg.GroupID // 普通群聊
|
||
case constant.ReadGroupChatType:
|
||
return "sg_" + msg.GroupID // 超级群聊
|
||
```
|
||
|
||
**差异**:
|
||
- `WriteGroupChatType` (值为2): 会话ID前缀为 `g_`
|
||
- `ReadGroupChatType` (值为3): 会话ID前缀为 `sg_`
|
||
|
||
**⚠️ 潜在问题**:
|
||
- 如果 `GroupType=1` 但使用 `SessionType=WriteGroupChatType`,会话ID会是 `g_xxx` 而不是 `sg_xxx`
|
||
- 这可能导致会话管理不一致
|
||
|
||
### 2.4 在线推送方法
|
||
|
||
**位置**: `internal/push/onlinepusher.go:99`
|
||
|
||
**推送方法**:
|
||
- 所有群聊消息(无论 GroupType)都使用 `SuperGroupOnlineBatchPushOneMsg` 方法
|
||
- 方法名虽然叫 "SuperGroup",但实际上所有群聊都使用这个方法
|
||
|
||
**结论**:推送方法本身**不受 GroupType 影响**,但推送逻辑受 `SessionType` 影响
|
||
|
||
## 三、使用限制和潜在错误
|
||
|
||
### 3.1 必须使用正确的 SessionType ⚠️ **关键**
|
||
|
||
**问题**:如果创建了 `GroupType=1` 的群组,但发送消息时:
|
||
- ❌ 使用 `SessionType=WriteGroupChatType` (值为2) → 会走 `Push2User`,推送逻辑可能异常
|
||
- ✅ 必须使用 `SessionType=ReadGroupChatType` (值为3) → 会走 `Push2Group`,推送正常
|
||
|
||
**建议**:客户端发送消息时,需要根据群组的 `GroupType` 自动设置正确的 `SessionType`:
|
||
- `GroupType=1` (SuperGroup) → `SessionType=ReadGroupChatType` (值为3)
|
||
- `GroupType=2` (WorkingGroup) → `SessionType=WriteGroupChatType` (值为2) 或 `ReadGroupChatType` (值为3)
|
||
|
||
### 3.2 权限检查缺失 ⚠️ **安全风险**
|
||
|
||
**SuperGroup 跳过的检查**:
|
||
1. **链接检测**:普通成员可以发送包含链接的消息
|
||
2. **二维码检测**:普通成员可以发送包含二维码的图片
|
||
3. **禁言检查**:被禁言的成员仍可发送消息
|
||
4. **群组禁言检查**:群组被禁言时,成员仍可发送消息
|
||
|
||
**安全影响**:
|
||
- 可能被用于发送恶意链接
|
||
- 可能被用于发送包含二维码的垃圾信息
|
||
- 禁言功能失效
|
||
|
||
### 3.3 会话管理不一致
|
||
|
||
**问题**:
|
||
- 如果 `GroupType=1` 但使用 `SessionType=WriteGroupChatType`,会话ID会是 `g_xxx`
|
||
- 如果使用 `SessionType=ReadGroupChatType`,会话ID会是 `sg_xxx`
|
||
- 这可能导致同一个群组产生不同的会话ID,造成会话管理混乱
|
||
|
||
## 四、总结
|
||
|
||
### 4.1 主要差异
|
||
|
||
| 方面 | SuperGroup (GroupType=1) | WorkingGroup (GroupType=2) |
|
||
|------|-------------------------|---------------------------|
|
||
| **消息验证** | 跳过大部分检查(链接、二维码、禁言) | 完整验证 |
|
||
| **文件权限** | 检查(群主/管理员/userType=1) | 检查(群主/管理员/userType=1) |
|
||
| **推送机制** | 依赖 SessionType,需使用 ReadGroupChatType | 依赖 SessionType |
|
||
| **会话ID** | 需使用 ReadGroupChatType 生成 sg_ 前缀 | 可使用 WriteGroupChatType 或 ReadGroupChatType |
|
||
|
||
### 4.2 使用建议
|
||
|
||
如果允许创建 `SuperGroup` 类型的群组,需要:
|
||
|
||
1. **客户端适配**:
|
||
- 发送消息时,根据群组的 `GroupType` 自动设置正确的 `SessionType`
|
||
- `GroupType=1` → `SessionType=ReadGroupChatType` (值为3)
|
||
|
||
2. **安全考虑**:
|
||
- 明确 SuperGroup 跳过权限检查的设计意图
|
||
- 如果需要安全控制,考虑在业务层或回调中实现
|
||
|
||
3. **一致性**:
|
||
- 确保所有使用 SuperGroup 的地方都使用 `ReadGroupChatType`
|
||
- 统一会话ID生成规则
|
||
|
||
### 4.3 潜在错误场景
|
||
|
||
1. **推送错误**:如果使用错误的 SessionType,消息可能无法正确推送给所有群成员
|
||
2. **会话混乱**:同一个群组可能产生不同的会话ID
|
||
3. **权限绕过**:SuperGroup 会跳过禁言等权限检查
|
||
4. **安全风险**:可以发送链接和二维码,可能被滥用
|
||
|
||
## 五、代码修改建议
|
||
|
||
如果要支持 SuperGroup,建议:
|
||
|
||
1. **创建群组时**:允许 `GroupType=1` 和 `GroupType=2`
|
||
2. **消息发送时**:根据 `GroupType` 自动设置 `SessionType`
|
||
3. **消息验证时**:明确 SuperGroup 的特殊逻辑,考虑是否需要保留部分安全检查
|
||
4. **文档说明**:明确 SuperGroup 和 WorkingGroup 的差异和使用场景
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|