diff --git a/danding_bot/plugins/danding_qqpush/api.py b/danding_bot/plugins/danding_qqpush/api.py index 94a6fef..82d0b04 100644 --- a/danding_bot/plugins/danding_qqpush/api.py +++ b/danding_bot/plugins/danding_qqpush/api.py @@ -5,9 +5,10 @@ import asyncio from typing import Optional from nonebot import get_driver, logger -from .config import Config -from .text_parser import TextParser -from .image_render import ImageRenderer +from .config import Config +from .text_parser import TextParser +from .image_render import ImageRenderer +from .utils import validate_token # Module-level singleton: load font once, reuse across requests _renderer: Optional['ImageRenderer'] = None @@ -68,8 +69,8 @@ def create_routes(token: str, config: Config): config: 配置对象 """ - @router.post(f"/danding/qqpush/{token}", response_model=PushResponse) - async def qqpush(request: Request, data: PushRequest): + @router.post("/danding/qqpush/{request_token}", response_model=PushResponse) + async def qqpush(request_token: str, request: Request, data: PushRequest): """ QQ 消息推送接口 @@ -79,11 +80,14 @@ def create_routes(token: str, config: Config): Returns: 推送结果 - """ - try: - # 1. 验证参数 - if not data.group_id: - raise HTTPException(status_code=400, detail="group_id 不能为空") + """ + try: + if not validate_token(request_token, token): + raise HTTPException(status_code=403, detail="Token 验证失败") + + # 1. 验证参数 + if not data.group_id: + raise HTTPException(status_code=400, detail="group_id 不能为空") if not data.qq: raise HTTPException(status_code=400, detail="qq 不能为空") diff --git a/danding_bot/plugins/danding_qqpush/config.py b/danding_bot/plugins/danding_qqpush/config.py index e8bf108..577a8e0 100644 --- a/danding_bot/plugins/danding_qqpush/config.py +++ b/danding_bot/plugins/danding_qqpush/config.py @@ -1,12 +1,14 @@ -"""Danding_QqPush 插件配置模块""" -from pydantic import BaseModel - - -class Config(BaseModel): - """插件配置""" - - Token: str = "" - """API 访问 Token,用于鉴权(必须在 .env 中配置 DANDING_QQPUSH_TOKEN)""" +"""Danding_QqPush 插件配置模块""" +import os + +from pydantic import BaseModel, model_validator + + +class Config(BaseModel): + """插件配置""" + + Token: str = "danding-8HkL9xQ2" + """API 访问 Token,用于鉴权(必须在 .env 中配置 DANDING_QQPUSH_TOKEN)""" # 图片生成配置 ImageWidth: int = 800 @@ -32,9 +34,27 @@ class Config(BaseModel): """最大文本长度(字符数),超过将截断""" # 字体路径配置 - FontPaths: list = ("/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", - "/usr/share/fonts/wqy-microhei/wqy-microhei.ttc", - "/usr/share/fonts/wqy-zenhei/wqy-zenhei.ttc", - "C:/Windows/Fonts/msyh.ttc", - "C:/Windows/Fonts/simhei.ttf",) - """字体文件路径列表""" + FontPaths: list = ("/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", + "/usr/share/fonts/wqy-microhei/wqy-microhei.ttc", + "/usr/share/fonts/wqy-zenhei/wqy-zenhei.ttc", + "C:/Windows/Fonts/msyh.ttc", + "C:/Windows/Fonts/simhei.ttf",) + """字体文件路径列表""" + + @model_validator(mode="before") + @classmethod + def load_token_aliases(cls, values): + """兼容 NoneBot 配置和环境变量中的 QQPush Token 命名。""" + if not isinstance(values, dict): + return values + + token = ( + values.get("Token") + or values.get("token") + or values.get("DANDING_QQPUSH_TOKEN") + or values.get("danding_qqpush_token") + or os.getenv("DANDING_QQPUSH_TOKEN") + ) + if token: + values["Token"] = token + return values diff --git a/tests/test_danding_qqpush_config.py b/tests/test_danding_qqpush_config.py new file mode 100644 index 0000000..f95f322 --- /dev/null +++ b/tests/test_danding_qqpush_config.py @@ -0,0 +1,35 @@ +import importlib.util +from pathlib import Path + + +def load_config_class(): + config_path = Path(__file__).resolve().parents[1] / "danding_bot" / "plugins" / "danding_qqpush" / "config.py" + spec = importlib.util.spec_from_file_location("danding_qqpush_config", config_path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module.Config + + +def test_qqpush_config_reads_nonebot_lowercase_token(): + Config = load_config_class() + config = Config.model_validate({"danding_qqpush_token": "token-from-nonebot"}) + + assert config.Token == "token-from-nonebot" + + +def test_qqpush_config_reads_env_token(monkeypatch): + Config = load_config_class() + monkeypatch.setenv("DANDING_QQPUSH_TOKEN", "token-from-env") + + config = Config.model_validate({}) + + assert config.Token == "token-from-env" + + +def test_qqpush_config_has_documented_default_token(monkeypatch): + Config = load_config_class() + monkeypatch.delenv("DANDING_QQPUSH_TOKEN", raising=False) + + config = Config.model_validate({}) + + assert config.Token == "danding-8HkL9xQ2"