import re SIGNAL_PREFIX = re.compile(r"^signal:", re.IGNORECASE) GROUP_PREFIX = re.compile(r"^group:", re.IGNORECASE) UUID_PREFIX = re.compile(r"^uuid:", re.IGNORECASE) USERNAME_PREFIX = re.compile(r"^u:", re.IGNORECASE) RECIPIENT_PATTERN = re.compile(r"^\+?\d{7,15}$") def normalize_signal_target(raw: str) -> str | None: if not raw: return None raw = raw.strip() lowered = raw.lower() if lowered.startswith("signal:group:"): return "group:" + raw[len("signal:group:") :] if lowered.startswith("signal:"): inner = raw[len("signal:") :] if inner.lower().startswith("group:"): return inner return _normalize_recipient(inner) if lowered.startswith("group:"): return raw if lowered.startswith("u:") and not lowered.startswith("uuid:"): return "username:" + raw[len("u:") :] if lowered.startswith("username:"): return raw if lowered.startswith("uuid:"): return _normalize_uuid(raw[len("uuid:") :]) if RECIPIENT_PATTERN.match(raw): return _normalize_recipient(raw) return raw def parse_signal_target(raw: str) -> tuple[str, str] | None: """θΏ”ε›ž (kind, value) ζˆ– None; kind ∈ {recipient, groupId, username}""" normalized = normalize_signal_target(raw) if not normalized: return None lowered = normalized.lower() if lowered.startswith("group:"): return ("groupId", normalized[len("group:") :]) if lowered.startswith("username:"): return ("username", normalized[len("username:") :]) return ("recipient", normalized) def _normalize_recipient(value: str) -> str: value = value.strip() if not value.startswith("+"): return f"+{value}" return value def _normalize_uuid(value: str) -> str: return value.strip().replace("-", "").lower()