fix(security): lock down inbound DMs by default
This commit is contained in:
@@ -16,6 +16,10 @@ import {
|
||||
import { resolveStorePath, updateLastRoute } from "../config/sessions.js";
|
||||
import { danger, logVerbose, shouldLogVerbose } from "../globals.js";
|
||||
import { mediaKindFromMime } from "../media/constants.js";
|
||||
import {
|
||||
readProviderAllowFromStore,
|
||||
upsertProviderPairingRequest,
|
||||
} from "../pairing/pairing-store.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { createIMessageRpcClient } from "./client.js";
|
||||
import { sendMessageIMessage } from "./send.js";
|
||||
@@ -130,6 +134,7 @@ export async function monitorIMessageProvider(
|
||||
const allowFrom = resolveAllowFrom(opts);
|
||||
const groupAllowFrom = resolveGroupAllowFrom(opts);
|
||||
const groupPolicy = cfg.imessage?.groupPolicy ?? "open";
|
||||
const dmPolicy = cfg.imessage?.dmPolicy ?? "pairing";
|
||||
const mentionRegexes = buildMentionRegexes(cfg);
|
||||
const includeAttachments =
|
||||
opts.includeAttachments ?? cfg.imessage?.includeAttachments ?? false;
|
||||
@@ -153,20 +158,34 @@ export async function monitorIMessageProvider(
|
||||
if (isGroup && !chatId) return;
|
||||
|
||||
const groupId = isGroup ? String(chatId) : undefined;
|
||||
const storeAllowFrom = await readProviderAllowFromStore("imessage").catch(
|
||||
() => [],
|
||||
);
|
||||
const effectiveDmAllowFrom = Array.from(
|
||||
new Set([...allowFrom, ...storeAllowFrom]),
|
||||
)
|
||||
.map((v) => String(v).trim())
|
||||
.filter(Boolean);
|
||||
const effectiveGroupAllowFrom = Array.from(
|
||||
new Set([...groupAllowFrom, ...storeAllowFrom]),
|
||||
)
|
||||
.map((v) => String(v).trim())
|
||||
.filter(Boolean);
|
||||
|
||||
if (isGroup) {
|
||||
if (groupPolicy === "disabled") {
|
||||
logVerbose("Blocked iMessage group message (groupPolicy: disabled)");
|
||||
return;
|
||||
}
|
||||
if (groupPolicy === "allowlist") {
|
||||
if (groupAllowFrom.length === 0) {
|
||||
if (effectiveGroupAllowFrom.length === 0) {
|
||||
logVerbose(
|
||||
"Blocked iMessage group message (groupPolicy: allowlist, no groupAllowFrom)",
|
||||
);
|
||||
return;
|
||||
}
|
||||
const allowed = isAllowedIMessageSender({
|
||||
allowFrom: groupAllowFrom,
|
||||
allowFrom: effectiveGroupAllowFrom,
|
||||
sender,
|
||||
chatId: chatId ?? undefined,
|
||||
chatGuid,
|
||||
@@ -192,16 +211,64 @@ export async function monitorIMessageProvider(
|
||||
}
|
||||
}
|
||||
|
||||
const dmAuthorized = isAllowedIMessageSender({
|
||||
allowFrom,
|
||||
sender,
|
||||
chatId: chatId ?? undefined,
|
||||
chatGuid,
|
||||
chatIdentifier,
|
||||
});
|
||||
if (!isGroup && !dmAuthorized) {
|
||||
logVerbose(`Blocked iMessage sender ${sender} (not in allowFrom)`);
|
||||
return;
|
||||
const dmHasWildcard = effectiveDmAllowFrom.includes("*");
|
||||
const dmAuthorized =
|
||||
dmPolicy === "open"
|
||||
? true
|
||||
: dmHasWildcard ||
|
||||
(effectiveDmAllowFrom.length > 0 &&
|
||||
isAllowedIMessageSender({
|
||||
allowFrom: effectiveDmAllowFrom,
|
||||
sender,
|
||||
chatId: chatId ?? undefined,
|
||||
chatGuid,
|
||||
chatIdentifier,
|
||||
}));
|
||||
if (!isGroup) {
|
||||
if (dmPolicy === "disabled") return;
|
||||
if (!dmAuthorized) {
|
||||
if (dmPolicy === "pairing") {
|
||||
const senderId = normalizeIMessageHandle(sender);
|
||||
const { code } = await upsertProviderPairingRequest({
|
||||
provider: "imessage",
|
||||
id: senderId,
|
||||
meta: {
|
||||
sender: senderId,
|
||||
chatId: chatId ? String(chatId) : undefined,
|
||||
},
|
||||
});
|
||||
logVerbose(
|
||||
`imessage pairing request sender=${senderId} code=${code}`,
|
||||
);
|
||||
try {
|
||||
await sendMessageIMessage(
|
||||
sender,
|
||||
[
|
||||
"Clawdbot: access not configured.",
|
||||
"",
|
||||
`Pairing code: ${code}`,
|
||||
"",
|
||||
"Ask the bot owner to approve with:",
|
||||
"clawdbot pairing approve --provider imessage <code>",
|
||||
].join("\n"),
|
||||
{
|
||||
client,
|
||||
maxBytes: mediaMaxBytes,
|
||||
...(chatId ? { chatId } : {}),
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
logVerbose(
|
||||
`imessage pairing reply failed for ${senderId}: ${String(err)}`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
logVerbose(
|
||||
`Blocked iMessage sender ${sender} (dmPolicy=${dmPolicy})`,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const messageText = (message.text ?? "").trim();
|
||||
@@ -217,9 +284,9 @@ export async function monitorIMessageProvider(
|
||||
});
|
||||
const canDetectMention = mentionRegexes.length > 0;
|
||||
const commandAuthorized = isGroup
|
||||
? groupAllowFrom.length > 0
|
||||
? effectiveGroupAllowFrom.length > 0
|
||||
? isAllowedIMessageSender({
|
||||
allowFrom: groupAllowFrom,
|
||||
allowFrom: effectiveGroupAllowFrom,
|
||||
sender,
|
||||
chatId: chatId ?? undefined,
|
||||
chatGuid,
|
||||
|
||||
Reference in New Issue
Block a user