from __future__ import annotations import logging logger = logging.getLogger(__name__) class RocketChatSecurityAdapter: def resolve_dm_policy(self, account: dict) -> str: return account.get("dm_policy", "pairing") def resolve_group_policy(self, account: dict) -> str: return account.get("group_policy", "allowlist") def resolve_channel_policy(self, account: dict) -> str: return account.get("channel_policy", "allowlist") def is_sender_allowed( self, sender_id: str, allow_list: list[str], sender_name: str | None = None, ) -> bool: normalized = [normalize_allow_entry(e) for e in allow_list] if sender_id in normalized: return True if "*" in normalized: return True if sender_name: raw_entries = [str(e).strip() for e in allow_list] if f"@{sender_name}" in raw_entries or sender_name in raw_entries: return True return False def check_sender_access( self, chat_type: str, sender_id: str, account: dict, sender_name: str | None = None, ) -> tuple[bool, str]: if chat_type == "direct": return self._check_dm_access(sender_id, account, sender_name) if chat_type == "channel": return self._check_channel_access(sender_id, account, sender_name) return self._check_group_access(sender_id, account, sender_name) def _check_dm_access( self, sender_id: str, account: dict, sender_name: str | None = None, ) -> tuple[bool, str]: policy = self.resolve_dm_policy(account) if policy == "open": allow_from = account.get("allow_from", []) if "*" in [str(e).strip() for e in allow_from]: return True, "ok" return self._check_allowlist(sender_id, account, sender_name, "dm") if policy == "pairing": allow_from = account.get("allow_from", []) if self.is_sender_allowed(sender_id, allow_from, sender_name): return True, "ok" return False, "pairing_required" if policy == "allowlist": return self._check_allowlist(sender_id, account, sender_name, "dm") if policy == "disabled": return False, "dm_disabled" return False, "unknown_policy" def _check_group_access( self, sender_id: str, account: dict, sender_name: str | None = None, ) -> tuple[bool, str]: policy = self.resolve_group_policy(account) if policy == "open": return True, "ok" if policy == "allowlist": return self._check_allowlist(sender_id, account, sender_name, "group") if policy == "disabled": return False, "group_disabled" return False, "unknown_policy" def _check_channel_access( self, sender_id: str, account: dict, sender_name: str | None = None, ) -> tuple[bool, str]: policy = self.resolve_channel_policy(account) if policy == "open": return True, "ok" if policy == "allowlist": return self._check_allowlist(sender_id, account, sender_name, "channel") if policy == "disabled": return False, "channel_disabled" return False, "unknown_policy" def _check_allowlist( self, sender_id: str, account: dict, sender_name: str | None, scope: str, ) -> tuple[bool, str]: if scope == "group": allow_key = "group_allow_from" elif scope == "channel": allow_key = "channel_allow_from" else: allow_key = "allow_from" allow_list = account.get(allow_key, []) if not allow_list: allow_list = account.get("allow_from", []) if self.is_sender_allowed(sender_id, allow_list, sender_name): return True, "ok" return False, f"{scope}_not_allowed" def normalize_allow_entry(raw: str | int) -> str: entry = str(raw).strip() for prefix in ["rocketchat:", "user:", "@"]: if entry.startswith(prefix): entry = entry[len(prefix) :] return entry def normalize_allow_list(raw_entries: list[str | int]) -> list[str]: return [normalize_allow_entry(e) for e in raw_entries]