Files
AuthBot/README.md
T
snowy-yang 755013b9db 初始提交:QQ 群入群验证机器人
基于 qqbotsdk-py 的入群验证:进群发按钮验证码、完成前禁言、
超时踢出(11253 时兜底长期禁言)、乱点他人按钮处罚、状态持久化
与重启恢复。38 个单元/集成测试。
2026-10-04 18:44:08 +08:00

108 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AuthBot — QQ 群入群验证机器人
基于 [qqbotsdk-py](https://pypi.org/project/qqbotsdk-py/)(QQ 官方开放平台 SDK)的群验证机器人:
新成员进群 → 机器人发**数学选择题 + 按钮验证码** → 完成验证前该成员处于**禁言**状态 →
限时内点对按钮立即解禁;**超时未通过则移出群**(若踢人接口未获官方内邀权限,自动降级为
长期禁言 + 通知管理员)。
## 功能一览
- 进群自动验证:`GROUP_MEMBER_ADD` 事件触发,数学题 4 选 1 按钮(题目随机、答错换题、倒计时不重置)
- 验证前禁言:按 `member_openid` 单独禁言(不碰全员禁言),通过后立即解禁
- 超时踢出:默认 10 分钟;踢人失败(业务码 11253)自动兜底为禁言 72 小时 + 群内提示管理员
- 旧题防重放:按钮 data 携带题目 token,换题后旧按钮点击无效
- 反捣乱:非被试者点击他人的验证按钮,30 分钟窗口内累计 3 次即禁言 5 分钟
(次数与时长可配:`FOREIGN_CLICK_LIMIT` / `FOREIGN_CLICK_MUTE_MINUTES`)
- 状态持久化:`data/` 下 JSON 存储,进程重启自动恢复禁言与倒计时(已过期立即处理)
- 轻量管理指令:群里 `@机器人 验证状态` 查看待验证名单与剩余时间;
`@机器人 验证我`(或 `测试验证`)对发起人本人走一遍完整验证流程,方便上线前自测
- 免验信任期(可选):通过后 N 天内退群重进不再验证,默认 0(每次都验)
## 环境要求
- Python **3.12+**(SDK 硬性要求;开发环境为 3.14)
- `qqbotsdk-py >= 0.2.1`(0.2.1 修复了按成员禁言的请求体——旧版平铺写法会被服务端静默忽略)
- QQ 开放平台机器人([q.qq.com](https://q.qq.com) 注册,拿到 AppID / AppSecret)
## 快速开始
```bash
# 1. 安装依赖
python -m venv .venv
.venv\Scripts\pip install -r requirements.txt
# 2. 配置凭据
copy .env.example .env
# 编辑 .env,填入 APPID / APPSECRET
# 3. 启动(WebSocket 方式,开箱即用)
.venv\Scripts\python main.py
```
事件订阅开关已配好在 `intents.toml`:`GROUP_AND_C2C_EVENT`(@消息)、
`GROUP_MEMBER_EVENT`(进退群,**默认关闭的关键开关**)、`INTERACTION`(按钮回调)。
## 平台侧准备(重要)
1. **markdown 消息与按钮(键盘)权限**:在 q.qq.com 开发者后台为机器人申请。
没有该权限验证码发不出去——机器人此时**不会禁言新成员**(防止把人永久锁死),
并在日志输出 CRITICAL/ERROR 提示排查方向。
2. **机器人入群并设为群管理员**:禁言(`restrict_chat_setting`)、移出成员都需要管理员身份。
3. **踢人接口处于官方"内邀接入中"**:未开通的机器人调用返回业务码 11253。
机器人会自动降级:延长禁言(默认 72 小时,可配)并在群里提示管理员手动处理。
4. 群消息接收方式保持默认(@机器人)即可,无需"接收所有消息"权限。
## 配置项(.env)
| 变量 | 默认 | 说明 |
| --- | --- | --- |
| `APPID` / `APPSECRET` | 必填 | 开放平台凭据 |
| `CONNECTER` | `websocket` | `websocket` 或 `webhook` |
| `VERIFY_TIMEOUT_MINUTES` | `10` | 验证限时,超时触发处理 |
| `PENDING_MUTE_HOURS` | `24` | 待验证期间禁言时长 |
| `TIMEOUT_KICK` | `true` | 超时是否尝试移出群 |
| `TIMEOUT_FALLBACK_MUTE_HOURS` | `72` | 踢出失败后的兜底禁言时长 |
| `CAPTCHA_OPTIONS` | `4` | 选项个数(2~5) |
| `VERIFIED_TRUST_DAYS` | `0` | 通过后免验天数(0=每次都验) |
| `FOREIGN_CLICK_LIMIT` | `3` | 他人乱点验证按钮的处罚阈值(30 分钟窗口) |
| `FOREIGN_CLICK_MUTE_MINUTES` | `5` | 乱点处罚的禁言时长(分钟) |
| `DATA_DIR` | `data` | 状态文件目录 |
## 目录结构
```
main.py 入口
authbot/
config.py .env 业务参数读取与校验
captcha.py 验证码生成、按钮编解码、消息模板
state.py pending/verified 持久化 + 超时定时器
handlers.py 事件处理器(进群/按钮/退群/@指令/超时流程)
intents.toml 事件订阅开关
data/ 运行时状态(自动创建)
tests/ pytest 单元测试
```
## 已知限制(官方 API 能力边界)
- 群场景只有 **openid**(`group_openid` / `member_openid`),拿不到真实 QQ 号,
所以提示信息里只能显示 openid 尾号。
- **群主/管理员/机器人无法被禁言**(官方限制,接口会静默返回成功但不生效);
机器人会在回查禁言列表后发现这一点,`验证我` 测试时会明确提示。因此请用
普通成员账号测试禁言效果。
- 禁言接口请求体为嵌套结构 `{"members": [{"op": "add|update|del", ...}]}`
(平铺写法会被服务端静默忽略,实测踩坑;SDK 0.2.1 起已内置正确封装);
写入后机器人会回查确认生效。
- 被动回复有窗口限制:群内同一凭据 5 分钟内最多 5 条;主动消息默认未开通,
超时通知发送失败时仅记录日志(禁言/踢人不受影响)。
- 兜底禁言同样需要机器人是群管理员。
## 测试
```bash
.venv\Scripts\python -m pytest tests/ -v
```
覆盖验证码生成/编解码、状态持久化、定时器触发与取消、重启恢复、配置校验、
处理器装配(不发起任何网络请求)。