fix(whatsapp): allow media from allowlisted groups without groupAllowFrom

This commit is contained in:
Sarang19 2026-01-30 10:44:35 +05:30
parent 4de0bae45a
commit cddab06112
3 changed files with 247 additions and 22 deletions

View File

@ -0,0 +1,209 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { checkInboundAccessControl } from "./access-control.js";
const sendMessageMock = vi.fn();
const readAllowFromStoreMock = vi.fn();
const upsertPairingRequestMock = vi.fn();
let config: Record<string, unknown> = {};
vi.mock("../../config/config.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../config/config.js")>();
return {
...actual,
loadConfig: () => config,
};
});
vi.mock("../../pairing/pairing-store.js", () => ({
readChannelAllowFromStore: (...args: unknown[]) => readAllowFromStoreMock(...args),
upsertChannelPairingRequest: (...args: unknown[]) => upsertPairingRequestMock(...args),
}));
beforeEach(() => {
config = {
channels: {
whatsapp: {
dmPolicy: "allowlist",
allowFrom: ["+15550009999"],
groupPolicy: "allowlist",
},
},
};
sendMessageMock.mockReset().mockResolvedValue(undefined);
readAllowFromStoreMock.mockReset().mockResolvedValue([]);
upsertPairingRequestMock.mockReset().mockResolvedValue({ code: "PAIRCODE", created: true });
});
describe("checkInboundAccessControl group allowlist (#3375)", () => {
it("allows messages from any sender when group is in groups allowlist", async () => {
config = {
channels: {
whatsapp: {
dmPolicy: "allowlist",
allowFrom: ["+15550009999"],
groupPolicy: "allowlist",
groups: {
"123456789@g.us": { requireMention: false },
},
},
},
};
const result = await checkInboundAccessControl({
accountId: "default",
from: "123456789@g.us",
selfE164: "+15550009999",
senderE164: "+15550001111", // Sender NOT in allowFrom
group: true,
groupId: "123456789@g.us",
pushName: "Unknown User",
isFromMe: false,
sock: { sendMessage: sendMessageMock },
remoteJid: "123456789@g.us",
});
expect(result.allowed).toBe(true);
});
it("blocks messages when group is NOT in groups allowlist and sender NOT in groupAllowFrom", async () => {
config = {
channels: {
whatsapp: {
dmPolicy: "allowlist",
allowFrom: ["+15550009999"],
groupPolicy: "allowlist",
groupAllowFrom: ["+15550009999"],
// No groups config - so group is not in allowlist
},
},
};
const result = await checkInboundAccessControl({
accountId: "default",
from: "123456789@g.us",
selfE164: "+15550009999",
senderE164: "+15550001111", // Sender NOT in groupAllowFrom
group: true,
groupId: "123456789@g.us",
pushName: "Unknown User",
isFromMe: false,
sock: { sendMessage: sendMessageMock },
remoteJid: "123456789@g.us",
});
expect(result.allowed).toBe(false);
});
it("allows messages when sender is in groupAllowFrom even if group not in allowlist", async () => {
config = {
channels: {
whatsapp: {
dmPolicy: "allowlist",
allowFrom: ["+15550009999"],
groupPolicy: "allowlist",
groupAllowFrom: ["+15550001111"],
},
},
};
const result = await checkInboundAccessControl({
accountId: "default",
from: "123456789@g.us",
selfE164: "+15550009999",
senderE164: "+15550001111", // Sender IS in groupAllowFrom
group: true,
groupId: "123456789@g.us",
pushName: "Allowed User",
isFromMe: false,
sock: { sendMessage: sendMessageMock },
remoteJid: "123456789@g.us",
});
expect(result.allowed).toBe(true);
});
it("blocks all group messages when groupPolicy is disabled", async () => {
config = {
channels: {
whatsapp: {
dmPolicy: "allowlist",
allowFrom: ["+15550009999"],
groupPolicy: "disabled",
},
},
};
const result = await checkInboundAccessControl({
accountId: "default",
from: "123456789@g.us",
selfE164: "+15550009999",
senderE164: "+15550001111",
group: true,
groupId: "123456789@g.us",
pushName: "User",
isFromMe: false,
sock: { sendMessage: sendMessageMock },
remoteJid: "123456789@g.us",
});
expect(result.allowed).toBe(false);
});
it("blocks group messages when groupPolicy is allowlist but no groups configured and no groupAllowFrom", async () => {
config = {
channels: {
whatsapp: {
dmPolicy: "allowlist",
allowFrom: ["+15550009999"],
groupPolicy: "allowlist",
// No groups and no groupAllowFrom
},
},
};
const result = await checkInboundAccessControl({
accountId: "default",
from: "123456789@g.us",
selfE164: "+15550009999",
senderE164: "+15550001111",
group: true,
groupId: "123456789@g.us",
pushName: "User",
isFromMe: false,
sock: { sendMessage: sendMessageMock },
remoteJid: "123456789@g.us",
});
expect(result.allowed).toBe(false);
});
it("allows messages with groupAllowFrom wildcard", async () => {
config = {
channels: {
whatsapp: {
dmPolicy: "allowlist",
allowFrom: ["+15550009999"],
groupPolicy: "allowlist",
groupAllowFrom: ["*"],
},
},
};
const result = await checkInboundAccessControl({
accountId: "default",
from: "123456789@g.us",
selfE164: "+15550009999",
senderE164: "+15550001111",
group: true,
groupId: "123456789@g.us",
pushName: "Any User",
isFromMe: false,
sock: { sendMessage: sendMessageMock },
remoteJid: "123456789@g.us",
});
expect(result.allowed).toBe(true);
});
});

