From 43ae3bc489b53474e5d959dda3099f092ff81bbb Mon Sep 17 00:00:00 2001 From: Thiago Roque Ragazzo Date: Fri, 20 Mar 2026 13:26:28 -0300 Subject: [PATCH] fix(whatsapp): cover BR variant checks in monitor routing --- .../process-message.inbound-context.test.ts | 71 +++++++++++++++++++ .../src/auto-reply/monitor/process-message.ts | 10 ++- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/extensions/whatsapp/src/auto-reply/monitor/process-message.inbound-context.test.ts b/extensions/whatsapp/src/auto-reply/monitor/process-message.inbound-context.test.ts index c6db2affda3..4b321ea8579 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/process-message.inbound-context.test.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/process-message.inbound-context.test.ts @@ -350,6 +350,41 @@ describe("web processMessage inbound context", () => { expect(updateLastRouteMock).toHaveBeenCalledTimes(1); }); + it("authorizes control commands when BR ninth-digit variants differ", async () => { + capturedCtx = undefined; + + await processMessage( + makeProcessMessageArgs({ + routeSessionKey: "agent:main:whatsapp:direct:+5535998627740", + groupHistoryKey: "+5535998627740", + cfg: { + channels: { + whatsapp: { + dmPolicy: "allowlist", + allowFrom: ["+553598627740"], + }, + }, + commands: { useAccessGroups: true }, + messages: {}, + session: { store: sessionStorePath }, + } as unknown as ReturnType, + msg: { + id: "msg-command-br-variant", + from: "+5535998627740", + to: "+2000", + chatType: "direct", + body: "/status", + senderE164: "+5535998627740", + selfE164: "+5519999835286", + accountId: "default", + }, + }), + ); + + expect(capturedCtx).toBeTruthy(); + expect((capturedCtx as { CommandAuthorized?: boolean }).CommandAuthorized).toBe(true); + }); + it("does not update main last route for isolated DM scope sessions", async () => { const updateLastRouteMock = vi.mocked(updateLastRouteInBackground); updateLastRouteMock.mockClear(); @@ -440,4 +475,40 @@ describe("web processMessage inbound context", () => { expect(updateLastRouteMock).toHaveBeenCalledTimes(1); }); + + it("updates main last route when pinned owner and sender differ only by BR ninth digit", async () => { + const updateLastRouteMock = vi.mocked(updateLastRouteInBackground); + updateLastRouteMock.mockClear(); + + const args = makeProcessMessageArgs({ + routeSessionKey: "agent:main:main", + groupHistoryKey: "+5535998627740", + cfg: { + channels: { + whatsapp: { + allowFrom: ["+553598627740"], + }, + }, + messages: {}, + session: { store: sessionStorePath, dmScope: "main" }, + } as unknown as ReturnType, + msg: { + id: "msg-last-route-br-variant", + from: "+5535998627740", + to: "+2000", + chatType: "direct", + body: "hello", + senderE164: "+5535998627740", + }, + }); + args.route = { + ...args.route, + sessionKey: "agent:main:main", + mainSessionKey: "agent:main:main", + }; + + await processMessage(args); + + expect(updateLastRouteMock).toHaveBeenCalledTimes(1); + }); }); diff --git a/extensions/whatsapp/src/auto-reply/monitor/process-message.ts b/extensions/whatsapp/src/auto-reply/monitor/process-message.ts index 067087f87d3..069641b5a28 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/process-message.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/process-message.ts @@ -30,6 +30,7 @@ import { resolveDmGroupAccessWithCommandGate, } from "openclaw/plugin-sdk/security-runtime"; import { jidToE164, normalizeE164 } from "openclaw/plugin-sdk/text-runtime"; +import { areEquivalentWhatsAppDirectTargets } from "openclaw/plugin-sdk/whatsapp-shared"; import { resolveWhatsAppAccount } from "../../accounts.js"; import { newConnectionId } from "../../reconnect.js"; import { formatError } from "../../session.js"; @@ -101,7 +102,9 @@ async function resolveWhatsAppCommandAuthorized(params: { const normalizedEntries = allowEntries .map((entry) => normalizeE164(String(entry))) .filter((entry): entry is string => Boolean(entry)); - return normalizedEntries.includes(senderE164); + return normalizedEntries.some((entry) => + areEquivalentWhatsAppDirectTargets(entry, senderE164), + ); }, command: { useAccessGroups, @@ -342,7 +345,10 @@ export async function processMessage(params: { msg: params.msg, }); const shouldUpdateMainLastRoute = - !pinnedMainDmRecipient || pinnedMainDmRecipient === dmRouteTarget; + !pinnedMainDmRecipient || + (dmRouteTarget + ? areEquivalentWhatsAppDirectTargets(pinnedMainDmRecipient, dmRouteTarget) + : false); const inboundLastRouteSessionKey = resolveInboundLastRouteSessionKey({ route: params.route, sessionKey: params.route.sessionKey,