@openclaw/whatsapp 2026.5.2 → 2026.5.3-beta.2
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/dist/access-control-BQ3tCkH8.js +288 -0
- package/dist/account-config-CNQ33oav.js +47 -0
- package/dist/account-ids-DG18xddX.js +5 -0
- package/dist/accounts-BDqgpFEB.js +116 -0
- package/dist/action-runtime-DTGNgG-i.js +74 -0
- package/dist/action-runtime-api.js +2 -0
- package/dist/action-runtime.runtime.js +2 -0
- package/dist/active-listener-N7GFKsuN.js +11 -0
- package/dist/agent-tools-login-DpRxLNRB.js +89 -0
- package/dist/api.js +148 -0
- package/dist/audio-preflight.runtime-Bcdsl_ri.js +7 -0
- package/dist/auth-presence.js +32 -0
- package/dist/auth-store-BjCb50Ry.js +381 -0
- package/dist/channel-DQ-5Xoj9.js +542 -0
- package/dist/channel-config-api.js +2 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/channel-react-action-Df20qAy9.js +42 -0
- package/dist/channel.runtime-DKXRnA8x.js +55 -0
- package/dist/channel.setup-DOHR2BGp.js +20 -0
- package/dist/command-policy-O8sRnqUV.js +8 -0
- package/dist/config-schema-Dmo66Ubb.js +27 -0
- package/dist/connection-controller-BiHAsTM8.js +596 -0
- package/dist/connection-controller-registry-D_iIGz5m.js +22 -0
- package/dist/constants-DLGCIbfl.js +4 -0
- package/dist/constants.js +2 -0
- package/dist/contract-api.js +19 -0
- package/dist/creds-files-_2V8jzQa.js +19 -0
- package/dist/directory-config-DVs4ffXu.js +37 -0
- package/dist/directory-contract-api.js +2 -0
- package/dist/doctor-A9tXm9Om.js +48 -0
- package/dist/doctor-contract-api.js +10 -0
- package/dist/group-session-contract-B8QBn0I2.js +15 -0
- package/dist/identity-QHAlV7Fu.js +75 -0
- package/dist/index.js +18 -0
- package/dist/legacy-session-surface-api.js +8 -0
- package/dist/legacy-state-migrations-api.js +2 -0
- package/dist/light-runtime-api.js +5 -0
- package/dist/login-DymdrKca.js +52 -0
- package/dist/login-qr-DIS0Iv-7.js +378 -0
- package/dist/login-qr-api.js +2 -0
- package/dist/login-qr-runtime.js +16 -0
- package/dist/monitor-C4Fhg_lD.js +3349 -0
- package/dist/normalize-CWYiGkXw.js +2 -0
- package/dist/normalize-target-BPVHNsM5.js +74 -0
- package/dist/outbound-adapter-BssVnZdz.js +29 -0
- package/dist/outbound-base-Bq1UYEK5.js +119 -0
- package/dist/outbound-media-contract-CGss_QHy.js +163 -0
- package/dist/outbound-payload-test-api.js +2 -0
- package/dist/quoted-message-TENQzyxV.js +108 -0
- package/dist/reaction-level-CRVEVAfi.js +16 -0
- package/dist/reply-resolver.runtime-BRCgoO4C.js +2 -0
- package/dist/resolve-outbound-target-CN-Wo6IY.js +39 -0
- package/dist/rolldown-runtime-RkAeH_Qm.js +27 -0
- package/dist/runtime-6fZ67abR.js +8 -0
- package/dist/runtime-api.js +15 -0
- package/dist/runtime-group-policy-Gp1lQ0at.js +11 -0
- package/dist/secret-contract-api.js +5 -0
- package/dist/security-contract-DqH8JDX6.js +26 -0
- package/dist/security-contract-api.js +2 -0
- package/dist/send-CIyLFxdZ.js +234 -0
- package/dist/session-contract-B0efQf9P.js +27 -0
- package/dist/session-errors-CSuKZPub.js +63 -0
- package/dist/session.runtime-C1eSE_KK.js +13 -0
- package/dist/setup-core-DZKvpzbH.js +46 -0
- package/dist/setup-entry.js +23 -0
- package/dist/setup-plugin-api.js +2 -0
- package/dist/setup-surface-ieFnIW4g.js +344 -0
- package/dist/shared-D_wzSVar.js +307 -0
- package/dist/state-migrations-DnCdvoYD.js +39 -0
- package/dist/targets.js +2 -0
- package/dist/test-api.js +3 -0
- package/dist/text-runtime-C1zNiZeO.js +116 -0
- package/package.json +14 -6
- package/action-runtime-api.ts +0 -1
- package/action-runtime.runtime.ts +0 -1
- package/api.ts +0 -213
- package/auth-presence.ts +0 -80
- package/channel-config-api.ts +0 -1
- package/channel-plugin-api.ts +0 -3
- package/config-api.ts +0 -4
- package/constants.ts +0 -1
- package/contract-api.ts +0 -29
- package/directory-contract-api.ts +0 -4
- package/doctor-contract-api.ts +0 -8
- package/index.test.ts +0 -13
- package/index.ts +0 -16
- package/legacy-session-surface-api.ts +0 -6
- package/legacy-state-migrations-api.ts +0 -1
- package/light-runtime-api.ts +0 -12
- package/login-qr-api.ts +0 -1
- package/login-qr-runtime.ts +0 -23
- package/outbound-payload-test-api.ts +0 -1
- package/runtime-api.ts +0 -84
- package/secret-contract-api.ts +0 -4
- package/security-contract-api.ts +0 -4
- package/setup-entry.test.ts +0 -21
- package/setup-entry.ts +0 -21
- package/setup-plugin-api.ts +0 -3
- package/src/account-config.ts +0 -77
- package/src/account-ids.ts +0 -13
- package/src/account-types.ts +0 -5
- package/src/accounts.test.ts +0 -182
- package/src/accounts.ts +0 -176
- package/src/accounts.whatsapp-auth.test.ts +0 -59
- package/src/action-runtime-target-auth.ts +0 -27
- package/src/action-runtime.test.ts +0 -330
- package/src/action-runtime.ts +0 -76
- package/src/active-listener.test.ts +0 -65
- package/src/active-listener.ts +0 -17
- package/src/agent-tools-login.test.ts +0 -81
- package/src/agent-tools-login.ts +0 -113
- package/src/approval-auth.test.ts +0 -24
- package/src/approval-auth.ts +0 -27
- package/src/auth-store.runtime.ts +0 -1
- package/src/auth-store.test.ts +0 -311
- package/src/auth-store.ts +0 -502
- package/src/auto-reply/config.runtime.ts +0 -16
- package/src/auto-reply/constants.ts +0 -1
- package/src/auto-reply/deliver-reply.test.ts +0 -843
- package/src/auto-reply/deliver-reply.ts +0 -279
- package/src/auto-reply/loggers.ts +0 -6
- package/src/auto-reply/mentions.ts +0 -131
- package/src/auto-reply/monitor/ack-reaction.test.ts +0 -170
- package/src/auto-reply/monitor/ack-reaction.ts +0 -99
- package/src/auto-reply/monitor/audio-preflight.runtime.ts +0 -9
- package/src/auto-reply/monitor/broadcast.ts +0 -153
- package/src/auto-reply/monitor/commands.ts +0 -19
- package/src/auto-reply/monitor/echo.ts +0 -64
- package/src/auto-reply/monitor/group-activation.runtime.ts +0 -1
- package/src/auto-reply/monitor/group-activation.test.ts +0 -189
- package/src/auto-reply/monitor/group-activation.ts +0 -73
- package/src/auto-reply/monitor/group-gating.audio-preflight.test.ts +0 -103
- package/src/auto-reply/monitor/group-gating.runtime.ts +0 -8
- package/src/auto-reply/monitor/group-gating.ts +0 -217
- package/src/auto-reply/monitor/group-members.test.ts +0 -56
- package/src/auto-reply/monitor/group-members.ts +0 -65
- package/src/auto-reply/monitor/inbound-context.test.ts +0 -97
- package/src/auto-reply/monitor/inbound-context.ts +0 -92
- package/src/auto-reply/monitor/inbound-dispatch.runtime.ts +0 -21
- package/src/auto-reply/monitor/inbound-dispatch.test.ts +0 -895
- package/src/auto-reply/monitor/inbound-dispatch.ts +0 -422
- package/src/auto-reply/monitor/last-route.test.ts +0 -37
- package/src/auto-reply/monitor/last-route.ts +0 -61
- package/src/auto-reply/monitor/message-line.runtime.ts +0 -38
- package/src/auto-reply/monitor/message-line.ts +0 -54
- package/src/auto-reply/monitor/on-message.audio-preflight.test.ts +0 -354
- package/src/auto-reply/monitor/on-message.ts +0 -291
- package/src/auto-reply/monitor/peer.ts +0 -17
- package/src/auto-reply/monitor/process-message.audio-preflight.test.ts +0 -420
- package/src/auto-reply/monitor/process-message.test.ts +0 -355
- package/src/auto-reply/monitor/process-message.ts +0 -531
- package/src/auto-reply/monitor/runtime-api.ts +0 -30
- package/src/auto-reply/monitor-state.test.ts +0 -64
- package/src/auto-reply/monitor-state.ts +0 -106
- package/src/auto-reply/monitor.ts +0 -600
- package/src/auto-reply/reply-resolver.runtime.ts +0 -1
- package/src/auto-reply/types.ts +0 -48
- package/src/auto-reply/util.ts +0 -63
- package/src/auto-reply/web-auto-reply-monitor.test.ts +0 -687
- package/src/auto-reply/web-auto-reply-utils.test.ts +0 -392
- package/src/auto-reply.broadcast-groups.combined.test.ts +0 -246
- package/src/auto-reply.broadcast-groups.test-harness.ts +0 -47
- package/src/auto-reply.impl.ts +0 -6
- package/src/auto-reply.test-harness.ts +0 -421
- package/src/auto-reply.ts +0 -1
- package/src/auto-reply.web-auto-reply.compresses-common-formats-jpeg-cap.test.ts +0 -427
- package/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts +0 -908
- package/src/auto-reply.web-auto-reply.last-route.test.ts +0 -184
- package/src/channel-actions.runtime.ts +0 -7
- package/src/channel-actions.test.ts +0 -216
- package/src/channel-actions.ts +0 -84
- package/src/channel-outbound.test.ts +0 -131
- package/src/channel-outbound.ts +0 -36
- package/src/channel-react-action.runtime.ts +0 -7
- package/src/channel-react-action.test.ts +0 -294
- package/src/channel-react-action.ts +0 -84
- package/src/channel.runtime.ts +0 -117
- package/src/channel.setup.test.ts +0 -461
- package/src/channel.setup.ts +0 -28
- package/src/channel.ts +0 -339
- package/src/command-policy.ts +0 -7
- package/src/config-accessors.test.ts +0 -34
- package/src/config-accessors.ts +0 -22
- package/src/config-schema.test.ts +0 -121
- package/src/config-schema.ts +0 -6
- package/src/config-ui-hints.ts +0 -24
- package/src/connection-controller-registry.test.ts +0 -27
- package/src/connection-controller-registry.ts +0 -49
- package/src/connection-controller.test.ts +0 -282
- package/src/connection-controller.ts +0 -679
- package/src/creds-files.ts +0 -19
- package/src/creds-persistence.ts +0 -102
- package/src/directory-config.test.ts +0 -60
- package/src/directory-config.ts +0 -40
- package/src/directory-contract.test.ts +0 -56
- package/src/doctor-contract.ts +0 -11
- package/src/doctor.test.ts +0 -74
- package/src/doctor.ts +0 -56
- package/src/group-intro.ts +0 -15
- package/src/group-policy.test.ts +0 -36
- package/src/group-policy.ts +0 -40
- package/src/group-session-contract.ts +0 -20
- package/src/group-session-key.test.ts +0 -53
- package/src/group-session-key.ts +0 -41
- package/src/heartbeat.ts +0 -34
- package/src/identity.ts +0 -164
- package/src/inbound/access-control.test-harness.ts +0 -37
- package/src/inbound/access-control.test.ts +0 -375
- package/src/inbound/access-control.ts +0 -237
- package/src/inbound/dedupe.ts +0 -132
- package/src/inbound/extract.test.ts +0 -282
- package/src/inbound/extract.ts +0 -488
- package/src/inbound/lifecycle.ts +0 -39
- package/src/inbound/media.node.test.ts +0 -83
- package/src/inbound/media.ts +0 -102
- package/src/inbound/monitor.ts +0 -890
- package/src/inbound/runtime-api.ts +0 -7
- package/src/inbound/save-media.runtime.ts +0 -1
- package/src/inbound/send-api.test.ts +0 -319
- package/src/inbound/send-api.ts +0 -145
- package/src/inbound/send-result.ts +0 -61
- package/src/inbound/types.ts +0 -106
- package/src/inbound-context.contract.test.ts +0 -32
- package/src/inbound-policy.ts +0 -231
- package/src/inbound.media.test.ts +0 -320
- package/src/inbound.test.ts +0 -290
- package/src/inbound.ts +0 -9
- package/src/login-qr.test.ts +0 -483
- package/src/login-qr.ts +0 -542
- package/src/login.coverage.test.ts +0 -133
- package/src/login.test.ts +0 -89
- package/src/login.ts +0 -70
- package/src/logout.test.ts +0 -162
- package/src/media.test.ts +0 -480
- package/src/media.ts +0 -10
- package/src/monitor-inbox.allows-messages-from-senders-allowfrom-list.test-support.ts +0 -400
- package/src/monitor-inbox.append-upsert.test-support.ts +0 -133
- package/src/monitor-inbox.behavior.test.ts +0 -5
- package/src/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test-support.ts +0 -362
- package/src/monitor-inbox.captures-media-path-image-messages.test-support.ts +0 -306
- package/src/monitor-inbox.streams-inbound-messages.test-support.ts +0 -729
- package/src/monitor-inbox.test-harness.ts +0 -304
- package/src/normalize-target.ts +0 -123
- package/src/normalize.ts +0 -7
- package/src/outbound-adapter.poll.test.ts +0 -62
- package/src/outbound-adapter.sendpayload.test.ts +0 -195
- package/src/outbound-adapter.ts +0 -36
- package/src/outbound-base.test.ts +0 -560
- package/src/outbound-base.ts +0 -244
- package/src/outbound-media-contract.ts +0 -278
- package/src/outbound-media.runtime.ts +0 -36
- package/src/outbound-payload.contract.test.ts +0 -61
- package/src/outbound-send-deps.ts +0 -1
- package/src/outbound-test-support.ts +0 -16
- package/src/pairing-security.test-harness.ts +0 -59
- package/src/qr-image.ts +0 -1
- package/src/qr-terminal.ts +0 -1
- package/src/quoted-message.test.ts +0 -83
- package/src/quoted-message.ts +0 -184
- package/src/reaction-level.test.ts +0 -94
- package/src/reaction-level.ts +0 -21
- package/src/reconnect.test.ts +0 -51
- package/src/reconnect.ts +0 -55
- package/src/resolve-outbound-target.test.ts +0 -288
- package/src/resolve-outbound-target.ts +0 -58
- package/src/resolve-target.test.ts +0 -120
- package/src/runtime-api.ts +0 -59
- package/src/runtime-group-policy.ts +0 -16
- package/src/runtime.ts +0 -9
- package/src/security-contract.ts +0 -47
- package/src/security-fix.ts +0 -71
- package/src/send.test.ts +0 -534
- package/src/send.ts +0 -292
- package/src/session-contract.test.ts +0 -31
- package/src/session-contract.ts +0 -43
- package/src/session-errors.ts +0 -125
- package/src/session-route.test.ts +0 -41
- package/src/session-route.ts +0 -32
- package/src/session.runtime.ts +0 -8
- package/src/session.test.ts +0 -559
- package/src/session.ts +0 -330
- package/src/setup-core.ts +0 -52
- package/src/setup-finalize.ts +0 -446
- package/src/setup-surface.test.ts +0 -367
- package/src/setup-surface.ts +0 -69
- package/src/setup-test-helpers.ts +0 -216
- package/src/shared.ts +0 -291
- package/src/socket-timing.test.ts +0 -49
- package/src/socket-timing.ts +0 -38
- package/src/state-migrations.ts +0 -54
- package/src/status-issues.test.ts +0 -137
- package/src/status-issues.ts +0 -185
- package/src/system-prompt.test.ts +0 -199
- package/src/system-prompt.ts +0 -31
- package/src/targets-runtime.ts +0 -180
- package/src/test-helpers.ts +0 -690
- package/src/text-runtime.test.ts +0 -162
- package/src/text-runtime.ts +0 -11
- package/src/vcard.ts +0 -84
- package/targets.ts +0 -5
- package/test-api.ts +0 -2
- package/tsconfig.json +0 -16
package/src/identity.ts
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { jidToE164, normalizeE164 } from "./text-runtime.js";
|
|
2
|
-
|
|
3
|
-
const WHATSAPP_LID_RE = /@(lid|hosted\.lid)$/i;
|
|
4
|
-
|
|
5
|
-
export type WhatsAppIdentity = {
|
|
6
|
-
jid?: string | null;
|
|
7
|
-
lid?: string | null;
|
|
8
|
-
e164?: string | null;
|
|
9
|
-
name?: string | null;
|
|
10
|
-
label?: string | null;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export type WhatsAppSelfIdentity = {
|
|
14
|
-
jid?: string | null;
|
|
15
|
-
lid?: string | null;
|
|
16
|
-
e164?: string | null;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type WhatsAppReplyContext = {
|
|
20
|
-
id?: string;
|
|
21
|
-
body: string;
|
|
22
|
-
sender?: WhatsAppIdentity | null;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
type LegacySenderLike = {
|
|
26
|
-
sender?: WhatsAppIdentity;
|
|
27
|
-
senderJid?: string;
|
|
28
|
-
senderE164?: string;
|
|
29
|
-
senderName?: string;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
type LegacySelfLike = {
|
|
33
|
-
self?: WhatsAppSelfIdentity;
|
|
34
|
-
selfJid?: string | null;
|
|
35
|
-
selfLid?: string | null;
|
|
36
|
-
selfE164?: string | null;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
type LegacyReplyLike = {
|
|
40
|
-
replyTo?: WhatsAppReplyContext;
|
|
41
|
-
replyToId?: string;
|
|
42
|
-
replyToBody?: string;
|
|
43
|
-
replyToSender?: string;
|
|
44
|
-
replyToSenderJid?: string;
|
|
45
|
-
replyToSenderE164?: string;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
type LegacyMentionsLike = {
|
|
49
|
-
mentions?: string[];
|
|
50
|
-
mentionedJids?: string[];
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
function normalizeDeviceScopedJid(jid: string | null | undefined): string | null {
|
|
54
|
-
return jid ? jid.replace(/:\d+/, "") : null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function isLidJid(jid: string | null | undefined): boolean {
|
|
58
|
-
return Boolean(jid && WHATSAPP_LID_RE.test(jid));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function resolveComparableIdentity(
|
|
62
|
-
identity: WhatsAppIdentity | WhatsAppSelfIdentity | null | undefined,
|
|
63
|
-
authDir?: string,
|
|
64
|
-
): WhatsAppIdentity {
|
|
65
|
-
const rawJid = normalizeDeviceScopedJid(identity?.jid);
|
|
66
|
-
const rawLid = normalizeDeviceScopedJid(identity?.lid);
|
|
67
|
-
const lid = rawLid ?? (isLidJid(rawJid) ? rawJid : null);
|
|
68
|
-
const jid = rawJid && !isLidJid(rawJid) ? rawJid : null;
|
|
69
|
-
const e164 =
|
|
70
|
-
identity?.e164 != null
|
|
71
|
-
? normalizeE164(identity.e164)
|
|
72
|
-
: ((jid ? jidToE164(jid, authDir ? { authDir } : undefined) : null) ??
|
|
73
|
-
(lid ? jidToE164(lid, authDir ? { authDir } : undefined) : null));
|
|
74
|
-
return {
|
|
75
|
-
...identity,
|
|
76
|
-
jid,
|
|
77
|
-
lid,
|
|
78
|
-
e164,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function getComparableIdentityValues(
|
|
83
|
-
identity: WhatsAppIdentity | WhatsAppSelfIdentity | null | undefined,
|
|
84
|
-
): string[] {
|
|
85
|
-
const resolved = resolveComparableIdentity(identity);
|
|
86
|
-
return [resolved.e164, resolved.jid, resolved.lid].filter((value): value is string =>
|
|
87
|
-
Boolean(value),
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function identitiesOverlap(
|
|
92
|
-
left: WhatsAppIdentity | WhatsAppSelfIdentity | null | undefined,
|
|
93
|
-
right: WhatsAppIdentity | WhatsAppSelfIdentity | null | undefined,
|
|
94
|
-
): boolean {
|
|
95
|
-
const leftValues = new Set(getComparableIdentityValues(left));
|
|
96
|
-
if (leftValues.size === 0) {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
return getComparableIdentityValues(right).some((value) => leftValues.has(value));
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function getSenderIdentity(msg: LegacySenderLike, authDir?: string): WhatsAppIdentity {
|
|
103
|
-
return resolveComparableIdentity(
|
|
104
|
-
msg.sender ?? {
|
|
105
|
-
jid: msg.senderJid ?? null,
|
|
106
|
-
e164: msg.senderE164 ?? null,
|
|
107
|
-
name: msg.senderName ?? null,
|
|
108
|
-
},
|
|
109
|
-
authDir,
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export function getSelfIdentity(msg: LegacySelfLike, authDir?: string): WhatsAppSelfIdentity {
|
|
114
|
-
return resolveComparableIdentity(
|
|
115
|
-
msg.self ?? {
|
|
116
|
-
jid: msg.selfJid ?? null,
|
|
117
|
-
lid: msg.selfLid ?? null,
|
|
118
|
-
e164: msg.selfE164 ?? null,
|
|
119
|
-
},
|
|
120
|
-
authDir,
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export function getReplyContext(
|
|
125
|
-
msg: LegacyReplyLike,
|
|
126
|
-
authDir?: string,
|
|
127
|
-
): WhatsAppReplyContext | null {
|
|
128
|
-
if (msg.replyTo) {
|
|
129
|
-
return {
|
|
130
|
-
...msg.replyTo,
|
|
131
|
-
sender: resolveComparableIdentity(msg.replyTo.sender, authDir),
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
if (!msg.replyToBody) {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
return {
|
|
138
|
-
id: msg.replyToId,
|
|
139
|
-
body: msg.replyToBody,
|
|
140
|
-
sender: resolveComparableIdentity(
|
|
141
|
-
{
|
|
142
|
-
jid: msg.replyToSenderJid ?? null,
|
|
143
|
-
e164: msg.replyToSenderE164 ?? null,
|
|
144
|
-
label: msg.replyToSender ?? null,
|
|
145
|
-
},
|
|
146
|
-
authDir,
|
|
147
|
-
),
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function getMentionJids(msg: LegacyMentionsLike): string[] {
|
|
152
|
-
return msg.mentions ?? msg.mentionedJids ?? [];
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export function getMentionIdentities(
|
|
156
|
-
msg: LegacyMentionsLike,
|
|
157
|
-
authDir?: string,
|
|
158
|
-
): WhatsAppIdentity[] {
|
|
159
|
-
return getMentionJids(msg).map((jid) => resolveComparableIdentity({ jid }, authDir));
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export function getPrimaryIdentityId(identity: WhatsAppIdentity | null | undefined): string | null {
|
|
163
|
-
return identity?.e164 || identity?.jid?.trim() || identity?.lid || null;
|
|
164
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { beforeEach, vi } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
type AsyncMock,
|
|
4
|
-
loadConfigMock,
|
|
5
|
-
readAllowFromStoreMock,
|
|
6
|
-
resetPairingSecurityMocks,
|
|
7
|
-
upsertPairingRequestMock,
|
|
8
|
-
} from "../pairing-security.test-harness.js";
|
|
9
|
-
|
|
10
|
-
export const sendMessageMock = vi.fn() as AsyncMock;
|
|
11
|
-
export { readAllowFromStoreMock, upsertPairingRequestMock };
|
|
12
|
-
|
|
13
|
-
let config: Record<string, unknown> = {};
|
|
14
|
-
|
|
15
|
-
export function setAccessControlTestConfig(next: Record<string, unknown>): void {
|
|
16
|
-
config = next;
|
|
17
|
-
loadConfigMock.mockReturnValue(config);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function getAccessControlTestConfig(): Record<string, unknown> {
|
|
21
|
-
return config;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function setupAccessControlTestHarness(): void {
|
|
25
|
-
beforeEach(() => {
|
|
26
|
-
config = {
|
|
27
|
-
channels: {
|
|
28
|
-
whatsapp: {
|
|
29
|
-
dmPolicy: "pairing",
|
|
30
|
-
allowFrom: [],
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
sendMessageMock.mockReset().mockResolvedValue(undefined);
|
|
35
|
-
resetPairingSecurityMocks(config);
|
|
36
|
-
});
|
|
37
|
-
}
|
|
@@ -1,375 +0,0 @@
|
|
|
1
|
-
import { beforeAll, describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
readAllowFromStoreMock,
|
|
4
|
-
sendMessageMock,
|
|
5
|
-
getAccessControlTestConfig,
|
|
6
|
-
setAccessControlTestConfig,
|
|
7
|
-
setupAccessControlTestHarness,
|
|
8
|
-
upsertPairingRequestMock,
|
|
9
|
-
} from "./access-control.test-harness.js";
|
|
10
|
-
|
|
11
|
-
setupAccessControlTestHarness();
|
|
12
|
-
let checkInboundAccessControl: typeof import("./access-control.js").checkInboundAccessControl;
|
|
13
|
-
let resolveWhatsAppCommandAuthorized: typeof import("../inbound-policy.js").resolveWhatsAppCommandAuthorized;
|
|
14
|
-
|
|
15
|
-
beforeAll(async () => {
|
|
16
|
-
({ checkInboundAccessControl } = await import("./access-control.js"));
|
|
17
|
-
({ resolveWhatsAppCommandAuthorized } = await import("../inbound-policy.js"));
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
async function checkUnauthorizedWorkDmSender() {
|
|
21
|
-
return checkInboundAccessControl({
|
|
22
|
-
cfg: getAccessControlTestConfig() as never,
|
|
23
|
-
accountId: "work",
|
|
24
|
-
from: "+15550001111",
|
|
25
|
-
selfE164: "+15550009999",
|
|
26
|
-
senderE164: "+15550001111",
|
|
27
|
-
group: false,
|
|
28
|
-
pushName: "Stranger",
|
|
29
|
-
isFromMe: false,
|
|
30
|
-
sock: { sendMessage: sendMessageMock },
|
|
31
|
-
remoteJid: "15550001111@s.whatsapp.net",
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function expectSilentlyBlocked(result: { allowed: boolean }) {
|
|
36
|
-
expect(result.allowed).toBe(false);
|
|
37
|
-
expect(upsertPairingRequestMock).not.toHaveBeenCalled();
|
|
38
|
-
expect(sendMessageMock).not.toHaveBeenCalled();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async function checkCommandAuthorizedForDm(params: {
|
|
42
|
-
cfg: Record<string, unknown>;
|
|
43
|
-
accountId?: string;
|
|
44
|
-
from?: string;
|
|
45
|
-
senderE164?: string;
|
|
46
|
-
selfE164?: string;
|
|
47
|
-
}) {
|
|
48
|
-
return await resolveWhatsAppCommandAuthorized({
|
|
49
|
-
cfg: params.cfg as never,
|
|
50
|
-
msg: {
|
|
51
|
-
accountId: params.accountId ?? "work",
|
|
52
|
-
chatType: "direct",
|
|
53
|
-
from: params.from ?? "+15550001111",
|
|
54
|
-
senderE164: params.senderE164 ?? params.from ?? "+15550001111",
|
|
55
|
-
selfE164: params.selfE164 ?? "+15550009999",
|
|
56
|
-
body: "/status",
|
|
57
|
-
to: params.selfE164 ?? "+15550009999",
|
|
58
|
-
} as never,
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async function checkCommandAuthorizedForGroup(params: {
|
|
63
|
-
cfg: Record<string, unknown>;
|
|
64
|
-
accountId?: string;
|
|
65
|
-
from?: string;
|
|
66
|
-
senderE164?: string;
|
|
67
|
-
selfE164?: string;
|
|
68
|
-
}) {
|
|
69
|
-
return await resolveWhatsAppCommandAuthorized({
|
|
70
|
-
cfg: params.cfg as never,
|
|
71
|
-
msg: {
|
|
72
|
-
accountId: params.accountId ?? "work",
|
|
73
|
-
chatType: "group",
|
|
74
|
-
from: params.from ?? "120363401234567890@g.us",
|
|
75
|
-
conversationId: params.from ?? "120363401234567890@g.us",
|
|
76
|
-
chatId: params.from ?? "120363401234567890@g.us",
|
|
77
|
-
senderE164: params.senderE164 ?? "+15550001111",
|
|
78
|
-
selfE164: params.selfE164 ?? "+15550009999",
|
|
79
|
-
body: "/status",
|
|
80
|
-
to: params.selfE164 ?? "+15550009999",
|
|
81
|
-
} as never,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
describe("checkInboundAccessControl pairing grace", () => {
|
|
86
|
-
async function runPairingGraceCase(messageTimestampMs: number) {
|
|
87
|
-
const connectedAtMs = 1_000_000;
|
|
88
|
-
return await checkInboundAccessControl({
|
|
89
|
-
cfg: getAccessControlTestConfig() as never,
|
|
90
|
-
accountId: "default",
|
|
91
|
-
from: "+15550001111",
|
|
92
|
-
selfE164: "+15550009999",
|
|
93
|
-
senderE164: "+15550001111",
|
|
94
|
-
group: false,
|
|
95
|
-
pushName: "Sam",
|
|
96
|
-
isFromMe: false,
|
|
97
|
-
messageTimestampMs,
|
|
98
|
-
connectedAtMs,
|
|
99
|
-
pairingGraceMs: 30_000,
|
|
100
|
-
sock: { sendMessage: sendMessageMock },
|
|
101
|
-
remoteJid: "15550001111@s.whatsapp.net",
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
it("suppresses pairing replies for historical DMs on connect", async () => {
|
|
106
|
-
const result = await runPairingGraceCase(1_000_000 - 31_000);
|
|
107
|
-
|
|
108
|
-
expect(result.allowed).toBe(false);
|
|
109
|
-
expect(upsertPairingRequestMock).not.toHaveBeenCalled();
|
|
110
|
-
expect(sendMessageMock).not.toHaveBeenCalled();
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it("sends pairing replies for live DMs", async () => {
|
|
114
|
-
const result = await runPairingGraceCase(1_000_000 - 10_000);
|
|
115
|
-
|
|
116
|
-
expect(result.allowed).toBe(false);
|
|
117
|
-
expect(upsertPairingRequestMock).toHaveBeenCalled();
|
|
118
|
-
expect(sendMessageMock).toHaveBeenCalled();
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe("WhatsApp dmPolicy precedence", () => {
|
|
123
|
-
it("uses account-level dmPolicy instead of channel-level (#8736)", async () => {
|
|
124
|
-
// Channel-level says "pairing" but the account-level says "allowlist".
|
|
125
|
-
// The account-level override should take precedence, so an unauthorized
|
|
126
|
-
// sender should be blocked silently (no pairing reply).
|
|
127
|
-
const cfg = {
|
|
128
|
-
channels: {
|
|
129
|
-
whatsapp: {
|
|
130
|
-
dmPolicy: "pairing",
|
|
131
|
-
accounts: {
|
|
132
|
-
work: {
|
|
133
|
-
dmPolicy: "allowlist",
|
|
134
|
-
allowFrom: ["+15559999999"],
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
};
|
|
140
|
-
setAccessControlTestConfig(cfg);
|
|
141
|
-
|
|
142
|
-
const result = await checkUnauthorizedWorkDmSender();
|
|
143
|
-
const commandAuthorized = await checkCommandAuthorizedForDm({ cfg });
|
|
144
|
-
expectSilentlyBlocked(result);
|
|
145
|
-
expect(commandAuthorized).toBe(false);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it("inherits channel-level dmPolicy when account-level dmPolicy is unset", async () => {
|
|
149
|
-
// Account has allowFrom set, but no dmPolicy override. Should inherit the channel default.
|
|
150
|
-
// With dmPolicy=allowlist, unauthorized senders are silently blocked.
|
|
151
|
-
const cfg = {
|
|
152
|
-
channels: {
|
|
153
|
-
whatsapp: {
|
|
154
|
-
dmPolicy: "allowlist",
|
|
155
|
-
accounts: {
|
|
156
|
-
work: {
|
|
157
|
-
allowFrom: ["+15559999999"],
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
|
-
},
|
|
162
|
-
};
|
|
163
|
-
setAccessControlTestConfig(cfg);
|
|
164
|
-
|
|
165
|
-
const result = await checkUnauthorizedWorkDmSender();
|
|
166
|
-
const commandAuthorized = await checkCommandAuthorizedForDm({ cfg });
|
|
167
|
-
expectSilentlyBlocked(result);
|
|
168
|
-
expect(commandAuthorized).toBe(false);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it("does not merge persisted pairing approvals in allowlist mode", async () => {
|
|
172
|
-
const cfg = {
|
|
173
|
-
channels: {
|
|
174
|
-
whatsapp: {
|
|
175
|
-
dmPolicy: "allowlist",
|
|
176
|
-
accounts: {
|
|
177
|
-
work: {
|
|
178
|
-
allowFrom: ["+15559999999"],
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
};
|
|
184
|
-
setAccessControlTestConfig(cfg);
|
|
185
|
-
readAllowFromStoreMock.mockResolvedValue(["+15550001111"]);
|
|
186
|
-
|
|
187
|
-
const result = await checkUnauthorizedWorkDmSender();
|
|
188
|
-
const commandAuthorized = await checkCommandAuthorizedForDm({ cfg });
|
|
189
|
-
|
|
190
|
-
expectSilentlyBlocked(result);
|
|
191
|
-
expect(commandAuthorized).toBe(false);
|
|
192
|
-
expect(readAllowFromStoreMock).not.toHaveBeenCalled();
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
it("always allows same-phone DMs even when allowFrom is restrictive", async () => {
|
|
196
|
-
const cfg = {
|
|
197
|
-
channels: {
|
|
198
|
-
whatsapp: {
|
|
199
|
-
dmPolicy: "pairing",
|
|
200
|
-
allowFrom: ["+15550001111"],
|
|
201
|
-
},
|
|
202
|
-
},
|
|
203
|
-
};
|
|
204
|
-
setAccessControlTestConfig(cfg);
|
|
205
|
-
|
|
206
|
-
const result = await checkInboundAccessControl({
|
|
207
|
-
cfg: getAccessControlTestConfig() as never,
|
|
208
|
-
accountId: "default",
|
|
209
|
-
from: "+15550009999",
|
|
210
|
-
selfE164: "+15550009999",
|
|
211
|
-
senderE164: "+15550009999",
|
|
212
|
-
group: false,
|
|
213
|
-
pushName: "Owner",
|
|
214
|
-
isFromMe: false,
|
|
215
|
-
sock: { sendMessage: sendMessageMock },
|
|
216
|
-
remoteJid: "15550009999@s.whatsapp.net",
|
|
217
|
-
});
|
|
218
|
-
const commandAuthorized = await checkCommandAuthorizedForDm({
|
|
219
|
-
cfg,
|
|
220
|
-
accountId: "default",
|
|
221
|
-
from: "+15550009999",
|
|
222
|
-
senderE164: "+15550009999",
|
|
223
|
-
selfE164: "+15550009999",
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
expect(result.allowed).toBe(true);
|
|
227
|
-
expect(commandAuthorized).toBe(true);
|
|
228
|
-
expect(upsertPairingRequestMock).not.toHaveBeenCalled();
|
|
229
|
-
expect(sendMessageMock).not.toHaveBeenCalled();
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
it("allows DMs from generic message sender access groups", async () => {
|
|
233
|
-
const cfg = {
|
|
234
|
-
accessGroups: {
|
|
235
|
-
owners: {
|
|
236
|
-
type: "message.senders",
|
|
237
|
-
members: {
|
|
238
|
-
whatsapp: ["+15550001111"],
|
|
239
|
-
},
|
|
240
|
-
},
|
|
241
|
-
},
|
|
242
|
-
channels: {
|
|
243
|
-
whatsapp: {
|
|
244
|
-
dmPolicy: "allowlist",
|
|
245
|
-
accounts: {
|
|
246
|
-
work: {
|
|
247
|
-
allowFrom: ["accessGroup:owners"],
|
|
248
|
-
},
|
|
249
|
-
},
|
|
250
|
-
},
|
|
251
|
-
},
|
|
252
|
-
};
|
|
253
|
-
setAccessControlTestConfig(cfg);
|
|
254
|
-
|
|
255
|
-
const result = await checkInboundAccessControl({
|
|
256
|
-
cfg: getAccessControlTestConfig() as never,
|
|
257
|
-
accountId: "work",
|
|
258
|
-
from: "+15550001111",
|
|
259
|
-
selfE164: "+15550009999",
|
|
260
|
-
senderE164: "+15550001111",
|
|
261
|
-
group: false,
|
|
262
|
-
pushName: "Sam",
|
|
263
|
-
isFromMe: false,
|
|
264
|
-
sock: { sendMessage: sendMessageMock },
|
|
265
|
-
remoteJid: "15550001111@s.whatsapp.net",
|
|
266
|
-
});
|
|
267
|
-
const commandAuthorized = await checkCommandAuthorizedForDm({ cfg });
|
|
268
|
-
|
|
269
|
-
expect(result.allowed).toBe(true);
|
|
270
|
-
expect(commandAuthorized).toBe(true);
|
|
271
|
-
expect(upsertPairingRequestMock).not.toHaveBeenCalled();
|
|
272
|
-
expect(sendMessageMock).not.toHaveBeenCalled();
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
it("allows group messages from generic message sender access groups", async () => {
|
|
276
|
-
const cfg = {
|
|
277
|
-
accessGroups: {
|
|
278
|
-
operators: {
|
|
279
|
-
type: "message.senders",
|
|
280
|
-
members: {
|
|
281
|
-
whatsapp: ["+15550001111"],
|
|
282
|
-
},
|
|
283
|
-
},
|
|
284
|
-
},
|
|
285
|
-
channels: {
|
|
286
|
-
whatsapp: {
|
|
287
|
-
dmPolicy: "allowlist",
|
|
288
|
-
groupPolicy: "allowlist",
|
|
289
|
-
groupAllowFrom: ["accessGroup:operators"],
|
|
290
|
-
accounts: {
|
|
291
|
-
work: {
|
|
292
|
-
allowFrom: ["+15559999999"],
|
|
293
|
-
},
|
|
294
|
-
},
|
|
295
|
-
},
|
|
296
|
-
},
|
|
297
|
-
};
|
|
298
|
-
setAccessControlTestConfig(cfg);
|
|
299
|
-
|
|
300
|
-
const result = await checkInboundAccessControl({
|
|
301
|
-
cfg: getAccessControlTestConfig() as never,
|
|
302
|
-
accountId: "work",
|
|
303
|
-
from: "120363401234567890@g.us",
|
|
304
|
-
selfE164: "+15550009999",
|
|
305
|
-
senderE164: "+15550001111",
|
|
306
|
-
group: true,
|
|
307
|
-
pushName: "Sam",
|
|
308
|
-
isFromMe: false,
|
|
309
|
-
sock: { sendMessage: sendMessageMock },
|
|
310
|
-
remoteJid: "120363401234567890@g.us",
|
|
311
|
-
});
|
|
312
|
-
const commandAuthorized = await checkCommandAuthorizedForGroup({ cfg });
|
|
313
|
-
|
|
314
|
-
expect(result.allowed).toBe(true);
|
|
315
|
-
expect(commandAuthorized).toBe(true);
|
|
316
|
-
expect(upsertPairingRequestMock).not.toHaveBeenCalled();
|
|
317
|
-
expect(sendMessageMock).not.toHaveBeenCalled();
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
it("does not broaden self-chat mode to every paired DM when allowFrom is empty", async () => {
|
|
321
|
-
const cfg = {
|
|
322
|
-
channels: {
|
|
323
|
-
whatsapp: {
|
|
324
|
-
dmPolicy: "pairing",
|
|
325
|
-
allowFrom: [],
|
|
326
|
-
},
|
|
327
|
-
},
|
|
328
|
-
};
|
|
329
|
-
setAccessControlTestConfig(cfg);
|
|
330
|
-
|
|
331
|
-
const result = await checkInboundAccessControl({
|
|
332
|
-
cfg: getAccessControlTestConfig() as never,
|
|
333
|
-
accountId: "default",
|
|
334
|
-
from: "+15550001111",
|
|
335
|
-
selfE164: "+15550009999",
|
|
336
|
-
senderE164: "+15550001111",
|
|
337
|
-
group: false,
|
|
338
|
-
pushName: "Sam",
|
|
339
|
-
isFromMe: false,
|
|
340
|
-
sock: { sendMessage: sendMessageMock },
|
|
341
|
-
remoteJid: "15550001111@s.whatsapp.net",
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
expect(result.allowed).toBe(false);
|
|
345
|
-
expect(result.isSelfChat).toBe(false);
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
it("treats same-phone DMs as self-chat only when explicitly configured", async () => {
|
|
349
|
-
const cfg = {
|
|
350
|
-
channels: {
|
|
351
|
-
whatsapp: {
|
|
352
|
-
dmPolicy: "pairing",
|
|
353
|
-
allowFrom: ["+15550009999"],
|
|
354
|
-
},
|
|
355
|
-
},
|
|
356
|
-
};
|
|
357
|
-
setAccessControlTestConfig(cfg);
|
|
358
|
-
|
|
359
|
-
const result = await checkInboundAccessControl({
|
|
360
|
-
cfg: getAccessControlTestConfig() as never,
|
|
361
|
-
accountId: "default",
|
|
362
|
-
from: "+15550009999",
|
|
363
|
-
selfE164: "+15550009999",
|
|
364
|
-
senderE164: "+15550009999",
|
|
365
|
-
group: false,
|
|
366
|
-
pushName: "Owner",
|
|
367
|
-
isFromMe: false,
|
|
368
|
-
sock: { sendMessage: sendMessageMock },
|
|
369
|
-
remoteJid: "15550009999@s.whatsapp.net",
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
expect(result.allowed).toBe(true);
|
|
373
|
-
expect(result.isSelfChat).toBe(true);
|
|
374
|
-
});
|
|
375
|
-
});
|