mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-08 23:13:17 +08:00
Strip WhatsApp @bot LID tokens from inbound group text.
Mention triggers leave opaque LID digits in the body; remove those only, without injecting sender identity (use context enhancement when needed). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
d9edca4d5f
commit
e5e1e6573a
6 changed files with 138 additions and 52 deletions
4
FORK.md
4
FORK.md
|
|
@ -24,7 +24,7 @@ dsh plugin --profile web add -w "github:hansjone/dsh-im-ops"
|
|||
# 重启 dsh web
|
||||
```
|
||||
|
||||
包名:`dsh-im-ops@4.9.1-ops.2`(cordis id:`dsh-im-ops`)。
|
||||
包名:`dsh-im-ops@4.9.1-ops.3`(cordis id:`dsh-im-ops`)。
|
||||
|
||||
扫码态一般仍在 `~/.dsh/integrations/…`;换包后若异常,在 IM 设置里重新关联设备。
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ dsh plugin --profile web add -w "github:hansjone/dsh-im-ops"
|
|||
|
||||
2. **访问控制**仍由本 fork 持久化(`workspaces.json` 的 `accessPolicies`),设置 UI 与上游同构,运维可直接改白名单 / open 模式
|
||||
|
||||
3. **WhatsApp LID**:群参与者常为不透明 `@lid`,白名单只填手机号时会被静默拒绝。`4.9.1-ops.2` 用 Baileys LID→PN 映射扩展 sender 别名,并在 @ 提及匹配时同样解析;若仍被拒绝会回一句白名单提示
|
||||
3. **WhatsApp LID**:群参与者常为不透明 `@lid`,白名单只填手机号时会被静默拒绝。`4.9.1-ops.3` 用 Baileys LID→PN 映射扩展 sender 别名,并在 @ 提及匹配时同样解析;若仍被拒绝会回一句白名单提示
|
||||
|
||||
4. **主动群通告**继续用既有 delivery(`botId + targetId`),与入站 Session 策略独立
|
||||
|
||||
|
|
|
|||
|
|
@ -571,7 +571,7 @@ var React23 = __toESM(require("react"), 1);
|
|||
// package.json
|
||||
var package_default = {
|
||||
name: "dsh-im-ops",
|
||||
version: "4.9.1-ops.2",
|
||||
version: "4.9.1-ops.3",
|
||||
description: "Ops fork of dsh-im (all channels kept). Based on @xmanrui/dsh-im@4.9.1 \u2014 access/session policies owned here.",
|
||||
keywords: [
|
||||
"deepseek-harness",
|
||||
|
|
|
|||
56
lib/index.js
56
lib/index.js
File diff suppressed because one or more lines are too long
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "dsh-im-ops",
|
||||
"version": "4.9.1-ops.2",
|
||||
"version": "4.9.1-ops.3",
|
||||
"description": "Ops fork of dsh-im (all channels kept). Based on @xmanrui/dsh-im@4.9.1 — access/session policies owned here.",
|
||||
"keywords": [
|
||||
"deepseek-harness",
|
||||
|
|
|
|||
|
|
@ -76,6 +76,83 @@ async function lookupLidForPn(socket, pn) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect local-part tokens for the linked bot account (PN and LID).
|
||||
* Used only to strip trigger @mentions from inbound text — not context injection.
|
||||
* @param {string} accountJid
|
||||
* @param {string[]} mentionedJids
|
||||
* @param {string|null} accountLid
|
||||
* @returns {string[]}
|
||||
*/
|
||||
export function whatsappBotMentionTokens(accountJid, mentionedJids = [], accountLid = null) {
|
||||
const tokens = new Set();
|
||||
const add = (jid) => {
|
||||
if (typeof jid !== 'string' || !jid) return;
|
||||
const decoded = jidDecode(jid.trim());
|
||||
if (decoded?.user && /^\d+$/.test(decoded.user)) tokens.add(decoded.user);
|
||||
};
|
||||
add(accountJid);
|
||||
add(accountLid);
|
||||
for (const jid of mentionedJids) {
|
||||
if (typeof jid !== 'string' || !jid) continue;
|
||||
let matchesBot = false;
|
||||
try {
|
||||
matchesBot = areJidsSameUser(jid, accountJid) === true;
|
||||
} catch {
|
||||
matchesBot = false;
|
||||
}
|
||||
if (!matchesBot && accountLid) {
|
||||
try {
|
||||
matchesBot = areJidsSameUser(jid, accountLid) === true;
|
||||
} catch {
|
||||
matchesBot = false;
|
||||
}
|
||||
}
|
||||
if (matchesBot) add(jid);
|
||||
}
|
||||
return [...tokens];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove WhatsApp @bot trigger tokens from plain text (e.g. `@1627…` / leading LID).
|
||||
* Does not add sender identity — that belongs to optional context enhancement.
|
||||
* @param {string} text
|
||||
* @param {string[]} tokens
|
||||
* @returns {string}
|
||||
*/
|
||||
export function stripWhatsappBotMentionText(text, tokens) {
|
||||
if (typeof text !== 'string' || !text || !Array.isArray(tokens) || tokens.length === 0) {
|
||||
return typeof text === 'string' ? text : '';
|
||||
}
|
||||
let result = text;
|
||||
for (const token of tokens) {
|
||||
if (!/^\d{5,32}$/.test(token)) continue;
|
||||
const escaped = token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
result = result.replace(new RegExp(`@${escaped}\\b[\\u200e\\u200f\\s]*`, 'gu'), '');
|
||||
result = result.replace(new RegExp(`^${escaped}\\b[\\u200e\\u200f\\s]*`, 'u'), '');
|
||||
}
|
||||
return result.replace(/[ \t]{2,}/g, ' ').trim();
|
||||
}
|
||||
|
||||
function inboundMentionContext(rawMessage) {
|
||||
let current = rawMessage;
|
||||
for (let depth = 0; depth < 5 && current && typeof current === 'object'; depth += 1) {
|
||||
const context = current.extendedTextMessage?.contextInfo
|
||||
?? current.imageMessage?.contextInfo
|
||||
?? current.videoMessage?.contextInfo
|
||||
?? current.documentMessage?.contextInfo
|
||||
?? null;
|
||||
if (context) return context;
|
||||
const wrapper = ['ephemeralMessage', 'viewOnceMessage', 'documentWithCaptionMessage',
|
||||
'viewOnceMessageV2', 'viewOnceMessageV2Extension', 'editedMessage',
|
||||
'associatedChildMessage', 'groupStatusMessage', 'groupStatusMessageV2']
|
||||
.find((key) => current[key]?.message);
|
||||
if (!wrapper) return null;
|
||||
current = current[wrapper].message;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand inbound WhatsApp identities with PN/LID aliases and re-evaluate
|
||||
* group @mention against the linked account.
|
||||
|
|
@ -104,27 +181,12 @@ export async function enrichWhatsappInboundIdentities(message, raw, {
|
|||
if (pn) aliasIds.add(pn);
|
||||
}
|
||||
|
||||
const context = inboundMentionContext(raw?.message);
|
||||
const mentioned = Array.isArray(context?.mentionedJid) ? context.mentionedJid : [];
|
||||
const accountLid = await lookupLidForPn(socket, accountJid);
|
||||
|
||||
let addressed = message.addressed === true;
|
||||
if (message.kind === 'group' && addressed !== true) {
|
||||
const content = raw?.message;
|
||||
let current = content;
|
||||
let context = null;
|
||||
for (let depth = 0; depth < 5 && current && typeof current === 'object'; depth += 1) {
|
||||
context = current.extendedTextMessage?.contextInfo
|
||||
?? current.imageMessage?.contextInfo
|
||||
?? current.videoMessage?.contextInfo
|
||||
?? current.documentMessage?.contextInfo
|
||||
?? null;
|
||||
if (context) break;
|
||||
const wrapper = ['ephemeralMessage', 'viewOnceMessage', 'documentWithCaptionMessage',
|
||||
'viewOnceMessageV2', 'viewOnceMessageV2Extension', 'editedMessage',
|
||||
'associatedChildMessage', 'groupStatusMessage', 'groupStatusMessageV2']
|
||||
.find((key) => current[key]?.message);
|
||||
if (!wrapper) break;
|
||||
current = current[wrapper].message;
|
||||
}
|
||||
const mentioned = Array.isArray(context?.mentionedJid) ? context.mentionedJid : [];
|
||||
const accountLid = await lookupLidForPn(socket, accountJid);
|
||||
for (const jid of mentioned) {
|
||||
if (typeof jid !== 'string' || !jid) continue;
|
||||
try {
|
||||
|
|
@ -161,10 +223,14 @@ export async function enrichWhatsappInboundIdentities(message, raw, {
|
|||
}
|
||||
}
|
||||
|
||||
const botTokens = whatsappBotMentionTokens(accountJid, mentioned, accountLid);
|
||||
const content = stripWhatsappBotMentionText(message.content, botTokens);
|
||||
|
||||
aliasIds.delete(message.senderId);
|
||||
const senderAliasIds = [...aliasIds];
|
||||
return {
|
||||
...message,
|
||||
content,
|
||||
addressed,
|
||||
...(senderAliasIds.length > 0 ? { senderAliasIds } : {}),
|
||||
...(senderAliasIds[0] && !message.senderAlternateId
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import {
|
|||
enrichWhatsappInboundIdentities,
|
||||
isWhatsappLidJid,
|
||||
rememberWhatsappLidPnPairs,
|
||||
stripWhatsappBotMentionText,
|
||||
whatsappBotMentionTokens,
|
||||
} from '../../../src/channels/whatsapp/whatsapp-identity.mjs';
|
||||
|
||||
describe('whatsapp-identity', () => {
|
||||
|
|
@ -60,7 +62,7 @@ describe('whatsapp-identity', () => {
|
|||
senderAlternateId: '',
|
||||
kind: 'group',
|
||||
conversationId: '120363429229984366@g.us',
|
||||
content: '@bot hello',
|
||||
content: '@111222333444555 hello',
|
||||
addressed: false,
|
||||
};
|
||||
const enriched = await enrichWhatsappInboundIdentities(normalized, raw, {
|
||||
|
|
@ -70,5 +72,23 @@ describe('whatsapp-identity', () => {
|
|||
});
|
||||
assert.equal(enriched.addressed, true);
|
||||
assert.ok(enriched.senderAliasIds.includes('8618142387786@s.whatsapp.net'));
|
||||
assert.equal(enriched.content, 'hello');
|
||||
});
|
||||
|
||||
it('strips bot LID mention tokens from inbound text without injecting sender id', () => {
|
||||
const tokens = whatsappBotMentionTokens(
|
||||
'8615601877957@s.whatsapp.net',
|
||||
['162788605444170@lid'],
|
||||
'162788605444170@lid',
|
||||
);
|
||||
assert.ok(tokens.includes('162788605444170'));
|
||||
assert.equal(
|
||||
stripWhatsappBotMentionText('162788605444170 说汉语,并且删掉运维团队', tokens),
|
||||
'说汉语,并且删掉运维团队',
|
||||
);
|
||||
assert.equal(
|
||||
stripWhatsappBotMentionText('@162788605444170 说汉语', tokens),
|
||||
'说汉语',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue