mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-21 12:10:13 +08:00
bugfix:修复sqlite部分场景下锁竞争问题;新增插件恶意触发配置文件 (#2144)
* bugfix:修复sqlite部分场景下锁竞争问题;新增插件恶意触发配置文件 * 文件没同步完
This commit is contained in:
@@ -40,6 +40,24 @@ Config.add_plugin_config(
|
||||
type=int,
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"hook",
|
||||
"MALICIOUS_CHECK_MODE",
|
||||
"off",
|
||||
help="恶意触发检测模式:off=关闭,blacklist=仅列表插件检测,whitelist=列表插件跳过检测",
|
||||
default_value="off",
|
||||
type=str,
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"hook",
|
||||
"MALICIOUS_CHECK_PLUGINS",
|
||||
[],
|
||||
help="恶意触发检测插件列表,按模式作为黑名单或白名单使用,填插件模块名",
|
||||
default_value=[],
|
||||
type=list,
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"hook",
|
||||
"IS_SEND_TIP_MESSAGE",
|
||||
|
||||
@@ -17,7 +17,7 @@ from zhenxun.models.plugin_info import PluginInfo
|
||||
from zhenxun.models.user_console import UserConsole
|
||||
from zhenxun.services.cache.cache_containers import CacheDict
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.services.message_load import signal_overload
|
||||
from zhenxun.services.message_load import is_db_unhealthy, signal_overload
|
||||
from zhenxun.utils.enum import GoldHandle, PluginType
|
||||
from zhenxun.utils.exception import InsufficientGold
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
@@ -811,6 +811,8 @@ async def _run_selected_matcher(
|
||||
dependency_cache,
|
||||
lane: str = "command_exact",
|
||||
) -> None:
|
||||
# state is copied per matcher before dispatch; keep lane matcher-local.
|
||||
state["_zx_dispatch_lane"] = lane
|
||||
async with _dispatch_lane_section(lane):
|
||||
await nb_message.check_and_run_matcher(
|
||||
matcher,
|
||||
@@ -938,6 +940,11 @@ async def _has_limits_cached(
|
||||
event_cache.setdefault("module_limit_entries", {})[module] = limit_entries
|
||||
event_cache.setdefault("module_limits_ready", {})[module] = True
|
||||
return has_limits
|
||||
if is_db_unhealthy():
|
||||
module_limit_cache[module] = False
|
||||
if event_cache is not None:
|
||||
event_cache.setdefault("module_limits_ready", {})[module] = False
|
||||
return False
|
||||
limits = await LimitManager.get_module_limits(module)
|
||||
has_limits = bool(limits)
|
||||
module_limit_cache[module] = has_limits
|
||||
@@ -1075,7 +1082,7 @@ async def _get_plugin_cache_first(
|
||||
|
||||
plugin = provider.get_plugin_if_ready(module)
|
||||
cache_miss = plugin is None and not provider.plugin_cache_loaded()
|
||||
if plugin is None and allow_cache_load:
|
||||
if plugin is None and allow_cache_load and not is_db_unhealthy():
|
||||
plugin = await provider.get_plugin(module)
|
||||
cache_miss = False
|
||||
if event_cache is not None:
|
||||
@@ -1324,6 +1331,9 @@ async def _prepare_auth_state_with_fallback(
|
||||
)
|
||||
if prep is not None:
|
||||
return prep
|
||||
if is_db_unhealthy():
|
||||
hook_recorder.set("auth_snapshot", "cache_miss_db_unhealthy")
|
||||
return None
|
||||
hook_recorder.set("auth_snapshot", "cache_miss_fallback")
|
||||
return await _prepare_auth_state(
|
||||
module=module,
|
||||
@@ -1408,6 +1418,9 @@ async def _resolve_cost_gold(
|
||||
if prep.profile.cost_gold <= 0:
|
||||
hook_recorder.set("cost_gold", "skipped")
|
||||
return 0
|
||||
if is_db_unhealthy():
|
||||
hook_recorder.set("cost_gold", "db_unhealthy")
|
||||
raise SkipPluginException("数据库繁忙,金币功能暂不可用...")
|
||||
cost_start = time.time()
|
||||
try:
|
||||
if prep.user is None:
|
||||
|
||||
@@ -39,6 +39,49 @@ class HandleEventSelectorDependencies:
|
||||
_HANDLE_EVENT_PATCHED = False
|
||||
_ORIGINAL_HANDLE_EVENT: Callable[..., Awaitable[None]] | None = None
|
||||
_ORIGINAL_ADAPTER_HANDLE_EVENTS: dict[object, object] = {}
|
||||
_MATCHER_DEADLINE_BY_LANE = {
|
||||
"system": 15.0,
|
||||
"command": 12.0,
|
||||
"temp": 15.0,
|
||||
"passive_light": 3.0,
|
||||
"fallback_ai": 5.0,
|
||||
}
|
||||
_DEFAULT_MATCHER_DEADLINE = 5.0
|
||||
|
||||
|
||||
def _matcher_deadline_for_lane(lane: str) -> float:
|
||||
return _MATCHER_DEADLINE_BY_LANE.get(lane, _DEFAULT_MATCHER_DEADLINE)
|
||||
|
||||
|
||||
def _matcher_name(matcher: type[Matcher]) -> str:
|
||||
module = str(getattr(matcher, "module", "") or "")
|
||||
lineno = str(getattr(matcher, "lineno", "") or "")
|
||||
matcher_type = str(getattr(matcher, "type", "") or "")
|
||||
name = module or matcher.__name__
|
||||
if lineno:
|
||||
name = f"{name}:{lineno}"
|
||||
if matcher_type:
|
||||
name = f"{name}<{matcher_type}>"
|
||||
return name
|
||||
|
||||
|
||||
async def _run_matcher_with_deadline(
|
||||
anyio_mod: Any,
|
||||
coro: Awaitable[None],
|
||||
matcher: type[Matcher],
|
||||
lane: str,
|
||||
) -> None:
|
||||
timeout = _matcher_deadline_for_lane(lane)
|
||||
try:
|
||||
with anyio_mod.fail_after(timeout):
|
||||
await coro
|
||||
except TimeoutError:
|
||||
signal_overload(20.0)
|
||||
logger.warning(
|
||||
"matcher dispatch timeout: "
|
||||
f"matcher={_matcher_name(matcher)}, lane={lane}, timeout={timeout:.1f}s",
|
||||
LOGGER_COMMAND,
|
||||
)
|
||||
|
||||
|
||||
def _trim_leading_text(message: Any) -> None:
|
||||
@@ -140,7 +183,6 @@ async def patched_handle_event(
|
||||
stop_propagation = getattr(nb_message, "StopPropagation")
|
||||
handle_exception = getattr(nb_message, "_handle_exception")
|
||||
anyio_mod = getattr(nb_message, "anyio")
|
||||
run_coro_with_shield = getattr(nb_message, "run_coro_with_shield")
|
||||
|
||||
async with async_exit_stack() as stack:
|
||||
if not await apply_event_preprocessors(
|
||||
@@ -256,7 +298,8 @@ async def patched_handle_event(
|
||||
continue
|
||||
matcher_state = deps.build_matcher_state(state)
|
||||
tg.start_soon(
|
||||
run_coro_with_shield,
|
||||
_run_matcher_with_deadline,
|
||||
anyio_mod,
|
||||
deps.run_selected_matcher(
|
||||
matcher,
|
||||
bot,
|
||||
@@ -266,6 +309,8 @@ async def patched_handle_event(
|
||||
dependency_cache,
|
||||
lane,
|
||||
),
|
||||
matcher,
|
||||
lane,
|
||||
)
|
||||
|
||||
if show_log:
|
||||
|
||||
@@ -10,6 +10,7 @@ from nonebot.adapters import Bot, Event
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
|
||||
from zhenxun.services.message_load import is_db_unhealthy
|
||||
from zhenxun.utils.utils import EntityIDs
|
||||
|
||||
from .auth.context import (
|
||||
@@ -296,6 +297,9 @@ async def policy_precheck_stage(
|
||||
ctx.flags = apply_policy_precheck(ctx, deps)
|
||||
except PermissionExemption as exc:
|
||||
_recorder(ctx).set("policy_fallback", str(exc))
|
||||
if is_db_unhealthy():
|
||||
ctx.stop(allowed=True, effect="allow", reason="db_unhealthy_cache_miss")
|
||||
return
|
||||
ctx.prep = await deps.prepare_auth_state(
|
||||
module=ctx.module,
|
||||
context=ctx.event_context,
|
||||
|
||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from zhenxun.services.message_load import is_db_unhealthy
|
||||
from zhenxun.utils.enum import BlockType, PluginType
|
||||
|
||||
from .auth.data_provider import (
|
||||
@@ -103,7 +104,7 @@ async def get_plugin_auth_profile(
|
||||
if limits is None:
|
||||
limits = provider.get_module_limits_if_ready(module)
|
||||
limits_ready = limits is not None
|
||||
if limits is None and allow_cache_load:
|
||||
if limits is None and allow_cache_load and not is_db_unhealthy():
|
||||
limits = await provider.get_module_limits(module)
|
||||
limits_ready = True
|
||||
if limits is None:
|
||||
|
||||
@@ -10,7 +10,9 @@ from zhenxun.services.cache.runtime_cache import (
|
||||
GroupSnapshot,
|
||||
LevelUserSnapshot,
|
||||
)
|
||||
from zhenxun.services.db_context import with_db_timeout
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.services.message_load import is_db_unhealthy
|
||||
|
||||
from .auth.config import LOGGER_COMMAND
|
||||
from .auth.context import EventContext
|
||||
@@ -50,6 +52,41 @@ def _build_runtime_group_snapshot(context: EventContext) -> GroupSnapshot | None
|
||||
)
|
||||
|
||||
|
||||
def _build_default_bot_snapshot(context: EventContext) -> BotSnapshot:
|
||||
"""Fail-open bot snapshot used only while DB cold-path is unhealthy."""
|
||||
return BotSnapshot(
|
||||
bot_id=context.bot_id,
|
||||
status=True,
|
||||
platform=context.platform,
|
||||
block_plugins="",
|
||||
block_tasks="",
|
||||
available_plugins="",
|
||||
available_tasks="",
|
||||
)
|
||||
|
||||
|
||||
def _build_default_group_snapshot(context: EventContext) -> GroupSnapshot | None:
|
||||
"""Fail-open group snapshot used only while DB cold-path is unhealthy."""
|
||||
if not context.group_id:
|
||||
return None
|
||||
return GroupSnapshot(
|
||||
group_id=context.group_id,
|
||||
channel_id=context.channel_id,
|
||||
group_name="",
|
||||
max_member_count=0,
|
||||
member_count=0,
|
||||
status=True,
|
||||
level=5,
|
||||
is_super=False,
|
||||
group_flag=0,
|
||||
block_plugin="",
|
||||
superuser_block_plugin="",
|
||||
block_task="",
|
||||
superuser_block_task="",
|
||||
platform=context.platform,
|
||||
)
|
||||
|
||||
|
||||
def _qq_client_group_repair_key(context: EventContext) -> tuple[str, str] | None:
|
||||
if context.platform_scope != "qq_client" or not context.group_id:
|
||||
return None
|
||||
@@ -72,6 +109,8 @@ async def _repair_missing_qq_client_group(
|
||||
provider: PermissionDataProvider,
|
||||
) -> GroupSnapshot | None:
|
||||
"""Persist a minimal OneBot group when startup group sync returned empty."""
|
||||
if is_db_unhealthy():
|
||||
return None
|
||||
key = _qq_client_group_repair_key(context)
|
||||
if key is None or not provider.group_cache_loaded():
|
||||
return None
|
||||
@@ -97,9 +136,14 @@ async def _repair_missing_qq_client_group(
|
||||
"group_flag": 1,
|
||||
"platform": context.platform,
|
||||
}
|
||||
group, _ = await GroupConsole.get_or_create_root_group(
|
||||
group_id=group_id,
|
||||
defaults=defaults,
|
||||
group, _ = await with_db_timeout(
|
||||
GroupConsole.get_or_create_root_group(
|
||||
group_id=group_id,
|
||||
defaults=defaults,
|
||||
),
|
||||
timeout=2.0,
|
||||
operation="GroupConsole.get_or_create_root_group",
|
||||
source="auth_snapshot.repair_missing_group",
|
||||
)
|
||||
from zhenxun.services.cache.runtime_cache import GroupMemoryCache
|
||||
|
||||
@@ -129,6 +173,7 @@ class AuthSnapshot:
|
||||
ban_state: bool | None = None
|
||||
user_balance_loaded: bool = False
|
||||
user_balance: int | None = None
|
||||
db_unhealthy: bool = False
|
||||
cache_misses: frozenset[str] = field(default_factory=frozenset)
|
||||
|
||||
@property
|
||||
@@ -173,43 +218,63 @@ async def build_auth_snapshot(
|
||||
event_cache = context.event_cache
|
||||
entity = context.entity
|
||||
cache_misses: set[str] = set()
|
||||
db_unhealthy = is_db_unhealthy()
|
||||
can_load_cache = allow_cache_load and not db_unhealthy
|
||||
|
||||
bot_data: BotSnapshot | None = None
|
||||
if (
|
||||
event_cache is not None
|
||||
and "bot_data" in event_cache
|
||||
and (event_cache.get("bot_cache_ready") or not allow_cache_load)
|
||||
and (event_cache.get("bot_cache_ready") or not can_load_cache)
|
||||
):
|
||||
bot_data = event_cache.get("bot_data")
|
||||
else:
|
||||
bot_data = provider.get_bot_if_ready(bot.self_id)
|
||||
if bot_data is None:
|
||||
if allow_cache_load:
|
||||
if can_load_cache:
|
||||
bot_data = await provider.get_bot(bot.self_id)
|
||||
elif db_unhealthy:
|
||||
bot_data = _build_default_bot_snapshot(context)
|
||||
elif not provider.bot_cache_loaded():
|
||||
cache_misses.add("bot")
|
||||
if event_cache is not None:
|
||||
event_cache["bot_data"] = bot_data
|
||||
event_cache["bot_cache_ready"] = provider.bot_cache_loaded()
|
||||
event_cache["bot_cache_ready"] = provider.bot_cache_loaded() or db_unhealthy
|
||||
if bot_data is None and db_unhealthy:
|
||||
bot_data = _build_default_bot_snapshot(context)
|
||||
if event_cache is not None:
|
||||
event_cache["bot_data"] = bot_data
|
||||
event_cache["bot_cache_ready"] = True
|
||||
|
||||
group = None
|
||||
if entity.group_id:
|
||||
if (
|
||||
event_cache is not None
|
||||
and "group" in event_cache
|
||||
and (event_cache.get("group_cache_ready") or not allow_cache_load)
|
||||
and (event_cache.get("group_cache_ready") or not can_load_cache)
|
||||
):
|
||||
group = event_cache.get("group")
|
||||
else:
|
||||
group = provider.get_group_if_ready(entity.group_id, entity.channel_id)
|
||||
if group is None and not provider.group_cache_loaded():
|
||||
cache_misses.add("group")
|
||||
elif group is None and allow_cache_load:
|
||||
elif group is None and can_load_cache:
|
||||
group = await provider.get_group(entity.group_id, entity.channel_id)
|
||||
if group is None and db_unhealthy:
|
||||
group = _build_default_group_snapshot(context)
|
||||
cache_misses.discard("group")
|
||||
if event_cache is not None:
|
||||
event_cache["group"] = group
|
||||
event_cache["group_cache_ready"] = provider.group_cache_loaded()
|
||||
if group is None:
|
||||
event_cache["group_cache_ready"] = (
|
||||
provider.group_cache_loaded() or db_unhealthy
|
||||
)
|
||||
if group is None and db_unhealthy:
|
||||
group = _build_default_group_snapshot(context)
|
||||
cache_misses.discard("group")
|
||||
if event_cache is not None:
|
||||
event_cache["group"] = group
|
||||
event_cache["group_cache_ready"] = True
|
||||
if group is None and not db_unhealthy:
|
||||
group = await _repair_missing_qq_client_group(
|
||||
context,
|
||||
provider=provider,
|
||||
@@ -232,7 +297,7 @@ async def build_auth_snapshot(
|
||||
if (
|
||||
event_cache is not None
|
||||
and "admin_levels" in event_cache
|
||||
and (event_cache.get("admin_cache_ready") or not allow_cache_load)
|
||||
and (event_cache.get("admin_cache_ready") or not can_load_cache)
|
||||
):
|
||||
admin_levels = event_cache.get("admin_levels")
|
||||
else:
|
||||
@@ -241,16 +306,26 @@ async def build_auth_snapshot(
|
||||
entity.group_id,
|
||||
)
|
||||
if admin_levels is None:
|
||||
if allow_cache_load:
|
||||
if can_load_cache:
|
||||
admin_levels = await provider.get_admin_levels(
|
||||
entity.user_id,
|
||||
entity.group_id,
|
||||
)
|
||||
elif db_unhealthy:
|
||||
admin_levels = (None, None)
|
||||
else:
|
||||
cache_misses.add("admin_levels")
|
||||
if event_cache is not None:
|
||||
event_cache["admin_levels"] = admin_levels
|
||||
event_cache["admin_cache_ready"] = provider.admin_cache_loaded()
|
||||
event_cache["admin_cache_ready"] = (
|
||||
provider.admin_cache_loaded() or db_unhealthy
|
||||
)
|
||||
if admin_levels is None and db_unhealthy and not provider.admin_cache_loaded():
|
||||
admin_levels = (None, None)
|
||||
cache_misses.discard("admin_levels")
|
||||
if event_cache is not None:
|
||||
event_cache["admin_levels"] = admin_levels
|
||||
event_cache["admin_cache_ready"] = True
|
||||
|
||||
ban_state = None
|
||||
if not skip_ban:
|
||||
@@ -260,11 +335,15 @@ async def build_auth_snapshot(
|
||||
ban_state = provider.is_banned(entity.user_id, entity.group_id)
|
||||
if event_cache is not None:
|
||||
event_cache["ban_state"] = ban_state
|
||||
elif allow_cache_load:
|
||||
elif can_load_cache:
|
||||
await provider.ensure_ban_loaded()
|
||||
ban_state = provider.is_banned(entity.user_id, entity.group_id)
|
||||
if event_cache is not None:
|
||||
event_cache["ban_state"] = ban_state
|
||||
elif db_unhealthy:
|
||||
ban_state = False
|
||||
if event_cache is not None:
|
||||
event_cache["ban_state"] = ban_state
|
||||
else:
|
||||
cache_misses.add("ban")
|
||||
|
||||
@@ -276,6 +355,7 @@ async def build_auth_snapshot(
|
||||
group=group,
|
||||
admin_levels=admin_levels,
|
||||
ban_state=ban_state,
|
||||
db_unhealthy=db_unhealthy,
|
||||
cache_misses=frozenset(cache_misses),
|
||||
)
|
||||
|
||||
|
||||
@@ -61,6 +61,88 @@ _blmt = BanCheckLimiter(
|
||||
4,
|
||||
)
|
||||
|
||||
_MALICIOUS_CHECK_MODES = {"off", "blacklist", "whitelist"}
|
||||
_EVENT_PLUGIN_DEDUPE_TTL = 30.0
|
||||
_EVENT_PLUGIN_DEDUPE_MAX = 4096
|
||||
_event_plugin_seen: dict[str, float] = {}
|
||||
|
||||
|
||||
def _malicious_check_mode() -> str:
|
||||
mode = str(Config.get_config("hook", "MALICIOUS_CHECK_MODE") or "off")
|
||||
mode = mode.strip().lower()
|
||||
return mode if mode in _MALICIOUS_CHECK_MODES else "off"
|
||||
|
||||
|
||||
def _malicious_plugin_set() -> set[str]:
|
||||
value = Config.get_config("hook", "MALICIOUS_CHECK_PLUGINS")
|
||||
if value is None:
|
||||
return set()
|
||||
if isinstance(value, str):
|
||||
items = value.replace("\n", ",").split(",")
|
||||
elif isinstance(value, list | tuple | set):
|
||||
items = value
|
||||
else:
|
||||
items = [value]
|
||||
return {str(item).strip().casefold() for item in items if str(item).strip()}
|
||||
|
||||
|
||||
def _should_check_plugin(module: str, lane: str) -> bool:
|
||||
mode = _malicious_check_mode()
|
||||
if mode == "off":
|
||||
return False
|
||||
|
||||
normalized_module = str(module or "").strip().casefold()
|
||||
if not normalized_module:
|
||||
return False
|
||||
|
||||
plugin_set = _malicious_plugin_set()
|
||||
in_plugin_set = normalized_module in plugin_set
|
||||
is_passive = str(lane or "").startswith("passive_")
|
||||
|
||||
if mode == "blacklist":
|
||||
return in_plugin_set
|
||||
if is_passive:
|
||||
return False
|
||||
if mode == "whitelist":
|
||||
return not in_plugin_set
|
||||
return False
|
||||
|
||||
|
||||
def _event_plugin_key(event: Event, user_id: str, module: str) -> str:
|
||||
message_id = getattr(event, "message_id", None) or getattr(event, "id", None)
|
||||
if message_id is None:
|
||||
message_id = id(event)
|
||||
return f"{message_id}:{user_id}:{module}"
|
||||
|
||||
|
||||
def _remember_event_plugin_once(key: str) -> bool:
|
||||
now = time.monotonic()
|
||||
expires_at = _event_plugin_seen.get(key)
|
||||
if expires_at is not None and expires_at > now:
|
||||
return False
|
||||
|
||||
_event_plugin_seen[key] = now + _EVENT_PLUGIN_DEDUPE_TTL
|
||||
if len(_event_plugin_seen) > _EVENT_PLUGIN_DEDUPE_MAX:
|
||||
target_size = _EVENT_PLUGIN_DEDUPE_MAX // 2
|
||||
for cache_key, cache_expires_at in list(_event_plugin_seen.items()):
|
||||
if cache_expires_at <= now or len(_event_plugin_seen) > target_size:
|
||||
_event_plugin_seen.pop(cache_key, None)
|
||||
if len(_event_plugin_seen) <= target_size:
|
||||
break
|
||||
return True
|
||||
|
||||
|
||||
def _mark_event_plugin_checked(
|
||||
state: T_State, event: Event, user_id: str, module: str
|
||||
) -> bool:
|
||||
checked = state.setdefault("_zx_malicious_checked_plugins", set())
|
||||
if isinstance(checked, set):
|
||||
if module in checked:
|
||||
return False
|
||||
checked.add(module)
|
||||
|
||||
return _remember_event_plugin_once(_event_plugin_key(event, user_id, module))
|
||||
|
||||
|
||||
def _get_positive_config(key: str, cast_type: type[int] | type[float]) -> int | float:
|
||||
value = Config.get_config("hook", key)
|
||||
@@ -102,6 +184,10 @@ async def _(
|
||||
else:
|
||||
return
|
||||
|
||||
lane = state.get("_zx_dispatch_lane")
|
||||
if not _should_check_plugin(module, lane if isinstance(lane, str) else ""):
|
||||
return
|
||||
|
||||
user_id = resolve_actor_user_id(event, session.id1)
|
||||
group_id = resolve_event_group_id(event, session.id3 or session.id2)
|
||||
# 超级用户豁免恶意检测(A6):与权威权限路径保持一致,避免误封管理者。
|
||||
@@ -111,35 +197,42 @@ async def _(
|
||||
is_superuser = user_id in bot.config.superusers
|
||||
if is_superuser:
|
||||
return
|
||||
else:
|
||||
return
|
||||
|
||||
if not _mark_event_plugin_checked(state, event, user_id, module):
|
||||
return
|
||||
|
||||
# 只统计通过模式/lane过滤且同事件同插件去重后的有效触发。
|
||||
limiter_key = f"{user_id}__{module}"
|
||||
malicious_check_time = float(_get_positive_config("MALICIOUS_CHECK_TIME", float))
|
||||
malicious_ban_count = int(_get_positive_config("MALICIOUS_BAN_COUNT", int))
|
||||
malicious_ban_time = int(_get_positive_config("MALICIOUS_BAN_TIME", int))
|
||||
_blmt.configure(malicious_check_time, malicious_ban_count)
|
||||
if user_id and module:
|
||||
if _blmt.check(f"{user_id}__{module}"):
|
||||
await BanConsole.ban(
|
||||
user_id,
|
||||
group_id,
|
||||
9,
|
||||
"恶意触发命令检测",
|
||||
malicious_ban_time * 60,
|
||||
bot.self_id,
|
||||
)
|
||||
logger.info(
|
||||
f"触发了恶意触发检测: {matcher.plugin_name}",
|
||||
"HOOK",
|
||||
session=session,
|
||||
)
|
||||
await MessageUtils.build_message(
|
||||
[
|
||||
At(flag="user", target=user_id),
|
||||
"检测到恶意触发命令,您将被封禁 30 分钟",
|
||||
]
|
||||
).send()
|
||||
logger.debug(
|
||||
f"触发了恶意触发检测: {matcher.plugin_name}",
|
||||
"HOOK",
|
||||
session=session,
|
||||
)
|
||||
raise IgnoredException("检测到恶意触发命令")
|
||||
_blmt.add(f"{user_id}__{module}")
|
||||
if _blmt.check(limiter_key):
|
||||
await BanConsole.ban(
|
||||
user_id,
|
||||
group_id,
|
||||
9,
|
||||
"恶意触发命令检测",
|
||||
malicious_ban_time * 60,
|
||||
bot.self_id,
|
||||
)
|
||||
logger.info(
|
||||
f"触发了恶意触发检测: {matcher.plugin_name}",
|
||||
"HOOK",
|
||||
session=session,
|
||||
)
|
||||
await MessageUtils.build_message(
|
||||
[
|
||||
At(flag="user", target=user_id),
|
||||
"检测到恶意触发命令,您将被封禁 30 分钟",
|
||||
]
|
||||
).send()
|
||||
logger.debug(
|
||||
f"触发了恶意触发检测: {matcher.plugin_name}",
|
||||
"HOOK",
|
||||
session=session,
|
||||
)
|
||||
raise IgnoredException("检测到恶意触发命令")
|
||||
_blmt.add(limiter_key)
|
||||
|
||||
Reference in New Issue
Block a user