View File

@ -23,6 +23,8 @@ export async function checkInboundAccessControl(params: {
selfE164: string | null;
senderE164: string | null;
group: boolean;
/** Group JID for checking groups allowlist (only applicable when group=true) */
groupId?: string;
pushName?: string;
isFromMe: boolean;
messageTimestampMs?: number;
@ -90,28 +92,41 @@ export async function checkInboundAccessControl(params: {
};
}
if (params.group && groupPolicy === "allowlist") {
if (!groupAllowFrom || groupAllowFrom.length === 0) {
logVerbose("Blocked group message (groupPolicy: allowlist, no groupAllowFrom)");
return {
allowed: false,
shouldMarkRead: false,
isSelfChat,
resolvedAccountId: account.accountId,
};
}
const senderAllowed =
groupHasWildcard ||
(params.senderE164 != null && normalizedGroupAllowFrom.includes(params.senderE164));
if (!senderAllowed) {
logVerbose(
`Blocked group message from ${params.senderE164 ?? "unknown sender"} (groupPolicy: allowlist)`,
);
return {
allowed: false,
shouldMarkRead: false,
isSelfChat,
resolvedAccountId: account.accountId,
};
// Check if group is explicitly in the groups allowlist.
// If so, allow messages from all participants in this group (#3375).
const groups = account.groups;
const groupInAllowlist = params.groupId && groups && params.groupId in groups;
if (groupInAllowlist) {
logVerbose(`Allowing message from allowlisted group ${params.groupId}`);
// Continue to allow; don't return early so DM checks are skipped but message proceeds.
} else {
// Group not in allowlist - fall back to sender-based filtering via groupAllowFrom
if (!groupAllowFrom || groupAllowFrom.length === 0) {
logVerbose(
`Blocked group message from ${params.groupId ?? "unknown group"} (groupPolicy: allowlist, group not in allowlist, no groupAllowFrom)`,
);
return {
allowed: false,
shouldMarkRead: false,
isSelfChat,
resolvedAccountId: account.accountId,
};
}
const senderAllowed =
groupHasWildcard ||
(params.senderE164 != null && normalizedGroupAllowFrom.includes(params.senderE164));
if (!senderAllowed) {
logVerbose(
`Blocked group message from ${params.senderE164 ?? "unknown sender"} in ${params.groupId ?? "unknown group"} (groupPolicy: allowlist, sender not in groupAllowFrom)`,
);
return {
allowed: false,
shouldMarkRead: false,
isSelfChat,
resolvedAccountId: account.accountId,
};
}
}
}

View File

@ -183,6 +183,7 @@ export async function monitorWebInbox(options: {
selfE164,
senderE164,
group,
groupId: group ? remoteJid : undefined,
pushName: msg.pushName ?? undefined,
isFromMe: Boolean(msg.key?.fromMe),
messageTimestampMs,