From 00f874665d13893a61ad5d27ccb3d8a3a2f4987c Mon Sep 17 00:00:00 2001 From: liuwei Date: Mon, 20 Apr 2026 11:28:05 +0800 Subject: [PATCH] =?UTF-8?q?=E9=99=90=E5=88=B6=E7=BE=A4=E7=BA=A7=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E9=85=8D=E7=BD=AE=E4=BB=85=E5=BC=80=E6=94=BE=E7=BE=A4?= =?UTF-8?q?=E6=88=90=E5=91=98=E5=8F=98=E6=9B=B4=E7=9B=91=E6=8E=A7=E5=B9=B6?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=90=8E=E7=AB=AF=E7=99=BD=E5=90=8D=E5=8D=95?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blueprints/group_plugin_config.py | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/admin/dashboard/blueprints/group_plugin_config.py b/admin/dashboard/blueprints/group_plugin_config.py index 56a0773..ad026c0 100644 --- a/admin/dashboard/blueprints/group_plugin_config.py +++ b/admin/dashboard/blueprints/group_plugin_config.py @@ -7,6 +7,11 @@ from .auth import login_required group_plugin_config_bp = Blueprint("group_plugin_config", __name__, url_prefix="/group_plugin_config") +# 群级插件配置白名单: +# 当前业务阶段仅开放“群成员变更监控”,其余插件统一在后端拦截, +# 防止前端被绕过后写入不受控配置。 +ALLOWED_PLUGIN_NAMES = {"群成员变更监控"} + def _normalize_datetime_text(value): if value is None: @@ -19,6 +24,11 @@ def _normalize_datetime_text(value): return text +def _is_plugin_allowed(plugin_name: str) -> bool: + """检查插件名是否在群级配置白名单内。""" + return str(plugin_name or "").strip() in ALLOWED_PLUGIN_NAMES + + @group_plugin_config_bp.route("/") @login_required def page_group_plugin_config(): @@ -32,7 +42,18 @@ def api_list_group_plugin_config(): service = server.group_plugin_config_service group_id = str(request.args.get("group_id", "") or "").strip() plugin_name = str(request.args.get("plugin_name", "") or "").strip() - rows = service.list_configs(group_id=group_id, plugin_name=plugin_name) + # 列表接口默认仅返回白名单插件,避免管理端仍出现其它插件配置。 + # 若传入了非白名单插件名,直接返回空列表。 + if plugin_name and not _is_plugin_allowed(plugin_name): + return jsonify({"success": True, "data": []}) + if not plugin_name: + # service.list_configs 当前仅支持单个 plugin_name 过滤参数, + # 这里通过遍历白名单并聚合,确保结果严格受控。 + rows = [] + for allowed_name in sorted(ALLOWED_PLUGIN_NAMES): + rows.extend(service.list_configs(group_id=group_id, plugin_name=allowed_name)) + else: + rows = service.list_configs(group_id=group_id, plugin_name=plugin_name) for row in rows: row["created_at"] = _normalize_datetime_text(row.get("created_at")) row["updated_at"] = _normalize_datetime_text(row.get("updated_at")) @@ -42,9 +63,8 @@ def api_list_group_plugin_config(): @group_plugin_config_bp.route("/api/plugins", methods=["GET"]) @login_required def api_list_plugins(): - server = current_app.dashboard_server - plugin_names = sorted([str(p.name) for p in server.plugin_manager.plugins.values()]) - return jsonify({"success": True, "data": plugin_names}) + # 插件下拉框只暴露白名单,前端无需自行过滤。 + return jsonify({"success": True, "data": sorted(ALLOWED_PLUGIN_NAMES)}) @group_plugin_config_bp.route("/api/upsert", methods=["POST"]) @@ -63,6 +83,8 @@ def api_upsert_group_plugin_config(): if not group_id or not plugin_name: return jsonify({"success": False, "message": "group_id 或 plugin_name 不能为空"}), 400 + if not _is_plugin_allowed(plugin_name): + return jsonify({"success": False, "message": f"当前仅允许配置:{','.join(sorted(ALLOWED_PLUGIN_NAMES))}"}), 400 if isinstance(config_data, str): try: @@ -96,6 +118,8 @@ def api_delete_group_plugin_config(): config_key = str(payload.get("config_key") or "default").strip() or "default" if not group_id or not plugin_name: return jsonify({"success": False, "message": "group_id 或 plugin_name 不能为空"}), 400 + if not _is_plugin_allowed(plugin_name): + return jsonify({"success": False, "message": f"当前仅允许配置:{','.join(sorted(ALLOWED_PLUGIN_NAMES))}"}), 400 ok = service.delete_config(group_id=group_id, plugin_name=plugin_name, config_key=config_key) if not ok: