Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 34 additions & 9 deletions gateway/platforms/qqbot/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
app_id: "your-app-id" # or QQ_APP_ID env var
client_secret: "your-secret" # or QQ_CLIENT_SECRET env var
markdown_support: true # enable QQ markdown (msg_type 2)
dm_policy: "open" # open | allowlist | disabled
dm_policy: "pairing" # open | allowlist | disabled | pairing
allow_from: ["openid_1"]
group_policy: "open" # open | allowlist | disabled
group_policy: "pairing" # open | allowlist | disabled | pairing
group_allow_from: ["group_openid_1"]
stt: # Voice-to-text config (optional)
provider: "zai" # zai (GLM-ASR), openai (Whisper), etc.
Expand Down Expand Up @@ -208,11 +208,11 @@ def __init__(self, config: PlatformConfig):
self._markdown_support = bool(extra.get("markdown_support", True))

# Auth/ACL policies
self._dm_policy = str(extra.get("dm_policy", "open")).strip().lower()
self._dm_policy = str(extra.get("dm_policy", "pairing")).strip().lower()
self._allow_from = _coerce_list(
extra.get("allow_from") or extra.get("allowFrom")
)
self._group_policy = str(extra.get("group_policy", "open")).strip().lower()
self._group_policy = str(extra.get("group_policy", "pairing")).strip().lower()
self._group_allow_from = _coerce_list(
extra.get("group_allow_from") or extra.get("groupAllowFrom")
)
Expand Down Expand Up @@ -278,7 +278,7 @@ def enforces_own_access_policy(self) -> bool:
# Connection lifecycle
# ------------------------------------------------------------------

async def connect(self) -> bool:
async def connect(self, *, is_reconnect: bool = False) -> bool:
"""Authenticate, obtain gateway URL, and open the WebSocket."""
if not AIOHTTP_AVAILABLE:
message = "QQ startup failed: aiohttp not installed"
Expand Down Expand Up @@ -1214,7 +1214,7 @@ async def _handle_c2c_message(
user_openid = str(author.get("user_openid", ""))
if not user_openid:
return
if not self._is_dm_allowed(user_openid):
if not self._is_dm_intake_allowed(user_openid):
return

text = content
Expand Down Expand Up @@ -1454,7 +1454,7 @@ async def _handle_dm_message(
# Without this check any member of any guild the bot is in could
# bypass the configured allowlist via direct messages.
author_id = str(author.get("id", ""))
if not self._is_dm_allowed(author_id):
if not self._is_dm_intake_allowed(author_id):
logger.debug(
"[%s] Guild DM blocked by ACL: guild=%s user=%s",
self._log_tag, guild_id, author_id,
Expand Down Expand Up @@ -3142,19 +3142,44 @@ def _strip_at_mention(content: str) -> str:
stripped = re.sub(r"^@\S+\s*", "", content.strip())
return stripped

def _open_dm_opted_in(self) -> bool:
if os.getenv("GATEWAY_ALLOW_ALL_USERS", "").lower() in {"true", "1", "yes"}:
return True
return os.getenv("QQ_ALLOW_ALL_USERS", "").lower() in {"true", "1", "yes"}

def _is_dm_allowed(self, user_id: str) -> bool:
if self._dm_policy == "disabled":
return False
if self._dm_policy == "allowlist":
return self._entry_matches(self._allow_from, user_id)
return True
if self._dm_policy == "open":
return self._open_dm_opted_in()
return False

def _is_dm_intake_allowed(self, user_id: str) -> bool:
principal = str(user_id or "").strip()
if not principal:
return False
if self._dm_policy == "disabled":
return False
if self._dm_policy == "allowlist":
return self._entry_matches(self._allow_from, principal)
if self._dm_policy == "pairing":
return True
if self._dm_policy == "open":
return self._open_dm_opted_in()
return False

def _is_group_allowed(self, group_id: str, user_id: str) -> bool:
if self._group_policy == "disabled":
return False
if self._group_policy == "allowlist":
return self._entry_matches(self._group_allow_from, group_id)
return True
if self._group_policy == "pairing":
return False
if self._group_policy == "open":
return True
return False

@staticmethod
def _entry_matches(entries: List[str], target: str) -> bool:
Expand Down
Loading