mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-04 12:53:34 +00:00
fix(whatsapp): thread authDir through command authorization and owner bypass for LID JID resolution (#93379)
* fix(whatsapp): thread authDir through command authorization and owner bypass for LID JID resolution WhatsApp group commands (/new, /stop) can be ignored when Baileys reports the sender as a LID JID (@lid) instead of a phone JID (@s.whatsapp.net). The resolveWhatsAppCommandAuthorized() and isOwnerSender() functions called getSelfIdentity/getSenderIdentity without passing authDir, so the LID-to-phone reverse mapping could not happen. Fix: thread account.authDir through both command authorization and group owner-bypass identity resolution paths so that LID JIDs are properly resolved to phone E.164 identities before owner/allowlist checks. * fix(whatsapp): replace deprecated top-level fields with admission overrides in LID JID test
This commit is contained in:
@@ -78,12 +78,16 @@ function shouldWarnForGroupDrop(warnKey: string): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
function isOwnerSender(baseMentionConfig: MentionConfig, msg: AdmittedWebInboundMessage) {
|
||||
const sender = normalizeE164(getSenderIdentity(msg).e164 ?? "");
|
||||
function isOwnerSender(
|
||||
baseMentionConfig: MentionConfig,
|
||||
msg: AdmittedWebInboundMessage,
|
||||
authDir?: string,
|
||||
) {
|
||||
const sender = normalizeE164(getSenderIdentity(msg, authDir).e164 ?? "");
|
||||
if (!sender) {
|
||||
return false;
|
||||
}
|
||||
const owners = resolveOwnerList(baseMentionConfig, getSelfIdentity(msg).e164 ?? undefined);
|
||||
const owners = resolveOwnerList(baseMentionConfig, getSelfIdentity(msg, authDir).e164 ?? undefined);
|
||||
return owners.includes(sender);
|
||||
}
|
||||
|
||||
@@ -187,7 +191,7 @@ export async function applyGroupGating(params: ApplyGroupGatingParams) {
|
||||
self.e164,
|
||||
);
|
||||
const activationCommand = parseActivationCommand(commandBody);
|
||||
const owner = isOwnerSender(baseMentionConfig, params.msg);
|
||||
const owner = isOwnerSender(baseMentionConfig, params.msg, params.authDir);
|
||||
const shouldBypassMention = owner && hasControlCommand(commandBody, params.cfg);
|
||||
|
||||
if (activationCommand.hasCommand && !owner) {
|
||||
|
||||
@@ -437,6 +437,7 @@ export async function processMessage(params: {
|
||||
cfg: params.cfg,
|
||||
msg: params.msg,
|
||||
policy: inboundPolicy,
|
||||
authDir: account.authDir,
|
||||
})
|
||||
: undefined;
|
||||
const commandTurn: CommandTurnContext = isTextCommand
|
||||
|
||||
@@ -173,13 +173,14 @@ export async function resolveWhatsAppCommandAuthorized(params: {
|
||||
cfg: OpenClawConfig;
|
||||
msg: AdmittedWebInboundMessage;
|
||||
policy?: ResolvedWhatsAppInboundPolicy;
|
||||
authDir?: string;
|
||||
}): Promise<boolean> {
|
||||
const useAccessGroups = params.cfg.commands?.useAccessGroups !== false;
|
||||
if (!useAccessGroups) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const self = getSelfIdentity(params.msg);
|
||||
const self = getSelfIdentity(params.msg, params.authDir);
|
||||
const admission = requireWhatsAppInboundAdmission(params.msg);
|
||||
const policy =
|
||||
params.policy ??
|
||||
@@ -189,7 +190,7 @@ export async function resolveWhatsAppCommandAuthorized(params: {
|
||||
selfE164: self.e164 ?? null,
|
||||
});
|
||||
const isGroup = admission.conversation.kind === "group";
|
||||
const sender = getSenderIdentity(params.msg);
|
||||
const sender = getSenderIdentity(params.msg, params.authDir);
|
||||
const dmSender = sender.e164 ?? admission.conversation.id;
|
||||
const groupSender = sender.e164 ?? "";
|
||||
if (!normalizeE164(isGroup ? groupSender : dmSender)) {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
// Whatsapp tests cover access control plugin behavior.
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { beforeAll, describe, expect, it } from "vitest";
|
||||
import type {
|
||||
AcceptedInboundAccessControlResult,
|
||||
@@ -602,6 +605,54 @@ describe("WhatsApp dmPolicy precedence", () => {
|
||||
expect(result.isSelfChat).toBe(false);
|
||||
});
|
||||
|
||||
it("authorizes group commands when owner sender is a LID JID with authDir (issue #77755)", async () => {
|
||||
const lidDigits = "9876543210";
|
||||
const ownerE164 = "+15550001111";
|
||||
const authDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-wa-lid-77755-"));
|
||||
try {
|
||||
// Write reverse LID mapping so the LID JID resolves to the owner's phone
|
||||
fs.writeFileSync(
|
||||
path.join(authDir, `lid-mapping-${lidDigits}_reverse.json`),
|
||||
JSON.stringify(ownerE164),
|
||||
);
|
||||
|
||||
const cfg = {
|
||||
channels: {
|
||||
whatsapp: {
|
||||
dmPolicy: "allowlist",
|
||||
allowFrom: [ownerE164],
|
||||
},
|
||||
},
|
||||
};
|
||||
setAccessControlTestConfig(cfg);
|
||||
|
||||
const result = await resolveWhatsAppCommandAuthorized({
|
||||
cfg: cfg as never,
|
||||
msg: createTestWebInboundMessage({
|
||||
event: { id: "cmd-group-lid" },
|
||||
payload: { body: "/status" },
|
||||
platform: {
|
||||
chatJid: "120363401234567890@g.us",
|
||||
recipientJid: "+15550009999",
|
||||
senderJid: `${lidDigits}@lid`,
|
||||
selfE164: "+15550009999",
|
||||
},
|
||||
admission: {
|
||||
conversation: {
|
||||
id: "120363401234567890@g.us",
|
||||
kind: "group",
|
||||
},
|
||||
},
|
||||
}) as never,
|
||||
authDir,
|
||||
});
|
||||
|
||||
expect(result).toBe(true);
|
||||
} finally {
|
||||
fs.rmSync(authDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("treats same-phone DMs as self-chat only when explicitly configured", async () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
|
||||
Reference in New Issue
Block a user