Spaces:
Running
Running
| import { normalizeE164 } from "../utils.js"; | |
| export type SignalSender = | |
| | { kind: "phone"; raw: string; e164: string } | |
| | { kind: "uuid"; raw: string }; | |
| type SignalAllowEntry = | |
| | { kind: "any" } | |
| | { kind: "phone"; e164: string } | |
| | { kind: "uuid"; raw: string }; | |
| const UUID_HYPHENATED_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; | |
| const UUID_COMPACT_RE = /^[0-9a-f]{32}$/i; | |
| function looksLikeUuid(value: string): boolean { | |
| if (UUID_HYPHENATED_RE.test(value) || UUID_COMPACT_RE.test(value)) { | |
| return true; | |
| } | |
| const compact = value.replace(/-/g, ""); | |
| if (!/^[0-9a-f]+$/i.test(compact)) { | |
| return false; | |
| } | |
| return /[a-f]/i.test(compact); | |
| } | |
| function stripSignalPrefix(value: string): string { | |
| return value.replace(/^signal:/i, "").trim(); | |
| } | |
| export function resolveSignalSender(params: { | |
| sourceNumber?: string | null; | |
| sourceUuid?: string | null; | |
| }): SignalSender | null { | |
| const sourceNumber = params.sourceNumber?.trim(); | |
| if (sourceNumber) { | |
| return { | |
| kind: "phone", | |
| raw: sourceNumber, | |
| e164: normalizeE164(sourceNumber), | |
| }; | |
| } | |
| const sourceUuid = params.sourceUuid?.trim(); | |
| if (sourceUuid) { | |
| return { kind: "uuid", raw: sourceUuid }; | |
| } | |
| return null; | |
| } | |
| export function formatSignalSenderId(sender: SignalSender): string { | |
| return sender.kind === "phone" ? sender.e164 : `uuid:${sender.raw}`; | |
| } | |
| export function formatSignalSenderDisplay(sender: SignalSender): string { | |
| return sender.kind === "phone" ? sender.e164 : `uuid:${sender.raw}`; | |
| } | |
| export function formatSignalPairingIdLine(sender: SignalSender): string { | |
| if (sender.kind === "phone") { | |
| return `Your Signal number: ${sender.e164}`; | |
| } | |
| return `Your Signal sender id: ${formatSignalSenderId(sender)}`; | |
| } | |
| export function resolveSignalRecipient(sender: SignalSender): string { | |
| return sender.kind === "phone" ? sender.e164 : sender.raw; | |
| } | |
| export function resolveSignalPeerId(sender: SignalSender): string { | |
| return sender.kind === "phone" ? sender.e164 : `uuid:${sender.raw}`; | |
| } | |
| function parseSignalAllowEntry(entry: string): SignalAllowEntry | null { | |
| const trimmed = entry.trim(); | |
| if (!trimmed) { | |
| return null; | |
| } | |
| if (trimmed === "*") { | |
| return { kind: "any" }; | |
| } | |
| const stripped = stripSignalPrefix(trimmed); | |
| const lower = stripped.toLowerCase(); | |
| if (lower.startsWith("uuid:")) { | |
| const raw = stripped.slice("uuid:".length).trim(); | |
| if (!raw) { | |
| return null; | |
| } | |
| return { kind: "uuid", raw }; | |
| } | |
| if (looksLikeUuid(stripped)) { | |
| return { kind: "uuid", raw: stripped }; | |
| } | |
| return { kind: "phone", e164: normalizeE164(stripped) }; | |
| } | |
| export function isSignalSenderAllowed(sender: SignalSender, allowFrom: string[]): boolean { | |
| if (allowFrom.length === 0) { | |
| return false; | |
| } | |
| const parsed = allowFrom | |
| .map(parseSignalAllowEntry) | |
| .filter((entry): entry is SignalAllowEntry => entry !== null); | |
| if (parsed.some((entry) => entry.kind === "any")) { | |
| return true; | |
| } | |
| return parsed.some((entry) => { | |
| if (entry.kind === "phone" && sender.kind === "phone") { | |
| return entry.e164 === sender.e164; | |
| } | |
| if (entry.kind === "uuid" && sender.kind === "uuid") { | |
| return entry.raw === sender.raw; | |
| } | |
| return false; | |
| }); | |
| } | |
| export function isSignalGroupAllowed(params: { | |
| groupPolicy: "open" | "disabled" | "allowlist"; | |
| allowFrom: string[]; | |
| sender: SignalSender; | |
| }): boolean { | |
| const { groupPolicy, allowFrom, sender } = params; | |
| if (groupPolicy === "disabled") { | |
| return false; | |
| } | |
| if (groupPolicy === "open") { | |
| return true; | |
| } | |
| if (allowFrom.length === 0) { | |
| return false; | |
| } | |
| return isSignalSenderAllowed(sender, allowFrom); | |
| } | |