该提交新增了基于BlueBubbles的iMessage渠道插件,支持单聊和群组消息,包含文本、图片、语音、文件和视频消息收发,支持消息编辑、撤回、回复、 reactions和输入状态提示,同时实现了账号配置、安全校验、配对授权、消息格式化与分片等完整功能。
112 lines
3.7 KiB
Python
112 lines
3.7 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class IMessageSecurityAdapter:
|
|
DM_POLICY_OPTIONS = ["pairing", "allowlist", "open", "disabled"]
|
|
GROUP_POLICY_OPTIONS = ["open", "allowlist", "disabled"]
|
|
|
|
def __init__(self, config_adapter=None):
|
|
self._config_adapter = config_adapter
|
|
|
|
def _get_channel_config(self, config: dict) -> dict:
|
|
if self._config_adapter:
|
|
return self._config_adapter._get_channel_config(config)
|
|
return config.get("channels", {}).get("imessage", {})
|
|
|
|
def resolve_dm_policy(self, config: dict | None = None) -> dict:
|
|
if config:
|
|
channel_config = self._get_channel_config(config)
|
|
return {
|
|
"mode": channel_config.get("dm_policy", "pairing"),
|
|
"allow_from": channel_config.get("allow_from", []),
|
|
}
|
|
return {"mode": "pairing", "allow_from": []}
|
|
|
|
async def check_allowlist(self, peer_id: str, channel_type: str, config: dict | None = None) -> bool:
|
|
if not config:
|
|
return False
|
|
|
|
channel_config = self._get_channel_config(config)
|
|
dm_policy = channel_config.get("dm_policy", "pairing")
|
|
|
|
if dm_policy == "open":
|
|
return True
|
|
if dm_policy == "disabled":
|
|
return False
|
|
|
|
allow_from = channel_config.get("allow_from", [])
|
|
if "*" in allow_from:
|
|
return True
|
|
if peer_id in allow_from:
|
|
return True
|
|
|
|
if dm_policy == "pairing":
|
|
return False
|
|
|
|
return False
|
|
|
|
def resolve_group_policy(self, config: dict | None = None) -> dict:
|
|
if config:
|
|
channel_config = self._get_channel_config(config)
|
|
return {
|
|
"mode": channel_config.get("group_policy", "allowlist"),
|
|
"group_allow_from": channel_config.get("group_allow_from", []),
|
|
}
|
|
return {"mode": "allowlist", "group_allow_from": []}
|
|
|
|
async def check_group_access(self, config: dict, chat_guid: str, sender_handle: str) -> bool:
|
|
channel_config = self._get_channel_config(config)
|
|
group_policy = channel_config.get("group_policy", "allowlist")
|
|
|
|
if group_policy == "open":
|
|
return True
|
|
if group_policy == "disabled":
|
|
return False
|
|
|
|
group_allow_from = channel_config.get("group_allow_from", [])
|
|
if sender_handle in group_allow_from:
|
|
return True
|
|
|
|
groups = channel_config.get("groups", {})
|
|
if chat_guid in groups:
|
|
return True
|
|
|
|
return False
|
|
|
|
def is_allowed_dm(self, peer_id: str, allow_from: list[str], policy: str) -> bool:
|
|
if policy == "open":
|
|
return True
|
|
if policy == "disabled":
|
|
return False
|
|
if policy == "allowlist":
|
|
return peer_id in allow_from or "*" in allow_from
|
|
if policy == "pairing":
|
|
return peer_id in allow_from
|
|
return False
|
|
|
|
def is_allowed_group(self, group_id: str, group_allow_from: list[str], policy: str) -> bool:
|
|
if policy == "open":
|
|
return True
|
|
if policy == "disabled":
|
|
return False
|
|
if policy == "allowlist":
|
|
return group_id in group_allow_from
|
|
return False
|
|
|
|
def is_valid_allow_entry(self, entry: str) -> bool:
|
|
if not entry or entry == "*":
|
|
return True
|
|
if "@" in entry:
|
|
return True
|
|
if entry.startswith("+"):
|
|
return True
|
|
if entry.startswith("chat_guid:"):
|
|
return len(entry) > len("chat_guid:")
|
|
if entry.startswith("chat_identifier:"):
|
|
return len(entry) > len("chat_identifier:")
|
|
return False
|