



























11// Whatsapp tests cover access control plugin behavior.
22import { beforeAll, describe, expect, it } from "vitest";
3+import type {
4+AcceptedInboundAccessControlResult,
5+InboundAccessControlResult,
6+} from "./access-control.js";
37import {
48readAllowFromStoreMock,
59sendMessageMock,
@@ -19,6 +23,15 @@ beforeAll(async () => {
1923({ resolveWhatsAppCommandAuthorized } = await import("../inbound-policy.js"));
2024});
212526+function expectAccepted(
27+result: InboundAccessControlResult,
28+): asserts result is AcceptedInboundAccessControlResult {
29+expect(result.allowed).toBe(true);
30+if (!result.allowed) {
31+throw new Error("Expected accepted inbound access result");
32+}
33+}
34+2235async function checkUnauthorizedWorkDmSender() {
2336return checkInboundAccessControl({
2437cfg: getAccessControlTestConfig() as never,
@@ -92,6 +105,190 @@ async function checkCommandAuthorizedForGroup(params: {
92105});
93106}
94107108+describe("checkInboundAccessControl admission contract", () => {
109+it("keeps blocked results on the legacy flat access shape", async () => {
110+const cfg = {
111+channels: {
112+whatsapp: {
113+dmPolicy: "allowlist",
114+allowFrom: ["+15559999999"],
115+},
116+},
117+};
118+setAccessControlTestConfig(cfg);
119+120+const result = await checkInboundAccessControl({
121+cfg: getAccessControlTestConfig() as never,
122+accountId: "default",
123+from: "+15550001111",
124+selfE164: "+15550009999",
125+senderE164: "+15550001111",
126+group: false,
127+pushName: "Stranger",
128+isFromMe: false,
129+sock: { sendMessage: sendMessageMock },
130+remoteJid: "15550001111@s.whatsapp.net",
131+});
132+133+expect(result).toMatchObject({
134+allowed: false,
135+shouldMarkRead: false,
136+resolvedAccountId: "default",
137+isSelfChat: false,
138+});
139+expect("admission" in result).toBe(false);
140+});
141+142+it("returns accepted facts through admission while preserving legacy access fields", async () => {
143+const cfg = {
144+channels: {
145+whatsapp: {
146+dmPolicy: "allowlist",
147+contextVisibility: "allowlist_quote",
148+allowFrom: ["+15550001111"],
149+direct: {
150+"+15550001111": {
151+systemPrompt: "direct prompt",
152+},
153+},
154+},
155+},
156+};
157+setAccessControlTestConfig(cfg);
158+159+const result = await checkInboundAccessControl({
160+cfg: getAccessControlTestConfig() as never,
161+accountId: "default",
162+from: "+15550001111",
163+selfE164: "+15550009999",
164+senderE164: "+15550001111",
165+group: false,
166+pushName: "Sam",
167+isFromMe: false,
168+sock: { sendMessage: sendMessageMock },
169+remoteJid: "15550001111@s.whatsapp.net",
170+});
171+172+expectAccepted(result);
173+expect(result.resolvedAccountId).toBe(result.admission.accountId);
174+expect(result.isSelfChat).toBe(result.admission.isSelfChat);
175+expect(result.shouldMarkRead).toBe(true);
176+expect(result.admission).toMatchObject({
177+accountId: "default",
178+account: {
179+accountId: "default",
180+enabled: true,
181+sendReadReceipts: true,
182+},
183+conversation: {
184+kind: "direct",
185+id: "+15550001111",
186+groupSessionId: "+15550001111",
187+},
188+sender: {
189+id: "+15550001111",
190+dmSenderId: "+15550001111",
191+isSamePhone: false,
192+isDmSenderSamePhone: false,
193+},
194+ingress: {
195+admission: "dispatch",
196+decision: "allow",
197+reasonCode: "activation_allowed",
198+},
199+senderAccess: {
200+allowed: true,
201+decision: "allow",
202+providerMissingFallbackApplied: false,
203+reasonCode: "dm_policy_allowlisted",
204+},
205+commandAccess: {
206+requested: false,
207+authorized: false,
208+shouldBlockControlCommand: false,
209+reasonCode: "command_authorized",
210+},
211+activationAccess: {
212+ran: true,
213+allowed: true,
214+shouldSkip: false,
215+reasonCode: "activation_allowed",
216+},
217+});
218+expect(result.admission.account).not.toHaveProperty("authDir");
219+expect(result.admission.conversation).not.toHaveProperty("requireMention");
220+expect(result.admission.senderAccess).not.toHaveProperty("effectiveAllowFrom");
221+expect(result.admission.senderAccess).not.toHaveProperty("effectiveGroupAllowFrom");
222+expect(result.admission).not.toHaveProperty("resolvedPolicy");
223+});
224+225+it("uses group participant JID as the admission sender fallback", async () => {
226+const groupJid = "120363401234567890@g.us";
227+const participantJid = "15550001111@s.whatsapp.net";
228+const cfg = {
229+channels: {
230+whatsapp: {
231+groupPolicy: "open",
232+},
233+},
234+};
235+setAccessControlTestConfig(cfg);
236+237+const result = await checkInboundAccessControl({
238+cfg: getAccessControlTestConfig() as never,
239+accountId: "default",
240+from: groupJid,
241+selfE164: "+15550009999",
242+senderE164: null,
243+senderJid: participantJid,
244+group: true,
245+pushName: "Sam",
246+isFromMe: false,
247+sock: { sendMessage: sendMessageMock },
248+remoteJid: groupJid,
249+});
250+251+expectAccepted(result);
252+expect(result.admission.conversation).toMatchObject({
253+kind: "group",
254+id: groupJid,
255+groupSessionId: groupJid,
256+});
257+expect(result.admission.sender.id).toBe(participantJid);
258+expect(result.admission.sender.dmSenderId).toBe(groupJid);
259+});
260+261+it("does not authorize unresolved group participant JIDs as phone allowlist entries", async () => {
262+const groupJid = "120363401234567890@g.us";
263+const cfg = {
264+channels: {
265+whatsapp: {
266+groupPolicy: "allowlist",
267+groupAllowFrom: ["+15550001111"],
268+},
269+},
270+};
271+setAccessControlTestConfig(cfg);
272+273+const result = await checkInboundAccessControl({
274+cfg: getAccessControlTestConfig() as never,
275+accountId: "default",
276+from: groupJid,
277+selfE164: "+15550009999",
278+senderE164: null,
279+senderJid: "15550001111@lid",
280+group: true,
281+pushName: "Sam",
282+isFromMe: false,
283+sock: { sendMessage: sendMessageMock },
284+remoteJid: groupJid,
285+});
286+287+expect(result.allowed).toBe(false);
288+expect("admission" in result).toBe(false);
289+});
290+});
291+95292describe("checkInboundAccessControl pairing grace", () => {
96293async function runPairingGraceCase(messageTimestampMs: number) {
97294const connectedAtMs = 1_000_000;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。