@gakr-gakr/whatsapp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/action-runtime-api.ts +1 -0
- package/action-runtime.runtime.ts +1 -0
- package/api.ts +67 -0
- package/auth-presence.ts +80 -0
- package/autobot.plugin.json +23 -0
- package/channel-config-api.ts +1 -0
- package/channel-plugin-api.ts +3 -0
- package/config-api.ts +4 -0
- package/constants.ts +1 -0
- package/contract-api.ts +29 -0
- package/directory-contract-api.ts +4 -0
- package/doctor-contract-api.ts +8 -0
- package/index.ts +16 -0
- package/legacy-session-surface-api.ts +6 -0
- package/legacy-state-migrations-api.ts +1 -0
- package/light-runtime-api.ts +12 -0
- package/login-qr-api.ts +1 -0
- package/login-qr-runtime.ts +23 -0
- package/outbound-payload-test-api.ts +1 -0
- package/package.json +76 -0
- package/runtime-api.ts +84 -0
- package/secret-contract-api.ts +4 -0
- package/security-contract-api.ts +4 -0
- package/setup-entry.ts +21 -0
- package/setup-plugin-api.ts +3 -0
- package/src/account-config.ts +77 -0
- package/src/account-ids.ts +17 -0
- package/src/account-types.ts +5 -0
- package/src/accounts.ts +176 -0
- package/src/action-runtime-target-auth.ts +27 -0
- package/src/action-runtime.ts +76 -0
- package/src/active-listener.ts +17 -0
- package/src/agent-tools-login.ts +113 -0
- package/src/approval-auth.ts +27 -0
- package/src/auth-store.runtime.ts +1 -0
- package/src/auth-store.ts +494 -0
- package/src/auto-reply/config.runtime.ts +16 -0
- package/src/auto-reply/constants.ts +1 -0
- package/src/auto-reply/deliver-reply.ts +332 -0
- package/src/auto-reply/loggers.ts +6 -0
- package/src/auto-reply/mentions.ts +131 -0
- package/src/auto-reply/monitor/ack-reaction.ts +99 -0
- package/src/auto-reply/monitor/audio-preflight.runtime.ts +9 -0
- package/src/auto-reply/monitor/broadcast.ts +153 -0
- package/src/auto-reply/monitor/commands.ts +19 -0
- package/src/auto-reply/monitor/echo.ts +64 -0
- package/src/auto-reply/monitor/group-activation.runtime.ts +1 -0
- package/src/auto-reply/monitor/group-activation.ts +73 -0
- package/src/auto-reply/monitor/group-gating.runtime.ts +8 -0
- package/src/auto-reply/monitor/group-gating.ts +218 -0
- package/src/auto-reply/monitor/group-members.ts +65 -0
- package/src/auto-reply/monitor/inbound-context.ts +92 -0
- package/src/auto-reply/monitor/inbound-dispatch.runtime.ts +22 -0
- package/src/auto-reply/monitor/inbound-dispatch.ts +749 -0
- package/src/auto-reply/monitor/last-route.ts +61 -0
- package/src/auto-reply/monitor/listener-log.ts +28 -0
- package/src/auto-reply/monitor/message-line.runtime.ts +38 -0
- package/src/auto-reply/monitor/message-line.ts +54 -0
- package/src/auto-reply/monitor/on-message.ts +333 -0
- package/src/auto-reply/monitor/peer.ts +17 -0
- package/src/auto-reply/monitor/process-message.ts +584 -0
- package/src/auto-reply/monitor/runtime-api.ts +36 -0
- package/src/auto-reply/monitor/status-reaction.ts +108 -0
- package/src/auto-reply/monitor-state.ts +114 -0
- package/src/auto-reply/monitor.ts +720 -0
- package/src/auto-reply/reply-resolver.runtime.ts +1 -0
- package/src/auto-reply/types.ts +48 -0
- package/src/auto-reply/util.ts +62 -0
- package/src/auto-reply.impl.ts +6 -0
- package/src/auto-reply.ts +1 -0
- package/src/channel-actions.runtime.ts +7 -0
- package/src/channel-actions.ts +85 -0
- package/src/channel-outbound.ts +87 -0
- package/src/channel-react-action.runtime.ts +10 -0
- package/src/channel-react-action.ts +247 -0
- package/src/channel.runtime.ts +117 -0
- package/src/channel.setup.ts +32 -0
- package/src/channel.ts +356 -0
- package/src/command-policy.ts +7 -0
- package/src/config-accessors.ts +22 -0
- package/src/config-schema.ts +6 -0
- package/src/config-ui-hints.ts +24 -0
- package/src/connection-controller-registry.ts +49 -0
- package/src/connection-controller.ts +680 -0
- package/src/creds-files.ts +19 -0
- package/src/creds-persistence.ts +71 -0
- package/src/directory-config.ts +40 -0
- package/src/doctor-contract.ts +11 -0
- package/src/doctor.ts +56 -0
- package/src/document-filename.ts +17 -0
- package/src/group-intro.ts +15 -0
- package/src/group-policy.ts +40 -0
- package/src/group-session-contract.ts +20 -0
- package/src/group-session-key.ts +42 -0
- package/src/heartbeat.ts +34 -0
- package/src/identity.ts +164 -0
- package/src/inbound/access-control.ts +187 -0
- package/src/inbound/dedupe.ts +132 -0
- package/src/inbound/extract.ts +484 -0
- package/src/inbound/lifecycle.ts +39 -0
- package/src/inbound/media.ts +128 -0
- package/src/inbound/monitor.ts +1042 -0
- package/src/inbound/outbound-mentions.ts +260 -0
- package/src/inbound/runtime-api.ts +7 -0
- package/src/inbound/save-media.runtime.ts +1 -0
- package/src/inbound/send-api.ts +203 -0
- package/src/inbound/send-result.ts +109 -0
- package/src/inbound/types.ts +107 -0
- package/src/inbound-policy.ts +215 -0
- package/src/inbound.ts +9 -0
- package/src/login-qr.ts +542 -0
- package/src/login.ts +83 -0
- package/src/media.ts +10 -0
- package/src/monitor-inbox.allows-messages-from-senders-allowfrom-list.test-support.ts +417 -0
- package/src/monitor-inbox.append-upsert.test-support.ts +133 -0
- package/src/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test-support.ts +418 -0
- package/src/monitor-inbox.captures-media-path-image-messages.test-support.ts +308 -0
- package/src/monitor-inbox.streams-inbound-messages.test-support.ts +824 -0
- package/src/normalize-target.ts +148 -0
- package/src/normalize.ts +8 -0
- package/src/outbound-adapter.ts +36 -0
- package/src/outbound-base.ts +256 -0
- package/src/outbound-media-contract.ts +307 -0
- package/src/outbound-media.runtime.ts +41 -0
- package/src/outbound-send-deps.ts +1 -0
- package/src/outbound-test-support.ts +16 -0
- package/src/qa-driver.runtime.ts +189 -0
- package/src/qr-image.ts +1 -0
- package/src/qr-terminal.ts +1 -0
- package/src/quoted-message.ts +184 -0
- package/src/reaction-level.ts +24 -0
- package/src/reconnect.ts +55 -0
- package/src/resolve-outbound-target.ts +58 -0
- package/src/runtime-api.ts +59 -0
- package/src/runtime-group-policy.ts +16 -0
- package/src/runtime.ts +9 -0
- package/src/security-contract.ts +47 -0
- package/src/security-fix.ts +71 -0
- package/src/send.ts +342 -0
- package/src/session-contract.ts +43 -0
- package/src/session-errors.ts +125 -0
- package/src/session-route.ts +32 -0
- package/src/session.runtime.ts +8 -0
- package/src/session.ts +327 -0
- package/src/setup-core.ts +52 -0
- package/src/setup-finalize.ts +450 -0
- package/src/setup-surface.ts +71 -0
- package/src/setup-test-helpers.ts +217 -0
- package/src/shared.ts +291 -0
- package/src/socket-timing.ts +38 -0
- package/src/state-migrations.ts +55 -0
- package/src/status-issues.ts +185 -0
- package/src/system-prompt.ts +31 -0
- package/src/targets-runtime.ts +221 -0
- package/src/text-runtime.ts +18 -0
- package/src/vcard.ts +84 -0
- package/targets.ts +5 -0
- package/test-api.ts +2 -0
- package/tsconfig.json +16 -0
package/src/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test-support.ts
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import "./monitor-inbox.test-harness.js";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_ACCOUNT_ID,
|
|
5
|
+
expectPairingPromptSent,
|
|
6
|
+
getAuthDir,
|
|
7
|
+
getMonitorWebInbox,
|
|
8
|
+
getSock,
|
|
9
|
+
installWebMonitorInboxUnitTestHooks,
|
|
10
|
+
mockLoadConfig,
|
|
11
|
+
settleInboundWork,
|
|
12
|
+
waitForMessageCalls,
|
|
13
|
+
} from "./monitor-inbox.test-harness.js";
|
|
14
|
+
|
|
15
|
+
const nowSeconds = (offsetMs = 0) => Math.floor((Date.now() + offsetMs) / 1000);
|
|
16
|
+
const DEFAULT_MESSAGES_CFG = {
|
|
17
|
+
messagePrefix: undefined,
|
|
18
|
+
responsePrefix: undefined,
|
|
19
|
+
} as const;
|
|
20
|
+
const TIMESTAMP_OFF_MESSAGES_CFG = {
|
|
21
|
+
...DEFAULT_MESSAGES_CFG,
|
|
22
|
+
timestampPrefix: false,
|
|
23
|
+
} as const;
|
|
24
|
+
|
|
25
|
+
const createNotifyUpsert = (message: Record<string, unknown>) => ({
|
|
26
|
+
type: "notify",
|
|
27
|
+
messages: [message],
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const createDmMessage = (params: { id: string; remoteJid: string; conversation: string }) => ({
|
|
31
|
+
key: {
|
|
32
|
+
id: params.id,
|
|
33
|
+
fromMe: false,
|
|
34
|
+
remoteJid: params.remoteJid,
|
|
35
|
+
},
|
|
36
|
+
message: { conversation: params.conversation },
|
|
37
|
+
messageTimestamp: nowSeconds(),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const createGroupMessage = (params: {
|
|
41
|
+
id: string;
|
|
42
|
+
remoteJid?: string;
|
|
43
|
+
participant: string;
|
|
44
|
+
conversation: string;
|
|
45
|
+
}) => ({
|
|
46
|
+
key: {
|
|
47
|
+
id: params.id,
|
|
48
|
+
fromMe: false,
|
|
49
|
+
remoteJid: params.remoteJid ?? "11111@g.us",
|
|
50
|
+
participant: params.participant,
|
|
51
|
+
},
|
|
52
|
+
message: { conversation: params.conversation },
|
|
53
|
+
messageTimestamp: nowSeconds(),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
async function startWebInboxMonitor(params: {
|
|
57
|
+
config?: Record<string, unknown>;
|
|
58
|
+
loadConfig?: () => Record<string, unknown>;
|
|
59
|
+
sendReadReceipts?: boolean;
|
|
60
|
+
}) {
|
|
61
|
+
const monitorWebInbox = getMonitorWebInbox();
|
|
62
|
+
if (params.config) {
|
|
63
|
+
mockLoadConfig.mockReturnValue(params.config);
|
|
64
|
+
}
|
|
65
|
+
const onMessage = vi.fn();
|
|
66
|
+
const base = {
|
|
67
|
+
cfg: (params.config ?? mockLoadConfig()) as never,
|
|
68
|
+
...(params.loadConfig ? { loadConfig: params.loadConfig as never } : {}),
|
|
69
|
+
verbose: false,
|
|
70
|
+
accountId: DEFAULT_ACCOUNT_ID,
|
|
71
|
+
authDir: getAuthDir(),
|
|
72
|
+
onMessage,
|
|
73
|
+
};
|
|
74
|
+
const listener = await monitorWebInbox(
|
|
75
|
+
params.sendReadReceipts === undefined
|
|
76
|
+
? base
|
|
77
|
+
: {
|
|
78
|
+
...base,
|
|
79
|
+
sendReadReceipts: params.sendReadReceipts,
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
return { onMessage, listener, sock: getSock() };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function firstInboundPayload(onMessage: ReturnType<typeof vi.fn>) {
|
|
86
|
+
const payload = onMessage.mock.calls[0]?.[0];
|
|
87
|
+
if (!payload || typeof payload !== "object") {
|
|
88
|
+
throw new Error("expected first inbound payload");
|
|
89
|
+
}
|
|
90
|
+
return payload as Record<string, unknown>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
describe("web monitor inbox", () => {
|
|
94
|
+
installWebMonitorInboxUnitTestHooks();
|
|
95
|
+
|
|
96
|
+
it("blocks messages from unauthorized senders not in allowFrom", async () => {
|
|
97
|
+
// Test for auto-recovery fix: early allowFrom filtering prevents Bad MAC errors
|
|
98
|
+
// from unauthorized senders corrupting sessions
|
|
99
|
+
const config = {
|
|
100
|
+
channels: {
|
|
101
|
+
whatsapp: {
|
|
102
|
+
// Only allow +111
|
|
103
|
+
allowFrom: ["+111"],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
messages: DEFAULT_MESSAGES_CFG,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const { onMessage, listener, sock } = await startWebInboxMonitor({
|
|
110
|
+
config,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Message from unauthorized sender +999 (not in allowFrom)
|
|
114
|
+
sock.ev.emit(
|
|
115
|
+
"messages.upsert",
|
|
116
|
+
createNotifyUpsert(
|
|
117
|
+
createDmMessage({
|
|
118
|
+
id: "unauth1",
|
|
119
|
+
remoteJid: "999@s.whatsapp.net",
|
|
120
|
+
conversation: "unauthorized message",
|
|
121
|
+
}),
|
|
122
|
+
),
|
|
123
|
+
);
|
|
124
|
+
await vi.waitFor(() => expectPairingPromptSent(sock, "999@s.whatsapp.net", "+999"));
|
|
125
|
+
|
|
126
|
+
// Should NOT call onMessage for unauthorized senders
|
|
127
|
+
expect(onMessage).not.toHaveBeenCalled();
|
|
128
|
+
// Should NOT send read receipts for blocked senders (privacy + avoids Baileys Bad MAC churn).
|
|
129
|
+
expect(sock.readMessages).not.toHaveBeenCalled();
|
|
130
|
+
|
|
131
|
+
await listener.close();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("applies hot-reloaded dmPolicy allowlist to the active listener", async () => {
|
|
135
|
+
const startupConfig = {
|
|
136
|
+
channels: {
|
|
137
|
+
whatsapp: {
|
|
138
|
+
dmPolicy: "open",
|
|
139
|
+
allowFrom: ["*"],
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
messages: DEFAULT_MESSAGES_CFG,
|
|
143
|
+
};
|
|
144
|
+
const reloadedConfig = {
|
|
145
|
+
channels: {
|
|
146
|
+
whatsapp: {
|
|
147
|
+
dmPolicy: "allowlist",
|
|
148
|
+
allowFrom: ["+111"],
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
messages: DEFAULT_MESSAGES_CFG,
|
|
152
|
+
};
|
|
153
|
+
mockLoadConfig.mockReturnValue(startupConfig);
|
|
154
|
+
|
|
155
|
+
const { onMessage, listener, sock } = await startWebInboxMonitor({
|
|
156
|
+
config: startupConfig,
|
|
157
|
+
loadConfig: () => mockLoadConfig() as Record<string, unknown>,
|
|
158
|
+
});
|
|
159
|
+
mockLoadConfig.mockReturnValue(reloadedConfig);
|
|
160
|
+
|
|
161
|
+
sock.ev.emit(
|
|
162
|
+
"messages.upsert",
|
|
163
|
+
createNotifyUpsert(
|
|
164
|
+
createDmMessage({
|
|
165
|
+
id: "hot-reload-block",
|
|
166
|
+
remoteJid: "999@s.whatsapp.net",
|
|
167
|
+
conversation: "should be blocked after reload",
|
|
168
|
+
}),
|
|
169
|
+
),
|
|
170
|
+
);
|
|
171
|
+
await settleInboundWork();
|
|
172
|
+
|
|
173
|
+
expect(onMessage).not.toHaveBeenCalled();
|
|
174
|
+
expect(sock.sendMessage).not.toHaveBeenCalled();
|
|
175
|
+
expect(sock.readMessages).not.toHaveBeenCalled();
|
|
176
|
+
|
|
177
|
+
await listener.close();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("skips read receipts in self-chat mode", async () => {
|
|
181
|
+
const config = {
|
|
182
|
+
channels: {
|
|
183
|
+
whatsapp: {
|
|
184
|
+
// Self-chat heuristic: allowFrom includes selfE164 (+123).
|
|
185
|
+
allowFrom: ["+123"],
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
messages: DEFAULT_MESSAGES_CFG,
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const { onMessage, listener, sock } = await startWebInboxMonitor({
|
|
192
|
+
config,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
sock.ev.emit(
|
|
196
|
+
"messages.upsert",
|
|
197
|
+
createNotifyUpsert(
|
|
198
|
+
createDmMessage({
|
|
199
|
+
id: "self1",
|
|
200
|
+
remoteJid: "123@s.whatsapp.net",
|
|
201
|
+
conversation: "self ping",
|
|
202
|
+
}),
|
|
203
|
+
),
|
|
204
|
+
);
|
|
205
|
+
await waitForMessageCalls(onMessage, 1);
|
|
206
|
+
|
|
207
|
+
expect(onMessage).toHaveBeenCalledTimes(1);
|
|
208
|
+
expect(onMessage).toHaveBeenCalledWith(
|
|
209
|
+
expect.objectContaining({
|
|
210
|
+
from: "+123",
|
|
211
|
+
to: "+123",
|
|
212
|
+
body: "self ping",
|
|
213
|
+
accessControlPassed: true,
|
|
214
|
+
}),
|
|
215
|
+
);
|
|
216
|
+
expect(sock.readMessages).not.toHaveBeenCalled();
|
|
217
|
+
|
|
218
|
+
await listener.close();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("skips read receipts when disabled", async () => {
|
|
222
|
+
const { onMessage, listener, sock } = await startWebInboxMonitor({
|
|
223
|
+
sendReadReceipts: false,
|
|
224
|
+
});
|
|
225
|
+
sock.ev.emit(
|
|
226
|
+
"messages.upsert",
|
|
227
|
+
createNotifyUpsert(
|
|
228
|
+
createDmMessage({
|
|
229
|
+
id: "rr-off-1",
|
|
230
|
+
remoteJid: "222@s.whatsapp.net",
|
|
231
|
+
conversation: "read receipts off",
|
|
232
|
+
}),
|
|
233
|
+
),
|
|
234
|
+
);
|
|
235
|
+
await waitForMessageCalls(onMessage, 1);
|
|
236
|
+
|
|
237
|
+
expect(onMessage).toHaveBeenCalledTimes(1);
|
|
238
|
+
expect(sock.readMessages).not.toHaveBeenCalled();
|
|
239
|
+
|
|
240
|
+
await listener.close();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it("lets group messages through even when sender not in allowFrom", async () => {
|
|
244
|
+
const { onMessage, listener, sock } = await startWebInboxMonitor({
|
|
245
|
+
config: {
|
|
246
|
+
channels: { whatsapp: { allowFrom: ["+1234"], groupPolicy: "open" } },
|
|
247
|
+
messages: DEFAULT_MESSAGES_CFG,
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
sock.ev.emit(
|
|
251
|
+
"messages.upsert",
|
|
252
|
+
createNotifyUpsert(
|
|
253
|
+
createGroupMessage({
|
|
254
|
+
id: "grp3",
|
|
255
|
+
participant: "999@s.whatsapp.net",
|
|
256
|
+
conversation: "unauthorized group message",
|
|
257
|
+
}),
|
|
258
|
+
),
|
|
259
|
+
);
|
|
260
|
+
await settleInboundWork();
|
|
261
|
+
|
|
262
|
+
expect(onMessage).toHaveBeenCalledTimes(1);
|
|
263
|
+
const payload = firstInboundPayload(onMessage);
|
|
264
|
+
expect(payload.chatType).toBe("group");
|
|
265
|
+
expect(payload.senderE164).toBe("+999");
|
|
266
|
+
|
|
267
|
+
await listener.close();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("blocks all group messages when groupPolicy is 'disabled'", async () => {
|
|
271
|
+
const { onMessage, listener, sock } = await startWebInboxMonitor({
|
|
272
|
+
config: {
|
|
273
|
+
channels: { whatsapp: { allowFrom: ["+1234"], groupPolicy: "disabled" } },
|
|
274
|
+
messages: TIMESTAMP_OFF_MESSAGES_CFG,
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
sock.ev.emit(
|
|
278
|
+
"messages.upsert",
|
|
279
|
+
createNotifyUpsert(
|
|
280
|
+
createGroupMessage({
|
|
281
|
+
id: "grp-disabled",
|
|
282
|
+
participant: "999@s.whatsapp.net",
|
|
283
|
+
conversation: "group message should be blocked",
|
|
284
|
+
}),
|
|
285
|
+
),
|
|
286
|
+
);
|
|
287
|
+
await settleInboundWork();
|
|
288
|
+
|
|
289
|
+
// Should NOT call onMessage because groupPolicy is disabled
|
|
290
|
+
expect(onMessage).not.toHaveBeenCalled();
|
|
291
|
+
|
|
292
|
+
await listener.close();
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it("blocks group messages from senders not in groupAllowFrom when groupPolicy is 'allowlist'", async () => {
|
|
296
|
+
const { onMessage, listener, sock } = await startWebInboxMonitor({
|
|
297
|
+
config: {
|
|
298
|
+
channels: {
|
|
299
|
+
whatsapp: {
|
|
300
|
+
groupAllowFrom: ["+1234"], // Does not include +999
|
|
301
|
+
groupPolicy: "allowlist",
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
messages: TIMESTAMP_OFF_MESSAGES_CFG,
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
sock.ev.emit(
|
|
308
|
+
"messages.upsert",
|
|
309
|
+
createNotifyUpsert(
|
|
310
|
+
createGroupMessage({
|
|
311
|
+
id: "grp-allowlist-blocked",
|
|
312
|
+
participant: "999@s.whatsapp.net",
|
|
313
|
+
conversation: "unauthorized group sender",
|
|
314
|
+
}),
|
|
315
|
+
),
|
|
316
|
+
);
|
|
317
|
+
await settleInboundWork();
|
|
318
|
+
|
|
319
|
+
// Should NOT call onMessage because sender +999 not in groupAllowFrom
|
|
320
|
+
expect(onMessage).not.toHaveBeenCalled();
|
|
321
|
+
|
|
322
|
+
await listener.close();
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it("allows group messages from senders in groupAllowFrom when groupPolicy is 'allowlist'", async () => {
|
|
326
|
+
const { onMessage, listener, sock } = await startWebInboxMonitor({
|
|
327
|
+
config: {
|
|
328
|
+
channels: {
|
|
329
|
+
whatsapp: {
|
|
330
|
+
groupAllowFrom: ["+15551234567"], // Includes the sender
|
|
331
|
+
groupPolicy: "allowlist",
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
messages: TIMESTAMP_OFF_MESSAGES_CFG,
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
sock.ev.emit(
|
|
338
|
+
"messages.upsert",
|
|
339
|
+
createNotifyUpsert(
|
|
340
|
+
createGroupMessage({
|
|
341
|
+
id: "grp-allowlist-allowed",
|
|
342
|
+
participant: "15551234567@s.whatsapp.net",
|
|
343
|
+
conversation: "authorized group sender",
|
|
344
|
+
}),
|
|
345
|
+
),
|
|
346
|
+
);
|
|
347
|
+
await settleInboundWork();
|
|
348
|
+
|
|
349
|
+
// Should call onMessage because sender is in groupAllowFrom
|
|
350
|
+
expect(onMessage).toHaveBeenCalledTimes(1);
|
|
351
|
+
const payload = firstInboundPayload(onMessage);
|
|
352
|
+
expect(payload.chatType).toBe("group");
|
|
353
|
+
expect(payload.senderE164).toBe("+15551234567");
|
|
354
|
+
|
|
355
|
+
await listener.close();
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it("allows all group senders with wildcard in groupPolicy allowlist", async () => {
|
|
359
|
+
const { onMessage, listener, sock } = await startWebInboxMonitor({
|
|
360
|
+
config: {
|
|
361
|
+
channels: {
|
|
362
|
+
whatsapp: {
|
|
363
|
+
groupAllowFrom: ["*"], // Wildcard allows everyone
|
|
364
|
+
groupPolicy: "allowlist",
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
messages: TIMESTAMP_OFF_MESSAGES_CFG,
|
|
368
|
+
},
|
|
369
|
+
});
|
|
370
|
+
sock.ev.emit(
|
|
371
|
+
"messages.upsert",
|
|
372
|
+
createNotifyUpsert(
|
|
373
|
+
createGroupMessage({
|
|
374
|
+
id: "grp-wildcard-test",
|
|
375
|
+
remoteJid: "22222@g.us",
|
|
376
|
+
participant: "9999999999@s.whatsapp.net",
|
|
377
|
+
conversation: "wildcard group sender",
|
|
378
|
+
}),
|
|
379
|
+
),
|
|
380
|
+
);
|
|
381
|
+
await settleInboundWork();
|
|
382
|
+
|
|
383
|
+
// Should call onMessage because wildcard allows all senders
|
|
384
|
+
expect(onMessage).toHaveBeenCalledTimes(1);
|
|
385
|
+
const payload = firstInboundPayload(onMessage);
|
|
386
|
+
expect(payload.chatType).toBe("group");
|
|
387
|
+
|
|
388
|
+
await listener.close();
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it("blocks group messages when groupPolicy allowlist has no groupAllowFrom", async () => {
|
|
392
|
+
const { onMessage, listener, sock } = await startWebInboxMonitor({
|
|
393
|
+
config: {
|
|
394
|
+
channels: {
|
|
395
|
+
whatsapp: {
|
|
396
|
+
groupPolicy: "allowlist",
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
messages: TIMESTAMP_OFF_MESSAGES_CFG,
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
sock.ev.emit(
|
|
403
|
+
"messages.upsert",
|
|
404
|
+
createNotifyUpsert(
|
|
405
|
+
createGroupMessage({
|
|
406
|
+
id: "grp-allowlist-empty",
|
|
407
|
+
participant: "999@s.whatsapp.net",
|
|
408
|
+
conversation: "blocked by empty allowlist",
|
|
409
|
+
}),
|
|
410
|
+
),
|
|
411
|
+
);
|
|
412
|
+
await settleInboundWork();
|
|
413
|
+
|
|
414
|
+
expect(onMessage).not.toHaveBeenCalled();
|
|
415
|
+
|
|
416
|
+
await listener.close();
|
|
417
|
+
});
|
|
418
|
+
});
|