refactor(signal): normalize sender identity

This commit is contained in:
Peter Steinberger
2026-01-08 23:06:38 +00:00
parent 9e9f2babeb
commit 7c7858a519
7 changed files with 223 additions and 53 deletions

View File

@@ -19,6 +19,14 @@ import { normalizeE164 } from "../utils.js";
import { resolveSignalAccount } from "./accounts.js";
import { signalCheck, signalRpcRequest } from "./client.js";
import { spawnSignalDaemon } from "./daemon.js";
import {
formatSignalSenderDisplay,
formatSignalSenderId,
isSignalSenderAllowed,
resolveSignalPeerId,
resolveSignalRecipient,
resolveSignalSender,
} from "./identity.js";
import { sendMessageSignal } from "./send.js";
import { runSignalSseLoop } from "./sse-reconnect.js";
@@ -92,28 +100,6 @@ function normalizeAllowList(raw?: Array<string | number>): string[] {
return (raw ?? []).map((entry) => String(entry).trim()).filter(Boolean);
}
function isAllowedSender(sender: string, allowFrom: string[]): boolean {
if (allowFrom.length === 0) return false;
if (allowFrom.includes("*")) return true;
const normalizedAllow = allowFrom
.map((entry) => entry.replace(/^signal:/i, ""))
.map((entry) => normalizeE164(entry));
const normalizedSender = normalizeE164(sender);
return normalizedAllow.includes(normalizedSender);
}
export function isSignalGroupAllowed(params: {
groupPolicy: "open" | "disabled" | "allowlist";
allowFrom: string[];
sender: string;
}): boolean {
const { groupPolicy, allowFrom, sender } = params;
if (groupPolicy === "disabled") return false;
if (groupPolicy === "open") return true;
if (allowFrom.length === 0) return false;
return isAllowedSender(sender, allowFrom);
}
async function waitForSignalDaemonReady(params: {
baseUrl: string;
abortSignal?: AbortSignal;
@@ -320,11 +306,18 @@ export async function monitorSignalProvider(
envelope.dataMessage ?? envelope.editMessage?.dataMessage;
if (!dataMessage) return;
const sender = envelope.sourceNumber?.trim() || envelope.sourceUuid?.trim();
const sender = resolveSignalSender(envelope);
if (!sender) return;
if (account && envelope.sourceNumber && normalizeE164(envelope.sourceNumber) === normalizeE164(account)) {
return;
if (account && sender.kind === "phone") {
if (sender.e164 === normalizeE164(account)) {
return;
}
}
const senderDisplay = formatSignalSenderDisplay(sender);
const senderRecipient = resolveSignalRecipient(sender);
const senderPeerId = resolveSignalPeerId(sender);
const senderAllowId = formatSignalSenderId(sender);
if (!senderRecipient) return;
const groupId = dataMessage.groupInfo?.groupId ?? undefined;
const groupName = dataMessage.groupInfo?.groupName ?? undefined;
const isGroup = Boolean(groupId);
@@ -334,13 +327,15 @@ export async function monitorSignalProvider(
const effectiveDmAllow = [...allowFrom, ...storeAllowFrom];
const effectiveGroupAllow = [...groupAllowFrom, ...storeAllowFrom];
const dmAllowed =
dmPolicy === "open" ? true : isAllowedSender(sender, effectiveDmAllow);
dmPolicy === "open"
? true
: isSignalSenderAllowed(sender, effectiveDmAllow);
if (!isGroup) {
if (dmPolicy === "disabled") return;
if (!dmAllowed) {
if (dmPolicy === "pairing") {
const senderId = normalizeE164(sender);
const senderId = senderAllowId;
const { code, created } = await upsertProviderPairingRequest({
provider: "signal",
id: senderId,
@@ -352,7 +347,7 @@ export async function monitorSignalProvider(
logVerbose(`signal pairing request sender=${senderId}`);
try {
await sendMessageSignal(
senderId,
`signal:${senderRecipient}`,
[
"Clawdbot: access not configured.",
"",
@@ -376,7 +371,7 @@ export async function monitorSignalProvider(
}
} else {
logVerbose(
`Blocked signal sender ${sender} (dmPolicy=${dmPolicy})`,
`Blocked signal sender ${senderDisplay} (dmPolicy=${dmPolicy})`,
);
}
return;
@@ -393,9 +388,9 @@ export async function monitorSignalProvider(
);
return;
}
if (!isAllowedSender(sender, effectiveGroupAllow)) {
if (!isSignalSenderAllowed(sender, effectiveGroupAllow)) {
logVerbose(
`Blocked signal group sender ${sender} (not in groupAllowFrom)`,
`Blocked signal group sender ${senderDisplay} (not in groupAllowFrom)`,
);
return;
}
@@ -403,7 +398,7 @@ export async function monitorSignalProvider(
const commandAuthorized = isGroup
? effectiveGroupAllow.length > 0
? isAllowedSender(sender, effectiveGroupAllow)
? isSignalSenderAllowed(sender, effectiveGroupAllow)
: true
: dmAllowed;
const messageText = (dataMessage.message ?? "").trim();
@@ -418,7 +413,7 @@ export async function monitorSignalProvider(
baseUrl,
account,
attachment: firstAttachment,
sender,
sender: senderRecipient,
groupId,
maxBytes: mediaMaxBytes,
});
@@ -445,7 +440,7 @@ export async function monitorSignalProvider(
const fromLabel = isGroup
? `${groupName ?? "Signal Group"} id:${groupId}`
: `${envelope.sourceName ?? sender} id:${sender}`;
: `${envelope.sourceName ?? senderDisplay} id:${senderDisplay}`;
const body = formatAgentEnvelope({
provider: "Signal",
from: fromLabel,
@@ -459,20 +454,24 @@ export async function monitorSignalProvider(
accountId: accountInfo.accountId,
peer: {
kind: isGroup ? "group" : "dm",
id: isGroup ? (groupId ?? "unknown") : normalizeE164(sender),
id: isGroup ? (groupId ?? "unknown") : senderPeerId,
},
});
const signalTo = isGroup ? `group:${groupId}` : `signal:${sender}`;
const signalTo = isGroup
? `group:${groupId}`
: `signal:${senderRecipient}`;
const ctxPayload = {
Body: body,
From: isGroup ? `group:${groupId ?? "unknown"}` : `signal:${sender}`,
From: isGroup
? `group:${groupId ?? "unknown"}`
: `signal:${senderRecipient}`,
To: signalTo,
SessionKey: route.sessionKey,
AccountId: route.accountId,
ChatType: isGroup ? "group" : "direct",
GroupSubject: isGroup ? (groupName ?? undefined) : undefined,
SenderName: envelope.sourceName ?? sender,
SenderId: sender,
SenderName: envelope.sourceName ?? senderDisplay,
SenderId: senderDisplay,
Provider: "signal" as const,
Surface: "signal" as const,
MessageSid: envelope.timestamp ? String(envelope.timestamp) : undefined,
@@ -495,7 +494,7 @@ export async function monitorSignalProvider(
storePath,
sessionKey: route.mainSessionKey,
provider: "signal",
to: normalizeE164(sender),
to: senderRecipient,
accountId: route.accountId,
});
}