import logging logger = logging.getLogger("yuxi.channel.xmpp.security") def check_xmpp_allowlist(peer_id: str, allowlist: list[str]) -> bool: if not allowlist: return False if "*" in allowlist: return True bare = _extract_bare_jid(peer_id).lower() for entry in allowlist: if entry == "*": return True if _extract_bare_jid(entry).lower() == bare: return True return False def is_xmpp_mentioned(nick: str, body: str) -> bool: if not nick or not body: return False import re pattern = re.compile(rf"\b{re.escape(nick)}\b[:,\s]?", re.IGNORECASE) return bool(pattern.search(body)) def resolve_xmpp_dm_policy(account) -> str: return getattr(account, "dm_policy", "open") def resolve_xmpp_group_policy(account) -> str: return getattr(account, "group_policy", "open") def collect_xmpp_security_warnings(account) -> list[str]: warnings = [] if getattr(account, "dm_policy", "open") == "open": warnings.append("XMPP DM policy is 'open' — anyone can DM the bot") if getattr(account, "group_policy", "open") == "open": warnings.append("XMPP group policy is 'open' — any room can trigger bot replies") if not getattr(account, "password", ""): warnings.append("XMPP password is not configured") return warnings def _extract_bare_jid(jid: str) -> str: return jid.split("/")[0]