#6725·MoviePilot

[错误报告]: 未设置消息类型(mtype)的通知会绕过通知发送范围,企业微信以 touser=@all 广播

Author: q10710Created Sep 18, 2026Updated Sep 18, 2026
Labelsbug

确认

  • 我的版本是最新版本,我的版本号与 version 相同。
  • 我已经 issue 中搜索过,确认我的问题没有被提出过。
  • 我已经 Telegram频道 中搜索过,确认我的问题没有被提出过。
  • 我已经修改标题,将标题中的 描述 替换为我遇到的问题。

当前程序版本

v3.0.4

运行环境

Docker

问题类型

主程序运行问题

问题描述

现象

  • 通知发送范围(系统设置 → 通知)中,把「站点 / 媒体服务器 / 手动处理 / 插件 / 智能体 / 其它」都设为仅管理员后,企业微信应用可见范围内的非管理员用户仍然能收到这些通知
  • 受影响的通知几乎覆盖所有类型,用户侧观感是「通知发送范围设置没有生效」。

复现步骤

  1. 系统设置 → 通知:把场景「站点」的发送范围设为「仅管理员」。
  2. 触发一条**没有设置消息类型(mtype=None)**的通知。主程序自带的工作流「发送消息」动作就是这种情况:app/workflow/actions/send_message.py 构造 Message(source=client, userid=params.userid, title="【工作流执行结果】", text=msg_text, link=...)没有传 mtype;该动作 userid 留空时为 None
  3. 经由企业微信通知渠道(WECHAT_MODE=app,企业微信应用消息)发送。
  4. 结果:该企业微信应用可见范围内的全员都收到消息,包含非管理员、以及未勾选任何场景的用户。

期望行为

  • 未设置 mtype 的通知,应走最保守的投递范围(至少等同「仅管理员」),而不是广播给应用可见范围内的所有人。
  • 渠道侧也不应因为 mtype 为空而完全跳过通知场景开关校验。

已定位(v3.0.4 源码,均已核对)

  1. app/chain/_messaging.py::_notification_route_action()if message.userid or not message.mtype: return None —— mtype 为空时直接不读路由配置,action=None
  2. app/chain/_messaging.py::_notification_route_steps()send_original = not action 成立,且 action 为空时遍历不执行 → 最终 yield _NotificationRouteDelivery(message=message, ...),即原样投递原消息targetsuserid 仍为 None)。
  3. app/modules/wechat/__init__.py::post_message()if not userid and targets is not None: userid = targets.get('wechat_userid') —— targetsNone 时不会进入该分支,userid 保持 None
  4. app/modules/wechat/wechat.py::__send_message()if not userid: userid = "@all" → 请求体 {"touser": "@all", "agentid": ...} → 企业微信应用可见范围内全员
  5. app/modules/__init__.py::check_message():场景开关判据是 if not message.userid and message.mtype: —— mtype 为空时整段被跳过,渠道侧没有第二道闸
  6. WECHAT_ADMINS 仅用于「接收指令」的鉴权(modules/_base/notification.pyresolve_config_principal_ids),不限制外发,因此管理员白名单兜不住这个问题。

同类缺口(同一成因)

  • get_notification_switch() 找不到匹配 type 时同样返回 None → 任何未登记在 NotificationSwitchs 中的消息类型也会走原样投递 → @all,默认方向不安全。
  • 用户类场景(资源下载 / 整理入库 / 订阅 = user,admin)中,若消息没有责任人username 为空),_notification_route_steps()user 分支条件不成立 → 直接走 elsebreak不会继续投递给 admin,同样退化为 @all 广播。

影响面

  • 任何调用 post_message(...) 而没设置 mtype 的通知都会 @all 广播;主程序自带的工作流「发送消息」动作(【工作流执行结果】通知)就属于此类,第三方插件也存在同类调用。
  • 实际生效的边界只剩下企业微信「应用可见范围」,因此用户会误判为「通知发送范围配置失效」。

验证方式

  • 用主程序真实路由函数 _notification_route_steps() 与现网 NotificationSwitchs 取值做离线模拟(不发送真实消息):带 mtype 的站点 / 插件类通知只投递给管理员;而 mtype=None 的通知(工作流执行结果、无责任人的订阅类通知)最终 touser=None → 由渠道兜底为 @all
  • 本 Issue 未附加私有日志:问题在代码层面即可复现,为避免带入无关的会话内容,日志区留空。

建议修复方向(供参考)

  • _notification_route_action() 对无 mtype 的通知返回保守范围(例如 admin),或在 _notification_route_steps() 中当 action 为空时按 admin 处理;
  • check_message()mtype 为空时不视为通过场景开关校验;
  • wechat.__send_message()userid 兜底改为管理员,或让广播必须由调用方显式声明。

发生问题时系统日志和配置文件

bash
### Doctor 摘要
状态:healthy
运行环境:Docker
汇总:total=14 error=0 warn=1 advisory=1 fixed=0
关键发现:
- [warn/advisory] 最近日志存在插件异常;来源:autosignin.log;命中:5 条,去重后 2 条;建议:可使用安全模式启动后检查插件配置。

### 日志筛选依据
策略:time_window_and_keyword_block_match
时间窗口:最近 60 分钟
窗口起点:2026-09-18T20:03:51
关键词:未提供具体关键词
单文件最多保留:80 行
提示:未提供具体关键词,已跳过日志正文收集以避免误带无关日志。
命中文件:无

本 Issue 由 MoviePilot Agent 协助用户提交。