From 5894ffe82eade824472fbac118ac910fd694b72e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 14 Jan 2026 23:41:37 +0000 Subject: [PATCH] refactor(auth): streamline allowFrom normalization --- src/auto-reply/command-auth.ts | 75 ++++++++++++++++++---------------- src/whatsapp/normalize.test.ts | 19 +++++---- src/whatsapp/normalize.ts | 6 +-- 3 files changed, 55 insertions(+), 45 deletions(-) diff --git a/src/auto-reply/command-auth.ts b/src/auto-reply/command-auth.ts index f6b903e08..6c8fccb94 100644 --- a/src/auto-reply/command-auth.ts +++ b/src/auto-reply/command-auth.ts @@ -14,31 +14,6 @@ export type CommandAuthorization = { to?: string; }; -function resolveSenderId(params: { - dock?: ChannelDock; - cfg: ClawdbotConfig; - accountId?: string | null; - ctx: MsgContext; -}): string | undefined { - const { dock, cfg, accountId, ctx } = params; - - const senderCandidates = [ctx.SenderId, ctx.SenderE164, ctx.From] - .map((value) => (value ?? "").trim()) - .filter(Boolean); - - for (const sender of senderCandidates) { - const normalized = formatAllowFromList({ - dock, - cfg, - accountId, - allowFrom: [sender], - })[0]; - if (normalized) return normalized; - } - - return undefined; -} - function resolveProviderFromContext(ctx: MsgContext, cfg: ClawdbotConfig): ChannelId | undefined { const direct = normalizeChannelId(ctx.Provider) ?? @@ -81,6 +56,42 @@ function formatAllowFromList(params: { return allowFrom.map((entry) => String(entry).trim()).filter(Boolean); } +function normalizeAllowFromEntry(params: { + dock?: ChannelDock; + cfg: ClawdbotConfig; + accountId?: string | null; + value: string; +}): string | undefined { + return formatAllowFromList({ + dock: params.dock, + cfg: params.cfg, + accountId: params.accountId, + allowFrom: [params.value], + })[0]; +} + +function resolveSenderId(params: { + dock?: ChannelDock; + cfg: ClawdbotConfig; + accountId?: string | null; + senderId?: string | null; + senderE164?: string | null; + from?: string | null; +}): string | undefined { + const { dock, cfg, accountId } = params; + + const senderCandidates = [params.senderId, params.senderE164, params.from] + .map((value) => (value ?? "").trim()) + .filter(Boolean); + + for (const sender of senderCandidates) { + const normalized = normalizeAllowFromEntry({ dock, cfg, accountId, value: sender }); + if (normalized) return normalized; + } + + return undefined; +} + export function resolveCommandAuthorization(params: { ctx: MsgContext; cfg: ClawdbotConfig; @@ -105,12 +116,7 @@ export function resolveCommandAuthorization(params: { const ownerCandidates = allowAll ? [] : allowFromList.filter((entry) => entry !== "*"); if (!allowAll && ownerCandidates.length === 0 && to) { - const normalizedTo = formatAllowFromList({ - dock, - cfg, - accountId: ctx.AccountId, - allowFrom: [to], - })[0]; + const normalizedTo = normalizeAllowFromEntry({ dock, cfg, accountId: ctx.AccountId, value: to }); if (normalizedTo) ownerCandidates.push(normalizedTo); } const ownerList = ownerCandidates; @@ -119,10 +125,9 @@ export function resolveCommandAuthorization(params: { dock, cfg, accountId: ctx.AccountId, - ctx: { - ...ctx, - From: from, - }, + senderId: ctx.SenderId, + senderE164: ctx.SenderE164, + from, }); const enforceOwner = Boolean(dock?.commands?.enforceOwnerForCommands); diff --git a/src/whatsapp/normalize.test.ts b/src/whatsapp/normalize.test.ts index 3936b4098..662c19586 100644 --- a/src/whatsapp/normalize.test.ts +++ b/src/whatsapp/normalize.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; import { isWhatsAppGroupJid, - isWhatsAppUserJid, + isWhatsAppUserTarget, normalizeWhatsAppTarget, } from "./normalize.js"; @@ -45,6 +45,7 @@ describe("normalizeWhatsAppTarget", () => { it("normalizes LID JIDs to E.164", () => { expect(normalizeWhatsAppTarget("123456789@lid")).toBe("+123456789"); + expect(normalizeWhatsAppTarget("123456789@LID")).toBe("+123456789"); }); it("rejects invalid targets", () => { @@ -52,6 +53,7 @@ describe("normalizeWhatsAppTarget", () => { expect(normalizeWhatsAppTarget("whatsapp:")).toBeNull(); expect(normalizeWhatsAppTarget("@g.us")).toBeNull(); expect(normalizeWhatsAppTarget("whatsapp:group:@g.us")).toBeNull(); + expect(normalizeWhatsAppTarget("abc@s.whatsapp.net")).toBeNull(); }); it("handles repeated prefixes", () => { @@ -60,13 +62,16 @@ describe("normalizeWhatsAppTarget", () => { }); }); -describe("isWhatsAppUserJid", () => { +describe("isWhatsAppUserTarget", () => { it("detects user JIDs with various formats", () => { - expect(isWhatsAppUserJid("41796666864:0@s.whatsapp.net")).toBe(true); - expect(isWhatsAppUserJid("1234567890@s.whatsapp.net")).toBe(true); - expect(isWhatsAppUserJid("123456789@lid")).toBe(true); - expect(isWhatsAppUserJid("123456789-987654321@g.us")).toBe(false); - expect(isWhatsAppUserJid("+1555123")).toBe(false); + expect(isWhatsAppUserTarget("41796666864:0@s.whatsapp.net")).toBe(true); + expect(isWhatsAppUserTarget("1234567890@s.whatsapp.net")).toBe(true); + expect(isWhatsAppUserTarget("123456789@lid")).toBe(true); + expect(isWhatsAppUserTarget("123456789@LID")).toBe(true); + expect(isWhatsAppUserTarget("123@lid:0")).toBe(false); + expect(isWhatsAppUserTarget("abc@s.whatsapp.net")).toBe(false); + expect(isWhatsAppUserTarget("123456789-987654321@g.us")).toBe(false); + expect(isWhatsAppUserTarget("+1555123")).toBe(false); }); }); diff --git a/src/whatsapp/normalize.ts b/src/whatsapp/normalize.ts index a970fd298..b8bee8c95 100644 --- a/src/whatsapp/normalize.ts +++ b/src/whatsapp/normalize.ts @@ -25,9 +25,9 @@ export function isWhatsAppGroupJid(value: string): boolean { } /** - * Check if value looks like a WhatsApp user JID (e.g. "41796666864:0@s.whatsapp.net" or "123@lid"). + * Check if value looks like a WhatsApp user target (e.g. "41796666864:0@s.whatsapp.net" or "123@lid"). */ -export function isWhatsAppUserJid(value: string): boolean { +export function isWhatsAppUserTarget(value: string): boolean { const candidate = stripWhatsAppTargetPrefixes(value); return WHATSAPP_USER_JID_RE.test(candidate) || WHATSAPP_LID_RE.test(candidate); } @@ -53,7 +53,7 @@ export function normalizeWhatsAppTarget(value: string): string | null { return `${localPart}@g.us`; } // Handle user JIDs (e.g. "41796666864:0@s.whatsapp.net") - if (isWhatsAppUserJid(candidate)) { + if (isWhatsAppUserTarget(candidate)) { const phone = extractUserJidPhone(candidate); if (!phone) return null; const normalized = normalizeE164(phone);