mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
fix(whatsapp): separate raw JID parsing
This commit is contained in:
@@ -180,14 +180,18 @@ describe("whatsapp inbound context visibility", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps a malformed native quote participant out of comparable identity facts", () => {
|
||||
const malformedParticipant = "777:4:5@lid";
|
||||
it.each([
|
||||
["777:4:5@lid", "777@lid"],
|
||||
["whatsapp:777@lid", "777@lid"],
|
||||
["whatsapp:whatsapp:777@hosted.lid", "777@hosted.lid"],
|
||||
[" 777@s.whatsapp.net ", "+777"],
|
||||
])("keeps raw native quote participant %j out of comparable facts", (participant, allowFrom) => {
|
||||
const context = describeReplyContext({
|
||||
extendedTextMessage: {
|
||||
text: "current",
|
||||
contextInfo: {
|
||||
stanzaId: "malformed-native-quote",
|
||||
participant: malformedParticipant,
|
||||
participant,
|
||||
quotedMessage: { conversation: "Private quoted text" },
|
||||
},
|
||||
},
|
||||
@@ -203,22 +207,22 @@ describe("whatsapp inbound context visibility", () => {
|
||||
msg,
|
||||
mode: "allowlist",
|
||||
groupPolicy: "allowlist",
|
||||
groupAllowFrom: ["777@lid"],
|
||||
groupAllowFrom: [allowFrom],
|
||||
}),
|
||||
).toBeNull();
|
||||
const visibleQuote = resolveVisibleWhatsAppReplyContext({
|
||||
msg,
|
||||
mode: "allowlist_quote",
|
||||
groupPolicy: "allowlist",
|
||||
groupAllowFrom: ["777@lid"],
|
||||
groupAllowFrom: [allowFrom],
|
||||
});
|
||||
expect(visibleQuote?.body).toBe("Private quoted text");
|
||||
expect(visibleQuote?.sender).toMatchObject({
|
||||
jid: malformedParticipant,
|
||||
jid: participant,
|
||||
lid: null,
|
||||
e164: null,
|
||||
});
|
||||
expect(getComparableIdentityValues(visibleQuote?.sender)).not.toContain("777@lid");
|
||||
expect(getComparableIdentityValues(visibleQuote?.sender)).not.toContain(allowFrom);
|
||||
});
|
||||
|
||||
it("renders structured quoted media only at the visible preview boundary", () => {
|
||||
|
||||
@@ -245,6 +245,22 @@ describe("isBotMentionedFromTargets", () => {
|
||||
expectMentioned(msg, cfg, true);
|
||||
});
|
||||
|
||||
it.each([
|
||||
"whatsapp:216372600647751@lid",
|
||||
"whatsapp:whatsapp:216372600647751@lid",
|
||||
" 216372600647751@lid ",
|
||||
])("does not treat raw native mention %j as a self mention", (mentionedJid) => {
|
||||
const msg = makeMsg({
|
||||
body: "hey",
|
||||
mentionedJids: [mentionedJid],
|
||||
selfE164: "+15551234567",
|
||||
selfJid: "15551234567@s.whatsapp.net",
|
||||
selfLid: "216372600647751@lid",
|
||||
});
|
||||
|
||||
expectMentioned(msg, mentionCfg, false);
|
||||
});
|
||||
|
||||
it("honors explicit self-chat overrides without recomputing from allowFrom", () => {
|
||||
const cfg = {
|
||||
mentionRegexes: [/\bopenclaw\b/i],
|
||||
|
||||
@@ -43,6 +43,15 @@ describe("normalizeWhatsAppLidJid", () => {
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
"whatsapp:123@lid",
|
||||
"whatsapp:whatsapp:123@hosted.lid",
|
||||
" 123@s.whatsapp.net ",
|
||||
" 123@hosted ",
|
||||
])("keeps raw provider JID %j non-comparable", (jid) => {
|
||||
expect(resolveComparableIdentity({ jid })).toEqual({ jid, lid: null, e164: null });
|
||||
});
|
||||
|
||||
it.each([
|
||||
["123:4@s.whatsapp.net", { jid: "123@s.whatsapp.net", lid: null, e164: "+123" }],
|
||||
["123:4@hosted", { jid: "123@hosted", lid: null, e164: "+123" }],
|
||||
@@ -51,4 +60,10 @@ describe("normalizeWhatsAppLidJid", () => {
|
||||
])("canonicalizes exactly one device segment in %j", (jid, expected) => {
|
||||
expect(resolveComparableIdentity({ jid })).toEqual(expected);
|
||||
});
|
||||
|
||||
it("keeps configured LID aliases on convenience parsing", () => {
|
||||
expect(normalizeWhatsAppLidJid(" whatsapp:whatsapp:123:4@HOSTED.LID ")).toBe(
|
||||
"123@hosted.lid",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { MediaPlaceholderTextFact } from "openclaw/plugin-sdk/channel-inbound";
|
||||
// Whatsapp plugin module implements identity behavior.
|
||||
import { normalizeWhatsAppPhoneInput, parseWhatsAppJid } from "./phone-input.js";
|
||||
import {
|
||||
normalizeWhatsAppPhoneInput,
|
||||
parseExactWhatsAppJid,
|
||||
parseWhatsAppJid,
|
||||
} from "./phone-input.js";
|
||||
import { jidToE164 } from "./text-runtime.js";
|
||||
|
||||
export type WhatsAppIdentity = {
|
||||
@@ -64,14 +68,15 @@ type LegacyMentionsLike = {
|
||||
};
|
||||
|
||||
function normalizeDeviceScopedJid(jid: string | null | undefined): string | null {
|
||||
const parsed = typeof jid === "string" ? parseWhatsAppJid(jid) : null;
|
||||
const parsed = typeof jid === "string" ? parseExactWhatsAppJid(jid) : null;
|
||||
return parsed?.kind === "pn" || parsed?.kind === "lid"
|
||||
? `${parsed.digits}@${parsed.domain}`
|
||||
: (jid ?? null);
|
||||
}
|
||||
|
||||
function isWhatsAppLidJid(jid: string | null | undefined): boolean {
|
||||
return typeof jid === "string" && parseWhatsAppJid(jid)?.kind === "lid";
|
||||
function normalizeExactWhatsAppLidJid(jid: string | null | undefined): string | null {
|
||||
const parsed = typeof jid === "string" ? parseExactWhatsAppJid(jid) : null;
|
||||
return parsed?.kind === "lid" ? `${parsed.digits}@${parsed.domain}` : null;
|
||||
}
|
||||
|
||||
export function normalizeWhatsAppLidJid(jid: string | null | undefined): string | null {
|
||||
@@ -85,8 +90,8 @@ export function resolveComparableIdentity(
|
||||
): WhatsAppIdentity {
|
||||
const rawJid = normalizeDeviceScopedJid(identity?.jid);
|
||||
const rawLid = normalizeDeviceScopedJid(identity?.lid);
|
||||
const lid = normalizeWhatsAppLidJid(rawLid ?? rawJid);
|
||||
const jid = rawJid && !isWhatsAppLidJid(rawJid) ? rawJid : null;
|
||||
const lid = normalizeExactWhatsAppLidJid(rawLid ?? rawJid);
|
||||
const jid = rawJid && !normalizeExactWhatsAppLidJid(rawJid) ? rawJid : null;
|
||||
const e164 =
|
||||
identity?.e164 != null
|
||||
? normalizeWhatsAppPhoneInput(identity.e164)
|
||||
|
||||
@@ -36,29 +36,31 @@ export function stripWhatsAppTargetPrefixes(value: string): string {
|
||||
return candidate;
|
||||
}
|
||||
|
||||
export function parseWhatsAppJid(value: string): ParsedWhatsAppJid | null {
|
||||
export function parseExactWhatsAppJid(value: string): ParsedWhatsAppJid | null {
|
||||
if (hasUnsafeWhatsAppTargetCharacters(value)) {
|
||||
return null;
|
||||
}
|
||||
const stripped = stripWhatsAppTargetPrefixes(value);
|
||||
const hasGroupPrefix = /^group:/i.test(stripped);
|
||||
const candidate = trimWhatsAppAsciiSpaces(stripped.replace(/^group:/i, ""));
|
||||
for (const [kind, pattern] of WHATSAPP_JID_PATTERNS) {
|
||||
const match = candidate.match(pattern);
|
||||
const match = value.match(pattern);
|
||||
const digits = match?.[1];
|
||||
const domain = match?.[3]?.toLowerCase();
|
||||
if (!digits || !domain) {
|
||||
continue;
|
||||
}
|
||||
if (hasGroupPrefix && kind !== "group") {
|
||||
return null;
|
||||
}
|
||||
const device = match?.[2] ? `:${match[2]}` : "";
|
||||
return { kind, jid: `${digits}${device}@${domain}`, digits, domain };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
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);
|
||||
return hasGroupPrefix && parsed?.kind !== "group" ? null : parsed;
|
||||
}
|
||||
|
||||
export function normalizeWhatsAppPhoneInput(value: string): string | null {
|
||||
if (hasUnsafeWhatsAppTargetCharacters(value)) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user