diff --git a/docs/api/adapters/README.md b/docs/api/adapters/README.md index 172e87a4..05fe3b49 100644 --- a/docs/api/adapters/README.md +++ b/docs/api/adapters/README.md @@ -93,7 +93,7 @@ Adapter 类型 * `headers: dict`: 请求头 - * `body: Optional[dict]`: 请求数据,WebSocket 连接该部分为空 + * `body: Optional[bytes]`: 请求数据,WebSocket 连接该部分为 None diff --git a/docs/api/adapters/ding.md b/docs/api/adapters/ding.md index 7bb07c8a..7cfe5932 100644 --- a/docs/api/adapters/ding.md +++ b/docs/api/adapters/ding.md @@ -150,7 +150,7 @@ sidebarDepth: 0 -### _async_ `send(event, message, at_sender=False, **kwargs)` +### _async_ `send(event, message, at_sender=False, webhook=None, secret=None, **kwargs)` * **说明** @@ -171,6 +171,12 @@ sidebarDepth: 0 * `at_sender: bool`: 是否 @ 事件主体 + * `webhook: Optional[str]`: 该条消息将调用的 webhook 地址。不传则将使用 sessionWebhook,若其也不存在,该条消息不发送,使用自定义 webhook 时注意你设置的安全方式,如加关键词,IP地址,加签等等。 + + + * `secret: Optional[str]`: 如果你使用自定义的 webhook 地址,推荐使用加签方式对消息进行验证,将 机器人安全设置页面,加签一栏下面显示的SEC开头的字符串 传入这个参数即可。 + + * `**kwargs`: 覆盖默认参数 diff --git a/docs/api/matcher.md b/docs/api/matcher.md index 509ab6e9..0683c8f9 100644 --- a/docs/api/matcher.md +++ b/docs/api/matcher.md @@ -7,7 +7,7 @@ sidebarDepth: 0 ## 事件响应器 -该模块实现事件响应器的创建与运行,并提供一些快捷方法来帮助用户更好的与机器人进行 对话 。 +该模块实现事件响应器的创建与运行,并提供一些快捷方法来帮助用户更好的与机器人进行对话 。 ## `matchers` @@ -202,7 +202,7 @@ sidebarDepth: 0 * **类型** - `Optional[T_ArgsParser]` + `Optional[T_TypeUpdater]` @@ -217,7 +217,7 @@ sidebarDepth: 0 * **类型** - `Optional[T_ArgsParser]` + `Optional[T_PermissionUpdater]` @@ -237,7 +237,7 @@ sidebarDepth: 0 * **类型** - `List[T_Handler]` + `List[Handler]` diff --git a/docs/api/plugin.md b/docs/api/plugin.md index a924bb6b..cc785f1f 100644 --- a/docs/api/plugin.md +++ b/docs/api/plugin.md @@ -121,7 +121,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -162,7 +162,7 @@ def something_else(): * `rule: Optional[Union[Rule, T_RuleChecker]]`: 事件响应规则 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -206,7 +206,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -247,7 +247,7 @@ def something_else(): * `rule: Optional[Union[Rule, T_RuleChecker]]`: 事件响应规则 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -288,7 +288,7 @@ def something_else(): * `rule: Optional[Union[Rule, T_RuleChecker]]`: 事件响应规则 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -335,7 +335,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -382,7 +382,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -429,7 +429,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -481,7 +481,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -538,7 +538,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -590,7 +590,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -767,7 +767,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -808,7 +808,7 @@ def something_else(): * `rule: Optional[Union[Rule, T_RuleChecker]]`: 事件响应规则 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -852,7 +852,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -893,7 +893,7 @@ def something_else(): * `rule: Optional[Union[Rule, T_RuleChecker]]`: 事件响应规则 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -934,7 +934,7 @@ def something_else(): * `rule: Optional[Union[Rule, T_RuleChecker]]`: 事件响应规则 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -981,7 +981,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -1028,7 +1028,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -1075,7 +1075,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -1127,7 +1127,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -1184,7 +1184,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) @@ -1236,7 +1236,7 @@ def something_else(): * `permission: Optional[Permission]`: 事件响应权限 - * `handlers: Optional[List[T_Handler]]`: 事件处理函数列表 + * `handlers: Optional[List[Union[T_Handler, Handler]]]`: 事件处理函数列表 * `temp: bool`: 是否为临时事件响应器(仅执行一次) diff --git a/nonebot/adapters/_base.py b/nonebot/adapters/_base.py index effef2ff..dc2d663a 100644 --- a/nonebot/adapters/_base.py +++ b/nonebot/adapters/_base.py @@ -72,7 +72,7 @@ class Bot(abc.ABC): @classmethod @abc.abstractmethod async def check_permission(cls, driver: "Driver", connection_type: str, - headers: dict, body: Optional[dict]) -> str: + headers: dict, body: Optional[bytes]) -> str: """ :说明: @@ -83,7 +83,7 @@ class Bot(abc.ABC): * ``driver: Driver``: Driver 对象 * ``connection_type: str``: 连接类型 * ``headers: dict``: 请求头 - * ``body: Optional[dict]``: 请求数据,WebSocket 连接该部分为空 + * ``body: Optional[bytes]``: 请求数据,WebSocket 连接该部分为 None :返回: diff --git a/nonebot/drivers/fastapi.py b/nonebot/drivers/fastapi.py index d83fc762..18a5f1db 100644 --- a/nonebot/drivers/fastapi.py +++ b/nonebot/drivers/fastapi.py @@ -16,7 +16,7 @@ from typing import List, Optional, Callable import uvicorn from pydantic import BaseSettings from fastapi.responses import Response -from fastapi import Body, status, Request, FastAPI, HTTPException +from fastapi import status, Request, FastAPI, HTTPException from starlette.websockets import WebSocketDisconnect, WebSocket as FastAPIWebSocket from nonebot.log import logger @@ -177,11 +177,11 @@ class Driver(BaseDriver): **kwargs) @overrides(BaseDriver) - async def _handle_http(self, - adapter: str, - request: Request, - data: dict = Body(...)): - if not isinstance(data, dict): + async def _handle_http(self, adapter: str, request: Request): + data = await request.body() + data_dict = json.loads(data.decode()) + + if not isinstance(data_dict, dict): logger.warning("Data received is invalid") raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST) @@ -208,7 +208,7 @@ class Driver(BaseDriver): bot = BotClass("http", x_self_id) - asyncio.create_task(bot.handle_message(data)) + asyncio.create_task(bot.handle_message(data_dict)) return Response("", 204) @overrides(BaseDriver) diff --git a/packages/nonebot-adapter-cqhttp/nonebot/adapters/cqhttp/bot.py b/packages/nonebot-adapter-cqhttp/nonebot/adapters/cqhttp/bot.py index 3d440127..ca477559 100644 --- a/packages/nonebot-adapter-cqhttp/nonebot/adapters/cqhttp/bot.py +++ b/packages/nonebot-adapter-cqhttp/nonebot/adapters/cqhttp/bot.py @@ -244,7 +244,7 @@ class Bot(BaseBot): @classmethod @overrides(BaseBot) async def check_permission(cls, driver: "Driver", connection_type: str, - headers: dict, body: Optional[dict]) -> str: + headers: dict, body: Optional[bytes]) -> str: """ :说明: @@ -271,14 +271,13 @@ class Bot(BaseBot): if not x_signature: log("WARNING", "Missing Signature Header") raise RequestDenied(401, "Missing Signature") - sig = hmac.new(secret.encode("utf-8"), - json.dumps(body).encode(), "sha1").hexdigest() + sig = hmac.new(secret.encode("utf-8"), body, "sha1").hexdigest() if x_signature != "sha1=" + sig: log("WARNING", "Signature Header is invalid") raise RequestDenied(403, "Signature is invalid") access_token = cqhttp_config.access_token - if access_token and access_token != token: + if access_token and access_token != token and connection_type == "websocket": log( "WARNING", "Authorization Header is invalid" if token else "Missing Authorization Header") diff --git a/packages/nonebot-adapter-ding/nonebot/adapters/ding/bot.py b/packages/nonebot-adapter-ding/nonebot/adapters/ding/bot.py index db2e77d3..08175ce4 100644 --- a/packages/nonebot-adapter-ding/nonebot/adapters/ding/bot.py +++ b/packages/nonebot-adapter-ding/nonebot/adapters/ding/bot.py @@ -1,5 +1,4 @@ -import hmac -import base64 +import json import urllib.parse from datetime import datetime @@ -51,7 +50,7 @@ class Bot(BaseBot): @classmethod @overrides(BaseBot) async def check_permission(cls, driver: "Driver", connection_type: str, - headers: dict, body: Optional[dict]) -> str: + headers: dict, body: Optional[bytes]) -> str: """ :说明: @@ -81,7 +80,7 @@ class Bot(BaseBot): raise RequestDenied(403, "Signature is invalid") else: log("WARNING", "Ding signature check ignored!") - return body["chatbotUserId"] + return json.loads(body.decode())["chatbotUserId"] @overrides(BaseBot) async def handle_message(self, message: dict): diff --git a/packages/nonebot-adapter-ding/nonebot/adapters/ding/utils.py b/packages/nonebot-adapter-ding/nonebot/adapters/ding/utils.py index 13be81d0..5529d42b 100644 --- a/packages/nonebot-adapter-ding/nonebot/adapters/ding/utils.py +++ b/packages/nonebot-adapter-ding/nonebot/adapters/ding/utils.py @@ -1,7 +1,9 @@ import hmac -from nonebot.utils import logger_wrapper -import hashlib import base64 +import hashlib + +from nonebot.utils import logger_wrapper + log = logger_wrapper("DING") diff --git a/packages/nonebot-adapter-mirai/nonebot/adapters/mirai/bot.py b/packages/nonebot-adapter-mirai/nonebot/adapters/mirai/bot.py index 4f5cb196..1b598ebf 100644 --- a/packages/nonebot-adapter-mirai/nonebot/adapters/mirai/bot.py +++ b/packages/nonebot-adapter-mirai/nonebot/adapters/mirai/bot.py @@ -178,7 +178,7 @@ class Bot(BaseBot): @classmethod @overrides(BaseBot) async def check_permission(cls, driver: "Driver", connection_type: str, - headers: dict, body: Optional[dict]) -> str: + headers: dict, body: Optional[bytes]) -> str: if connection_type == 'ws': raise RequestDenied( status_code=501, @@ -224,7 +224,7 @@ class Bot(BaseBot): \:\:\: danger 由于Mirai的HTTP API特殊性, 该API暂时无法实现 \:\:\: - + \:\:\: tip 你可以使用 ``MiraiBot.api`` 中提供的调用方法来代替 \:\:\: @@ -447,7 +447,7 @@ class Bot(BaseBot): :说明: 使用此方法获取bot接收到的最老消息和最老各类事件 - (不会从MiraiApiHttp消息记录中删除) + (不会从MiraiApiHttp消息记录中删除) :参数: @@ -462,7 +462,7 @@ class Bot(BaseBot): 使用此方法获取bot接收到的最新消息和最新各类事件 (不会从MiraiApiHttp消息记录中删除) - + :参数: * ``count: int``: 获取消息和事件的数量 @@ -599,7 +599,7 @@ class Bot(BaseBot): """ :说明: - 使用此方法使Bot退出群聊 + 使用此方法使Bot退出群聊 :参数: diff --git a/packages/nonebot-adapter-mirai/nonebot/adapters/mirai/bot_ws.py b/packages/nonebot-adapter-mirai/nonebot/adapters/mirai/bot_ws.py index 9dabe356..7f990183 100644 --- a/packages/nonebot-adapter-mirai/nonebot/adapters/mirai/bot_ws.py +++ b/packages/nonebot-adapter-mirai/nonebot/adapters/mirai/bot_ws.py @@ -116,7 +116,8 @@ class WebsocketBot(Bot): @classmethod @overrides(Bot) async def check_permission(cls, driver: "Driver", connection_type: str, - headers: dict, body: Optional[dict]) -> NoReturn: + headers: dict, + body: Optional[bytes]) -> NoReturn: raise RequestDenied( status_code=501, reason=f'Connection {connection_type} not implented') @@ -127,7 +128,7 @@ class WebsocketBot(Bot): """ :说明: - 注册该Adapter + 注册该Adapter :参数: diff --git a/poetry.lock b/poetry.lock index d33bbbc2..41f617f8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -235,7 +235,7 @@ reference = "aliyun" [[package]] name = "httpx" -version = "0.17.0" +version = "0.17.1" description = "The next generation HTTP client." category = "dev" optional = false @@ -243,7 +243,7 @@ python-versions = ">=3.6" [package.dependencies] certifi = "*" -httpcore = ">=0.12.0,<0.13.0" +httpcore = ">=0.12.1,<0.13" rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} sniffio = "*" @@ -807,7 +807,7 @@ yapf = "*" [package.source] type = "git" -url = "git@github.com:nonebot/sphinx-markdown-builder.git" +url = "https://github.com/nonebot/sphinx-markdown-builder.git" reference = "master" resolved_reference = "fdbc39e1b50aabf8dbcf129895fbbd02cbf54554" @@ -998,16 +998,16 @@ reference = "aliyun" [[package]] name = "urllib3" -version = "1.26.3" +version = "1.26.4" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" [package.extras] -brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotlipy (>=0.6.0)"] [package.source] type = "legacy" @@ -1155,7 +1155,7 @@ quart = ["Quart"] [metadata] lock-version = "1.1" python-versions = "^3.7.3" -content-hash = "51c469a7330ef3dc06805b771670f2c1526ebfc6e50d7c22571ae3ffc7b0f352" +content-hash = "9907ba758206e19d2c36493252f8b026db796ff4dbc67142824d86da31763919" [metadata.files] aiofiles = [ @@ -1232,8 +1232,8 @@ httptools = [ {file = "httptools-0.1.1.tar.gz", hash = "sha256:41b573cf33f64a8f8f3400d0a7faf48e1888582b6f6e02b82b9bd4f0bf7497ce"}, ] httpx = [ - {file = "httpx-0.17.0-py3-none-any.whl", hash = "sha256:fe19522f7b0861a1f6ac83306360bb5b7fb1ed64633a1a04a33f04102a1bea60"}, - {file = "httpx-0.17.0.tar.gz", hash = "sha256:4f7ab2fef7f929c5531abd4f413b41ce2c820e3202f2eeee498f2d92b6849f8d"}, + {file = "httpx-0.17.1-py3-none-any.whl", hash = "sha256:d379653bd457e8257eb0df99cb94557e4aac441b7ba948e333be969298cac272"}, + {file = "httpx-0.17.1.tar.gz", hash = "sha256:cc2a55188e4b25272d2bcd46379d300f632045de4377682aa98a8a6069d55967"}, ] hypercorn = [ {file = "Hypercorn-0.11.2-py3-none-any.whl", hash = "sha256:8007c10f81566920f8ae12c0e26e146f94ca70506da964b5a727ad610aa1d821"}, @@ -1487,8 +1487,8 @@ untokenize = [ {file = "untokenize-0.1.1.tar.gz", hash = "md5:50d325dff09208c624cc603fad33bb0d"}, ] urllib3 = [ - {file = "urllib3-1.26.3-py2.py3-none-any.whl", hash = "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80"}, - {file = "urllib3-1.26.3.tar.gz", hash = "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"}, + {file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"}, + {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"}, ] uvicorn = [ {file = "uvicorn-0.13.4-py3-none-any.whl", hash = "sha256:7587f7b08bd1efd2b9bad809a3d333e972f1d11af8a5e52a9371ee3a5de71524"}, diff --git a/pyproject.toml b/pyproject.toml index 283b7927..11ec5be4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ nonebot-plugin-test = "^0.2.0" nonebot-adapter-cqhttp = { path = "./packages/nonebot-adapter-cqhttp", develop = true } nonebot-adapter-ding = { path = "./packages/nonebot-adapter-ding", develop = true } nonebot-adapter-mirai = { path = "./packages/nonebot-adapter-mirai", develop = true } -sphinx-markdown-builder = { git = "git@github.com:nonebot/sphinx-markdown-builder.git" } +sphinx-markdown-builder = { git = "https://github.com/nonebot/sphinx-markdown-builder.git" } [tool.poetry.extras] quart = ["quart"]