mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-23 19:08:22 -06:00
fix(whatsapp): enforce exact raw JID domains
This commit is contained in:
@@ -185,6 +185,12 @@ describe("whatsapp inbound context visibility", () => {
|
||||
["whatsapp:777@lid", "777@lid"],
|
||||
["whatsapp:whatsapp:777@hosted.lid", "777@hosted.lid"],
|
||||
[" 777@s.whatsapp.net ", "+777"],
|
||||
["777@S.WHATSAPP.NET", "+777"],
|
||||
["777@HOSTED", "+777"],
|
||||
["777@LID", "777@lid"],
|
||||
["777@HOSTED.LID", "777@hosted.lid"],
|
||||
["123-456@G.US", "123-456@g.us"],
|
||||
["777@NEWSLETTER", "777@newsletter"],
|
||||
])("keeps raw native quote participant %j out of comparable facts", (participant, allowFrom) => {
|
||||
const context = describeReplyContext({
|
||||
extendedTextMessage: {
|
||||
|
||||
@@ -246,16 +246,21 @@ describe("isBotMentionedFromTargets", () => {
|
||||
});
|
||||
|
||||
it.each([
|
||||
"whatsapp:216372600647751@lid",
|
||||
"whatsapp:whatsapp:216372600647751@lid",
|
||||
" 216372600647751@lid ",
|
||||
])("does not treat raw native mention %j as a self mention", (mentionedJid) => {
|
||||
["whatsapp:216372600647751@lid", "216372600647751@lid"],
|
||||
["whatsapp:whatsapp:216372600647751@lid", "216372600647751@lid"],
|
||||
[" 216372600647751@lid ", "216372600647751@lid"],
|
||||
["216372600647751@LID", "216372600647751@lid"],
|
||||
["15551234567@S.WHATSAPP.NET", "15551234567@s.whatsapp.net"],
|
||||
["216372600647751@LID", "216372600647751@LID"],
|
||||
["123-456@G.US", "123-456@G.US"],
|
||||
["216372600647751@NEWSLETTER", "216372600647751@NEWSLETTER"],
|
||||
])("does not treat raw native mention %j as self identity %j", (mentionedJid, selfJid) => {
|
||||
const msg = makeMsg({
|
||||
body: "hey",
|
||||
mentionedJids: [mentionedJid],
|
||||
selfE164: "+15551234567",
|
||||
selfJid: "15551234567@s.whatsapp.net",
|
||||
selfLid: "216372600647751@lid",
|
||||
selfJid,
|
||||
selfLid: selfJid.includes("@lid") || selfJid.includes("@LID") ? selfJid : undefined,
|
||||
});
|
||||
|
||||
expectMentioned(msg, mentionCfg, false);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Whatsapp identity tests cover strict provider identity aliases.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { normalizeWhatsAppLidJid, resolveComparableIdentity } from "./identity.js";
|
||||
import { parseExactWhatsAppJid, parseWhatsAppJid } from "./phone-input.js";
|
||||
|
||||
describe("normalizeWhatsAppLidJid", () => {
|
||||
it.each([
|
||||
@@ -66,4 +67,18 @@ describe("normalizeWhatsAppLidJid", () => {
|
||||
"123@hosted.lid",
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
["123@S.WHATSAPP.NET", "123@s.whatsapp.net"],
|
||||
["123:4@HOSTED", "123:4@hosted"],
|
||||
["123@LID", "123@lid"],
|
||||
["123:4@HOSTED.LID", "123:4@hosted.lid"],
|
||||
["123-456@G.US", "123-456@g.us"],
|
||||
["123@NEWSLETTER", "123@newsletter"],
|
||||
])("keeps raw domain case exact while convenience-normalizing %j", (raw, canonical) => {
|
||||
expect(parseExactWhatsAppJid(raw)).toBeNull();
|
||||
expect(parseWhatsAppJid(raw)?.jid).toBe(canonical);
|
||||
const resolved = resolveComparableIdentity({ jid: raw });
|
||||
expect(resolved).toEqual({ jid: raw, lid: null, e164: null });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -109,7 +109,9 @@ export function getComparableIdentityValues(
|
||||
identity: WhatsAppIdentity | WhatsAppSelfIdentity | null | undefined,
|
||||
): string[] {
|
||||
const resolved = resolveComparableIdentity(identity);
|
||||
return [resolved.e164, resolved.jid, resolved.lid].filter((value): value is string =>
|
||||
const parsedJid = resolved.jid ? parseExactWhatsAppJid(resolved.jid) : null;
|
||||
const comparableJid = parsedJid?.kind === "pn" || parsedJid?.kind === "lid" ? resolved.jid : null;
|
||||
return [resolved.e164, comparableJid, resolved.lid].filter((value): value is string =>
|
||||
Boolean(value),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ export async function resolveWhatsAppCommandAuthorized(params: {
|
||||
});
|
||||
const isGroup = admission.conversation.kind === "group";
|
||||
const sender = getSenderIdentity(params.msg, params.authDir);
|
||||
const stableSender = isGroup ? (sender.e164 ?? sender.lid ?? sender.jid) : admission.sender.id;
|
||||
const stableSender = isGroup ? (sender.e164 ?? sender.lid) : admission.sender.id;
|
||||
if (!stableSender) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ vi.mock("./session.js", async () => {
|
||||
groupFetchAllParticipating: vi.fn().mockResolvedValue({}),
|
||||
updateMediaMessage: vi.fn(),
|
||||
logger: {},
|
||||
user: { id: "me@s.whatsapp.net" },
|
||||
user: { id: "15550001111@s.whatsapp.net" },
|
||||
};
|
||||
return currentMockSocket;
|
||||
}),
|
||||
@@ -442,7 +442,7 @@ describe("web inbound media saves with extension", () => {
|
||||
contextInfo: {
|
||||
stanzaId: "quoted-image",
|
||||
participant: "222@s.whatsapp.net",
|
||||
mentionedJid: ["me@s.whatsapp.net"],
|
||||
mentionedJid: ["15550001111@s.whatsapp.net"],
|
||||
quotedMessage: {
|
||||
imageMessage: { mimetype: "image/jpeg" },
|
||||
},
|
||||
@@ -490,7 +490,7 @@ describe("web inbound media saves with extension", () => {
|
||||
text: "what is in your image?",
|
||||
contextInfo: {
|
||||
stanzaId: "bot-image",
|
||||
participant: "me@s.whatsapp.net",
|
||||
participant: "15550001111@s.whatsapp.net",
|
||||
quotedMessage: { imageMessage: { mimetype: "image/jpeg" } },
|
||||
},
|
||||
},
|
||||
@@ -510,7 +510,7 @@ describe("web inbound media saves with extension", () => {
|
||||
const retry = encryptMediaRetryRequest(
|
||||
quoted!.key as never,
|
||||
Buffer.alloc(32, 1),
|
||||
"me@s.whatsapp.net",
|
||||
"15550001111@s.whatsapp.net",
|
||||
);
|
||||
const retryNode = Array.isArray(retry.content)
|
||||
? retry.content.find((node) => node.tag === "rmr")
|
||||
|
||||
@@ -151,6 +151,10 @@ describe("typed WhatsApp direct identity access", () => {
|
||||
["123:4@hosted.lid", "123@hosted.lid", true],
|
||||
["15550001111:4@s.whatsapp.net", "+15550001111", true],
|
||||
["15550001111:4@hosted", "+15550001111", true],
|
||||
["123@LID", "123@lid", false],
|
||||
["123:4@HOSTED.LID", "123@hosted.lid", false],
|
||||
["15550001111@S.WHATSAPP.NET", "+15550001111", false],
|
||||
["15550001111:4@HOSTED", "+15550001111", false],
|
||||
])(
|
||||
"authorizes group command sender %j against exact direct entry %j as %j",
|
||||
async (senderJid, allowFrom, expected) => {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Whatsapp helper module owns dependency-free strict phone input parsing.
|
||||
const WHATSAPP_PHONE_INPUT_RE = /^\+?[\d ().-]+$/;
|
||||
const WHATSAPP_JID_PATTERNS = [
|
||||
["pn", /^(\d+)(?::(\d+))?@(s\.whatsapp\.net|hosted)$/i],
|
||||
["pn", /^(\d+)()@(c\.us)$/i],
|
||||
["lid", /^(\d+)(?::(\d+))?@(lid|hosted\.lid)$/i],
|
||||
["group", /^([0-9]+(?:-[0-9]+)*)()@(g\.us)$/i],
|
||||
["newsletter", /^([0-9]+)()@(newsletter)$/i],
|
||||
["pn", /^(\d+)(?::(\d+))?@(s\.whatsapp\.net|hosted)$/],
|
||||
["pn", /^(\d+)()@(c\.us)$/],
|
||||
["lid", /^(\d+)(?::(\d+))?@(lid|hosted\.lid)$/],
|
||||
["group", /^([0-9]+(?:-[0-9]+)*)()@(g\.us)$/],
|
||||
["newsletter", /^([0-9]+)()@(newsletter)$/],
|
||||
] as const;
|
||||
|
||||
type ParsedWhatsAppJid = {
|
||||
@@ -43,7 +43,7 @@ export function parseExactWhatsAppJid(value: string): ParsedWhatsAppJid | null {
|
||||
for (const [kind, pattern] of WHATSAPP_JID_PATTERNS) {
|
||||
const match = value.match(pattern);
|
||||
const digits = match?.[1];
|
||||
const domain = match?.[3]?.toLowerCase();
|
||||
const domain = match?.[3];
|
||||
if (!digits || !domain) {
|
||||
continue;
|
||||
}
|
||||
@@ -57,7 +57,7 @@ export function parseWhatsAppJid(value: string): ParsedWhatsAppJid | null {
|
||||
const stripped = stripWhatsAppTargetPrefixes(value);
|
||||
const hasGroupPrefix = /^group:/i.test(stripped);
|
||||
const candidate = trimWhatsAppAsciiSpaces(stripped.replace(/^group:/i, ""));
|
||||
const parsed = parseExactWhatsAppJid(candidate);
|
||||
const parsed = parseExactWhatsAppJid(candidate.toLowerCase());
|
||||
return hasGroupPrefix && parsed?.kind !== "group" ? null : parsed;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user