# 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 ``` 覆盖验证码生成/编解码、状态持久化、定时器触发与取消、重启恢复、配置校验、 处理器装配(不发起任何网络请求)。