新增 Signal 渠道扩展,支持在 Yuxi 平台中集成 Signal 加密即时通讯渠道。 包含以下功能模块: - client: Signal 客户端封装 - daemon: signald 守护进程管理 - config_schema: 配置模式 - send: 消息发送 - accounts: 账户管理 - account_management: 账户综合管理 - access_policy: 访问策略 - identity: 身份管理 - profiles: 用户资料 - groups: 群组管理 - format: 消息格式转换 - normalize: 消息规范化 - dedupe: 消息去重 - monitor: 渠道状态监控 - probe: 健康探测 - sse_reconnect: SSE 重连机制
94 lines
2.6 KiB
Python
94 lines
2.6 KiB
Python
import re
|
|
from dataclasses import dataclass
|
|
from typing import Literal
|
|
|
|
|
|
@dataclass
|
|
class SignalSenderPhone:
|
|
kind: Literal["phone"] = "phone"
|
|
raw: str = ""
|
|
e164: str = ""
|
|
|
|
|
|
@dataclass
|
|
class SignalSenderUuid:
|
|
kind: Literal["uuid"] = "uuid"
|
|
raw: str = ""
|
|
|
|
|
|
SignalSender = SignalSenderPhone | SignalSenderUuid
|
|
|
|
UUID_RE = re.compile(
|
|
r"^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$",
|
|
re.IGNORECASE,
|
|
)
|
|
|
|
|
|
def resolve_signal_sender(source_number: str | None, source_uuid: str | None) -> SignalSender | None:
|
|
if source_number:
|
|
return SignalSenderPhone(raw=source_number, e164=normalize_e164(source_number))
|
|
if source_uuid:
|
|
return SignalSenderUuid(raw=source_uuid)
|
|
return None
|
|
|
|
|
|
def normalize_e164(raw: str) -> str:
|
|
value = raw.strip()
|
|
if not value.startswith("+"):
|
|
return f"+{value}"
|
|
return value
|
|
|
|
|
|
def format_signal_sender_id(sender: SignalSender) -> str:
|
|
if isinstance(sender, SignalSenderUuid):
|
|
return f"uuid:{sender.raw}"
|
|
return sender.e164 or sender.raw
|
|
|
|
|
|
def format_signal_sender_display(sender: SignalSender) -> str:
|
|
return format_signal_sender_id(sender)
|
|
|
|
|
|
def format_signal_pairing_id_line(sender: SignalSender) -> str:
|
|
if isinstance(sender, SignalSenderUuid):
|
|
return f"Your Signal UUID: {sender.raw}"
|
|
return f"Your Signal number: {sender.e164 or sender.raw}"
|
|
|
|
|
|
def resolve_signal_recipient(sender: SignalSender) -> str:
|
|
if isinstance(sender, SignalSenderUuid):
|
|
return sender.raw
|
|
return sender.e164 or sender.raw
|
|
|
|
|
|
def resolve_signal_peer_id(sender: SignalSender) -> str:
|
|
return format_signal_sender_id(sender)
|
|
|
|
|
|
def match_signal_allow_entry(peer_id: str, allow_entry: str) -> bool:
|
|
if allow_entry == "*":
|
|
return True
|
|
|
|
lowered_entry = allow_entry.lower().strip()
|
|
|
|
if lowered_entry.startswith("uuid:"):
|
|
uuid_part = lowered_entry[len("uuid:") :].replace("-", "").lower()
|
|
peer_uuid = peer_id.replace("-", "").lower()
|
|
if peer_uuid.startswith("uuid:"):
|
|
peer_uuid = peer_uuid[len("uuid:") :]
|
|
return peer_uuid == uuid_part
|
|
|
|
peer_normalized = peer_id.strip()
|
|
if peer_normalized.startswith("signal:"):
|
|
peer_normalized = peer_normalized[len("signal:") :]
|
|
if not peer_normalized.startswith("+"):
|
|
peer_normalized = f"+{peer_normalized}"
|
|
|
|
entry_normalized = lowered_entry
|
|
if entry_normalized.startswith("signal:"):
|
|
entry_normalized = entry_normalized[len("signal:") :]
|
|
if not entry_normalized.startswith("+"):
|
|
entry_normalized = f"+{entry_normalized}"
|
|
|
|
return peer_normalized == entry_normalized
|