mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-06-13 22:34:06 +00:00
fix(qq): send pairing codes for unauthorized C2C users
This commit is contained in:
parent
facdc41a16
commit
7c3808327f
@ -490,14 +490,24 @@ class QQChannel(BaseChannel):
|
|||||||
|
|
||||||
content = (data.content or "").strip()
|
content = (data.content or "").strip()
|
||||||
|
|
||||||
if not self.is_allowed(user_id):
|
|
||||||
return
|
|
||||||
|
|
||||||
if data.id in self._processed_ids:
|
if data.id in self._processed_ids:
|
||||||
return
|
return
|
||||||
self._processed_ids.append(data.id)
|
self._processed_ids.append(data.id)
|
||||||
self._chat_type_cache[chat_id] = chat_type
|
self._chat_type_cache[chat_id] = chat_type
|
||||||
|
|
||||||
|
# Early permission check — avoid attachment downloads and ack side effects
|
||||||
|
# for unauthorized users. C2C messages can receive pairing codes;
|
||||||
|
# group messages remain silently ignored.
|
||||||
|
if not self.is_allowed(user_id):
|
||||||
|
if not is_group:
|
||||||
|
await self._handle_message(
|
||||||
|
sender_id=user_id,
|
||||||
|
chat_id=chat_id,
|
||||||
|
content="",
|
||||||
|
is_dm=True,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
# the data used by tests don't contain attachments property
|
# the data used by tests don't contain attachments property
|
||||||
# so we use getattr with a default of [] to avoid AttributeError in tests
|
# so we use getattr with a default of [] to avoid AttributeError in tests
|
||||||
attachments = getattr(data, "attachments", None) or []
|
attachments = getattr(data, "attachments", None) or []
|
||||||
@ -538,6 +548,7 @@ class QQChannel(BaseChannel):
|
|||||||
"message_id": data.id,
|
"message_id": data.id,
|
||||||
"attachments": att_meta,
|
"attachments": att_meta,
|
||||||
},
|
},
|
||||||
|
is_dm=not is_group,
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.exception("Error handling inbound message id={}", getattr(data, "id", "?"))
|
self.logger.exception("Error handling inbound message id={}", getattr(data, "id", "?"))
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import tempfile
|
import tempfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -58,6 +58,51 @@ async def test_on_group_message_routes_to_group_chat_id() -> None:
|
|||||||
assert msg.chat_id == "group123"
|
assert msg.chat_id == "group123"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_on_c2c_message_passes_is_dm_true_to_base_handler() -> None:
|
||||||
|
channel = QQChannel(QQConfig(app_id="app", secret="secret", allow_from=["user1"]), MessageBus())
|
||||||
|
channel._handle_message = AsyncMock()
|
||||||
|
|
||||||
|
data = SimpleNamespace(
|
||||||
|
id="msg-c2c",
|
||||||
|
content="hello",
|
||||||
|
author=SimpleNamespace(user_openid="user1"),
|
||||||
|
attachments=[],
|
||||||
|
)
|
||||||
|
|
||||||
|
await channel._on_message(data, is_group=False)
|
||||||
|
|
||||||
|
channel._handle_message.assert_awaited_once()
|
||||||
|
kwargs = channel._handle_message.await_args.kwargs
|
||||||
|
assert kwargs["sender_id"] == "user1"
|
||||||
|
assert kwargs["chat_id"] == "user1"
|
||||||
|
assert kwargs["content"] == "hello"
|
||||||
|
assert kwargs["is_dm"] is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_on_group_message_passes_is_dm_false_to_base_handler() -> None:
|
||||||
|
channel = QQChannel(QQConfig(app_id="app", secret="secret", allow_from=["user1"]), MessageBus())
|
||||||
|
channel._handle_message = AsyncMock()
|
||||||
|
|
||||||
|
data = SimpleNamespace(
|
||||||
|
id="msg-group",
|
||||||
|
content="hello",
|
||||||
|
group_openid="group123",
|
||||||
|
author=SimpleNamespace(member_openid="user1"),
|
||||||
|
attachments=[],
|
||||||
|
)
|
||||||
|
|
||||||
|
await channel._on_message(data, is_group=True)
|
||||||
|
|
||||||
|
channel._handle_message.assert_awaited_once()
|
||||||
|
kwargs = channel._handle_message.await_args.kwargs
|
||||||
|
assert kwargs["sender_id"] == "user1"
|
||||||
|
assert kwargs["chat_id"] == "group123"
|
||||||
|
assert kwargs["content"] == "hello"
|
||||||
|
assert kwargs["is_dm"] is False
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_send_group_message_uses_plain_text_group_api_with_msg_seq() -> None:
|
async def test_send_group_message_uses_plain_text_group_api_with_msg_seq() -> None:
|
||||||
channel = QQChannel(QQConfig(app_id="app", secret="secret", allow_from=["*"]), MessageBus())
|
channel = QQChannel(QQConfig(app_id="app", secret="secret", allow_from=["*"]), MessageBus())
|
||||||
|
|||||||
@ -183,7 +183,7 @@ async def test_send_media_failure_falls_back_to_text() -> None:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_on_message_ignores_unauthorized_sender_before_attachments_and_ack() -> None:
|
async def test_on_message_unauthorized_c2c_pairs_before_attachments_and_ack() -> None:
|
||||||
channel = QQChannel(
|
channel = QQChannel(
|
||||||
QQConfig(
|
QQConfig(
|
||||||
app_id="app",
|
app_id="app",
|
||||||
@ -206,9 +206,45 @@ async def test_on_message_ignores_unauthorized_sender_before_attachments_and_ack
|
|||||||
|
|
||||||
await channel._on_message(data, is_group=False)
|
await channel._on_message(data, is_group=False)
|
||||||
|
|
||||||
|
channel._handle_attachments.assert_not_awaited()
|
||||||
|
channel._handle_message.assert_awaited_once_with(
|
||||||
|
sender_id="blocked-user",
|
||||||
|
chat_id="blocked-user",
|
||||||
|
content="",
|
||||||
|
is_dm=True,
|
||||||
|
)
|
||||||
|
assert channel._client.api.c2c_calls == []
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_on_message_ignores_unauthorized_group_before_attachments_and_ack() -> None:
|
||||||
|
channel = QQChannel(
|
||||||
|
QQConfig(
|
||||||
|
app_id="app",
|
||||||
|
secret="secret",
|
||||||
|
allow_from=["allowed-user"],
|
||||||
|
ack_message="Processing...",
|
||||||
|
),
|
||||||
|
MessageBus(),
|
||||||
|
)
|
||||||
|
channel._client = _FakeClient()
|
||||||
|
channel._handle_attachments = AsyncMock(return_value=(["/tmp/a.png"], ["file"], []))
|
||||||
|
channel._handle_message = AsyncMock()
|
||||||
|
|
||||||
|
data = SimpleNamespace(
|
||||||
|
id="msg-blocked-group",
|
||||||
|
content="hello",
|
||||||
|
group_openid="group123",
|
||||||
|
author=SimpleNamespace(member_openid="blocked-user"),
|
||||||
|
attachments=[SimpleNamespace(filename="a.png")],
|
||||||
|
)
|
||||||
|
|
||||||
|
await channel._on_message(data, is_group=True)
|
||||||
|
|
||||||
channel._handle_attachments.assert_not_awaited()
|
channel._handle_attachments.assert_not_awaited()
|
||||||
channel._handle_message.assert_not_awaited()
|
channel._handle_message.assert_not_awaited()
|
||||||
assert channel._client.api.c2c_calls == []
|
assert channel._client.api.c2c_calls == []
|
||||||
|
assert channel._client.api.group_calls == []
|
||||||
|
|
||||||
|
|
||||||
# ── _on_message() exception handling ────────────────────────────────
|
# ── _on_message() exception handling ────────────────────────────────
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user