mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-09 03:03:24 +08:00
Revert "fix(whatsapp): handle group mentions and caller allowlists"
This reverts commit 9664e85599.
This commit is contained in:
parent
a9bb0ed3ba
commit
25d0b2fb0b
13 changed files with 215 additions and 564 deletions
|
|
@ -14,7 +14,6 @@ import {
|
|||
WhatsappAccountCard,
|
||||
WhatsappSettingsTab,
|
||||
} from '../../../plugin-src/client/channels/whatsapp/index.js';
|
||||
import { normalizeSnapshot } from '../../../plugin-src/client/channels/whatsapp/api.js';
|
||||
import { en, setImTranslator } from '../../../plugin-src/client/i18n.js';
|
||||
|
||||
const { act, create } = TestRenderer;
|
||||
|
|
@ -80,35 +79,13 @@ test('WhatsApp account card uses the unified compact channel layout', () => {
|
|||
assert.match(markup, /role="status"[^>]*>测试消息已发送/);
|
||||
});
|
||||
|
||||
test('WhatsApp client keeps private and group number lists separate', () => {
|
||||
const snapshot = normalizeSnapshot({
|
||||
bots: [{
|
||||
botId: 'whatsapp_test',
|
||||
accessPolicy: {
|
||||
accessMode: 'open',
|
||||
allowedNumbers: ['16505550999'],
|
||||
groupAllowedNumbers: ['33620607448'],
|
||||
},
|
||||
}],
|
||||
});
|
||||
assert.deepEqual(snapshot.bots[0].accessPolicy, {
|
||||
accessMode: 'open',
|
||||
allowedNumbers: ['16505550999'],
|
||||
groupAllowedNumbers: ['33620607448'],
|
||||
});
|
||||
});
|
||||
|
||||
test('WhatsApp access settings save a normalized selected-contact allowlist', async () => {
|
||||
const saved = [];
|
||||
let renderer;
|
||||
await act(async () => {
|
||||
renderer = create(React.createElement(WhatsappAccessSettings, {
|
||||
account: {
|
||||
accessPolicy: {
|
||||
accessMode: 'self-only',
|
||||
allowedNumbers: [],
|
||||
groupAllowedNumbers: ['33620607448'],
|
||||
},
|
||||
accessPolicy: { accessMode: 'self-only', allowedNumbers: [] },
|
||||
},
|
||||
onSave: async (value) => saved.push(value),
|
||||
}));
|
||||
|
|
@ -130,54 +107,16 @@ test('WhatsApp access settings save a normalized selected-contact allowlist', as
|
|||
assert.deepEqual(saved, [{
|
||||
accessMode: 'private-allowlist',
|
||||
allowedNumbers: ['16505550999'],
|
||||
groupAllowedNumbers: ['33620607448'],
|
||||
}]);
|
||||
await act(async () => { renderer.unmount(); });
|
||||
});
|
||||
|
||||
test('WhatsApp access settings save a normalized open-mode group caller allowlist', async () => {
|
||||
const saved = [];
|
||||
test('WhatsApp access settings only show the allowlist for selected contacts', async () => {
|
||||
let renderer;
|
||||
await act(async () => {
|
||||
renderer = create(React.createElement(WhatsappAccessSettings, {
|
||||
account: {
|
||||
accessPolicy: {
|
||||
accessMode: 'open',
|
||||
allowedNumbers: ['16505550000'],
|
||||
groupAllowedNumbers: [],
|
||||
},
|
||||
},
|
||||
onSave: async (value) => saved.push(value),
|
||||
}));
|
||||
});
|
||||
const textarea = renderer.root.findByProps({
|
||||
'aria-label': '允许在群聊中呼叫机器人的 WhatsApp 电话号码',
|
||||
});
|
||||
await act(async () => {
|
||||
textarea.props.onChange({ target: { value: '+16505550999\n16505550999' } });
|
||||
});
|
||||
await act(async () => {
|
||||
renderer.root.findByType('form').props.onSubmit({ preventDefault() {} });
|
||||
await flushMicrotasks();
|
||||
});
|
||||
assert.deepEqual(saved, [{
|
||||
accessMode: 'open',
|
||||
allowedNumbers: ['16505550000'],
|
||||
groupAllowedNumbers: ['16505550999'],
|
||||
}]);
|
||||
await act(async () => { renderer.unmount(); });
|
||||
});
|
||||
|
||||
test('WhatsApp access settings show mode-specific number allowlists', async () => {
|
||||
let renderer;
|
||||
await act(async () => {
|
||||
renderer = create(React.createElement(WhatsappAccessSettings, {
|
||||
account: {
|
||||
accessPolicy: {
|
||||
accessMode: 'self-only',
|
||||
allowedNumbers: ['16505550999'],
|
||||
groupAllowedNumbers: ['33620607448'],
|
||||
},
|
||||
accessPolicy: { accessMode: 'self-only', allowedNumbers: ['16505550999'] },
|
||||
},
|
||||
onSave: async () => {},
|
||||
}));
|
||||
|
|
@ -186,25 +125,16 @@ test('WhatsApp access settings show mode-specific number allowlists', async () =
|
|||
const allowlistFields = () => renderer.root.findAllByProps({
|
||||
'aria-label': '允许私聊的 WhatsApp 电话号码',
|
||||
});
|
||||
const groupCallerFields = () => renderer.root.findAllByProps({
|
||||
'aria-label': '允许在群聊中呼叫机器人的 WhatsApp 电话号码',
|
||||
});
|
||||
|
||||
assert.equal(allowlistFields().length, 0);
|
||||
assert.equal(groupCallerFields().length, 0);
|
||||
await act(async () => {
|
||||
select.props.onChange({ target: { value: 'private-allowlist' } });
|
||||
});
|
||||
assert.equal(allowlistFields().length, 1);
|
||||
assert.equal(groupCallerFields().length, 0);
|
||||
assert.equal(allowlistFields()[0].props.value, '16505550999');
|
||||
await act(async () => {
|
||||
select.props.onChange({ target: { value: 'open' } });
|
||||
});
|
||||
assert.equal(allowlistFields().length, 0);
|
||||
assert.equal(groupCallerFields().length, 1);
|
||||
assert.equal(groupCallerFields()[0].props.value, '33620607448');
|
||||
assert.match(textOf(renderer.root), /留空表示所有群成员/);
|
||||
await act(async () => { renderer.unmount(); });
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import {
|
|||
} from '../../../plugin-src/host/channels/whatsapp/rpc.mjs';
|
||||
|
||||
const ACCOUNT_JID = '16505550123@s.whatsapp.net';
|
||||
const ACCOUNT_LID = '123456789012345@lid';
|
||||
const AUTH_DIRECTORY = '7fe8c17e-4fb7-4c5b-a9dc-c36525575dd1';
|
||||
|
||||
function deferred() {
|
||||
|
|
@ -141,7 +140,6 @@ function linkedConfig(overrides = {}) {
|
|||
name: 'Harness WhatsApp',
|
||||
accessMode: WHATSAPP_ACCESS_MODES.open,
|
||||
allowedNumbers: [],
|
||||
groupAllowedNumbers: [],
|
||||
createdAt: new Date().toISOString(),
|
||||
connectedAt: new Date().toISOString(),
|
||||
...overrides,
|
||||
|
|
@ -165,31 +163,19 @@ test('WhatsApp migrates existing bots to self-only mode and validates access pol
|
|||
const legacy = linkedConfig();
|
||||
delete legacy.accessMode;
|
||||
delete legacy.allowedNumbers;
|
||||
delete legacy.groupAllowedNumbers;
|
||||
await writeFile(path, `${JSON.stringify({ version: 2, bots: [legacy] })}\n`);
|
||||
const store = await new WhatsappConfigStore(path).load();
|
||||
assert.deepEqual(store.get(legacy.botId), {
|
||||
...legacy,
|
||||
accessMode: WHATSAPP_ACCESS_MODES.selfOnly,
|
||||
allowedNumbers: [],
|
||||
groupAllowedNumbers: [],
|
||||
});
|
||||
assert.deepEqual(normalizeWhatsappAccessPolicy({
|
||||
accessMode: WHATSAPP_ACCESS_MODES.privateAllowlist,
|
||||
allowedNumbers: ['+16505550999', '16505550999'],
|
||||
groupAllowedNumbers: ['+33620607448', '33620607448'],
|
||||
}), {
|
||||
accessMode: WHATSAPP_ACCESS_MODES.privateAllowlist,
|
||||
allowedNumbers: ['16505550999'],
|
||||
groupAllowedNumbers: ['33620607448'],
|
||||
});
|
||||
assert.deepEqual(normalizeWhatsappAccessPolicy({
|
||||
accessMode: WHATSAPP_ACCESS_MODES.open,
|
||||
allowedNumbers: ['16505550999'],
|
||||
}), {
|
||||
accessMode: WHATSAPP_ACCESS_MODES.open,
|
||||
allowedNumbers: ['16505550999'],
|
||||
groupAllowedNumbers: [],
|
||||
});
|
||||
assert.throws(() => normalizeWhatsappAccessPolicy({
|
||||
accessMode: 'compatible',
|
||||
|
|
@ -414,57 +400,7 @@ test('WhatsApp normalizes direct, linked-account, and explicitly mentioned group
|
|||
}, ACCOUNT_JID), null);
|
||||
});
|
||||
|
||||
test('WhatsApp recognizes the linked account LID in group mentions and replies', () => {
|
||||
const lidMention = normalizeWhatsappMessage({
|
||||
key: {
|
||||
remoteJid: '120363000000000002@g.us',
|
||||
participant: '16505550999@s.whatsapp.net',
|
||||
id: 'group-lid-mention',
|
||||
fromMe: false,
|
||||
},
|
||||
message: {
|
||||
extendedTextMessage: {
|
||||
text: '@Harness question',
|
||||
contextInfo: { mentionedJid: [`${ACCOUNT_LID.split('@')[0]}:9@lid`] },
|
||||
},
|
||||
},
|
||||
}, ACCOUNT_JID, { accountAliases: [ACCOUNT_LID] });
|
||||
assert.equal(lidMention.addressed, true);
|
||||
|
||||
const lidReply = normalizeWhatsappMessage({
|
||||
key: {
|
||||
remoteJid: '120363000000000002@g.us',
|
||||
participant: '16505550999@s.whatsapp.net',
|
||||
id: 'group-lid-reply',
|
||||
fromMe: false,
|
||||
},
|
||||
message: {
|
||||
extendedTextMessage: {
|
||||
text: 'reply to the linked account',
|
||||
contextInfo: { participant: `${ACCOUNT_LID.split('@')[0]}:9@lid` },
|
||||
},
|
||||
},
|
||||
}, ACCOUNT_JID, { accountAliases: [ACCOUNT_LID] });
|
||||
assert.equal(lidReply.addressed, true);
|
||||
|
||||
const unrelatedLidMention = normalizeWhatsappMessage({
|
||||
key: {
|
||||
remoteJid: '120363000000000002@g.us',
|
||||
participant: '16505550999@s.whatsapp.net',
|
||||
id: 'group-other-lid-mention',
|
||||
fromMe: false,
|
||||
},
|
||||
message: {
|
||||
extendedTextMessage: {
|
||||
text: '@SomeoneElse question',
|
||||
contextInfo: { mentionedJid: ['999999999999999@lid'] },
|
||||
},
|
||||
},
|
||||
}, ACCOUNT_JID, { accountAliases: [ACCOUNT_LID] });
|
||||
assert.equal(unrelatedLidMention.addressed, false);
|
||||
});
|
||||
|
||||
test('WhatsApp access modes keep existing behavior and optionally restrict open group callers', () => {
|
||||
test('WhatsApp access modes allow self-chat, selected contacts, or the existing open behavior', () => {
|
||||
const direct = normalizeWhatsappMessage({
|
||||
key: {
|
||||
remoteJid: '987654321098765@lid',
|
||||
|
|
@ -495,16 +431,6 @@ test('WhatsApp access modes keep existing behavior and optionally restrict open
|
|||
},
|
||||
message: { conversation: 'hello from the linked account' },
|
||||
}, ACCOUNT_JID);
|
||||
const lidAddressedGroup = normalizeWhatsappMessage({
|
||||
key: {
|
||||
remoteJid: '120363000000000002@g.us',
|
||||
participant: '987654321098765@lid',
|
||||
participantAlt: '16505550999@s.whatsapp.net',
|
||||
id: 'access-lid-group',
|
||||
fromMe: false,
|
||||
},
|
||||
message: { conversation: 'hello from a LID-addressed member' },
|
||||
}, ACCOUNT_JID);
|
||||
|
||||
assert.equal(whatsappInboundAllowed(selfChat), true);
|
||||
assert.equal(whatsappInboundAllowed(direct), false);
|
||||
|
|
@ -519,34 +445,10 @@ test('WhatsApp access modes keep existing behavior and optionally restrict open
|
|||
allowedNumbers: new Set(['16505550000']),
|
||||
}), false);
|
||||
assert.equal(whatsappInboundAllowed(group, {
|
||||
accessMode: WHATSAPP_ACCESS_MODES.privateAllowlist,
|
||||
allowedNumbers: new Set(['16505550999']),
|
||||
}), false);
|
||||
assert.equal(whatsappInboundAllowed(direct, {
|
||||
accessMode: WHATSAPP_ACCESS_MODES.open,
|
||||
allowedNumbers: new Set(['16505550000']),
|
||||
groupAllowedNumbers: new Set(['16505550001']),
|
||||
}), true);
|
||||
assert.equal(whatsappInboundAllowed(group, {
|
||||
accessMode: WHATSAPP_ACCESS_MODES.open,
|
||||
}), true);
|
||||
assert.equal(whatsappInboundAllowed(group, {
|
||||
accessMode: WHATSAPP_ACCESS_MODES.open,
|
||||
allowedNumbers: new Set(['16505550000']),
|
||||
groupAllowedNumbers: new Set(['16505550999']),
|
||||
}), true);
|
||||
assert.equal(whatsappInboundAllowed(group, {
|
||||
accessMode: WHATSAPP_ACCESS_MODES.open,
|
||||
allowedNumbers: new Set(['16505550999']),
|
||||
groupAllowedNumbers: new Set(['16505550000']),
|
||||
}), false);
|
||||
assert.equal(whatsappInboundAllowed(lidAddressedGroup, {
|
||||
accessMode: WHATSAPP_ACCESS_MODES.open,
|
||||
groupAllowedNumbers: new Set(['16505550999']),
|
||||
}), true);
|
||||
assert.equal(whatsappInboundAllowed(linkedAccountGroup, {
|
||||
accessMode: WHATSAPP_ACCESS_MODES.open,
|
||||
groupAllowedNumbers: new Set(['16505550000']),
|
||||
}), true);
|
||||
});
|
||||
|
||||
|
|
@ -759,11 +661,7 @@ test('WhatsApp runtime filters messages before the bridge and applies policy upd
|
|||
assert.equal(runtime.status.ready, true);
|
||||
assert.equal(runtime.status.messagesRejected, 1);
|
||||
assert.equal(calls.length, 0);
|
||||
runtime.setAccessPolicy({
|
||||
accessMode: WHATSAPP_ACCESS_MODES.open,
|
||||
allowedNumbers: [],
|
||||
groupAllowedNumbers: [],
|
||||
});
|
||||
runtime.setAccessPolicy({ accessMode: WHATSAPP_ACCESS_MODES.open, allowedNumbers: [] });
|
||||
await callbacks.onMessage({
|
||||
key: { remoteJid: '16505550999@s.whatsapp.net', id: 'direct-3', fromMe: false },
|
||||
message: { conversation: 'hello again' },
|
||||
|
|
@ -773,95 +671,6 @@ test('WhatsApp runtime filters messages before the bridge and applies policy upd
|
|||
await runtime.stop();
|
||||
});
|
||||
|
||||
test('WhatsApp open mode uses the account LID and restricts group callers by phone number', async (t) => {
|
||||
const groupJid = '120363000000000003@g.us';
|
||||
let callbacks;
|
||||
let askCount = 0;
|
||||
const sent = [];
|
||||
const socket = {
|
||||
user: {
|
||||
id: '16505550123:9@s.whatsapp.net',
|
||||
lid: `${ACCOUNT_LID.split('@')[0]}:9@lid`,
|
||||
name: 'Harness WhatsApp',
|
||||
},
|
||||
sendPresenceUpdate: async () => {},
|
||||
readMessages: async () => {},
|
||||
sendMessage: async (jid, content, options = {}) => {
|
||||
sent.push({ jid, content, options });
|
||||
return { key: { id: options.messageId ?? 'group-lid-reply' } };
|
||||
},
|
||||
};
|
||||
const runtime = new WhatsappRuntime({
|
||||
config: linkedConfig({
|
||||
accessMode: WHATSAPP_ACCESS_MODES.open,
|
||||
allowedNumbers: ['16505550000'],
|
||||
groupAllowedNumbers: ['16505550999'],
|
||||
}),
|
||||
authDir: '/tmp/test-whatsapp-lid-group-mention',
|
||||
harness: {
|
||||
ensureRunning: async () => {},
|
||||
sessionExists: async () => true,
|
||||
ask: async () => {
|
||||
askCount += 1;
|
||||
return 'Harness LID answer';
|
||||
},
|
||||
},
|
||||
state: artifactState('session-lid-group-mention'),
|
||||
createSession: async (options) => {
|
||||
callbacks = options;
|
||||
return {
|
||||
socket,
|
||||
ready: Promise.resolve({ accountJid: ACCOUNT_JID, name: 'Harness WhatsApp' }),
|
||||
close: async () => {},
|
||||
logout: async () => {},
|
||||
};
|
||||
},
|
||||
});
|
||||
t.after(() => runtime.stop());
|
||||
await runtime.start();
|
||||
|
||||
const mentioned = {
|
||||
key: {
|
||||
remoteJid: groupJid,
|
||||
participant: '987654321098765@lid',
|
||||
participantAlt: '16505550999@s.whatsapp.net',
|
||||
id: 'runtime-group-lid-mention',
|
||||
fromMe: false,
|
||||
},
|
||||
message: {
|
||||
extendedTextMessage: {
|
||||
text: '@Harness question',
|
||||
contextInfo: { mentionedJid: [ACCOUNT_LID] },
|
||||
},
|
||||
},
|
||||
};
|
||||
await callbacks.onMessage(mentioned, { socket });
|
||||
|
||||
assert.equal(askCount, 1);
|
||||
assert.ok(sent.some(({ jid, content }) => (
|
||||
jid === groupJid && content.text === 'Harness LID answer'
|
||||
)));
|
||||
|
||||
await callbacks.onMessage({
|
||||
key: {
|
||||
remoteJid: groupJid,
|
||||
participant: '999999999999999@lid',
|
||||
participantAlt: '16505550000@s.whatsapp.net',
|
||||
id: 'runtime-group-disallowed-caller',
|
||||
fromMe: false,
|
||||
},
|
||||
message: {
|
||||
extendedTextMessage: {
|
||||
text: '@Harness disallowed question',
|
||||
contextInfo: { mentionedJid: [ACCOUNT_LID] },
|
||||
},
|
||||
},
|
||||
}, { socket });
|
||||
|
||||
assert.equal(askCount, 1);
|
||||
assert.equal(runtime.status.messagesRejected, 1);
|
||||
});
|
||||
|
||||
test('WhatsApp open mode answers linked-account group messages without processing reply echoes', async (t) => {
|
||||
const groupJid = '120363000000000001@g.us';
|
||||
let callbacks;
|
||||
|
|
@ -1710,7 +1519,6 @@ test('WhatsApp QR controller and RPC keep the raw QR and linked identity host-on
|
|||
setAccessPolicy: (value) => appliedPolicies.push({
|
||||
accessMode: value.accessMode,
|
||||
allowedNumbers: value.allowedNumbers,
|
||||
groupAllowedNumbers: value.groupAllowedNumbers,
|
||||
}),
|
||||
}),
|
||||
deleteAuth: async (name) => deletedAuth.push(name),
|
||||
|
|
@ -1735,31 +1543,26 @@ test('WhatsApp QR controller and RPC keep the raw QR and linked identity host-on
|
|||
assert.deepEqual(status.value.bots[0].accessPolicy, {
|
||||
accessMode: WHATSAPP_ACCESS_MODES.selfOnly,
|
||||
allowedNumbers: [],
|
||||
groupAllowedNumbers: [],
|
||||
});
|
||||
assert.doesNotMatch(JSON.stringify(status.value), /16505550123@s\.whatsapp\.net|authDirectory/);
|
||||
const updated = await handler(WHATSAPP_ENDPOINTS.setAccessPolicy, {
|
||||
botId: status.value.bots[0].botId,
|
||||
accessMode: WHATSAPP_ACCESS_MODES.privateAllowlist,
|
||||
allowedNumbers: ['+16505550999'],
|
||||
groupAllowedNumbers: ['+33620607448'],
|
||||
});
|
||||
assert.equal(updated.ok, true);
|
||||
assert.deepEqual(updated.value.bots[0].accessPolicy, {
|
||||
accessMode: WHATSAPP_ACCESS_MODES.privateAllowlist,
|
||||
allowedNumbers: ['16505550999'],
|
||||
groupAllowedNumbers: ['33620607448'],
|
||||
});
|
||||
assert.deepEqual(appliedPolicies, [{
|
||||
accessMode: WHATSAPP_ACCESS_MODES.privateAllowlist,
|
||||
allowedNumbers: ['16505550999'],
|
||||
groupAllowedNumbers: ['33620607448'],
|
||||
}]);
|
||||
const invalidPolicy = await handler(WHATSAPP_ENDPOINTS.setAccessPolicy, {
|
||||
botId: status.value.bots[0].botId,
|
||||
accessMode: 'compatible',
|
||||
allowedNumbers: [],
|
||||
groupAllowedNumbers: [],
|
||||
});
|
||||
assert.equal(invalidPolicy.ok, false);
|
||||
assert.equal(invalidPolicy.error.code, 'bad-request');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue