mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-17 11:10:44 +08:00
feat(whatsapp): add access modes
This commit is contained in:
parent
b0e2c266c5
commit
9b65dd3d6b
15 changed files with 860 additions and 162 deletions
|
|
@ -10,6 +10,10 @@ import { splitMessageText } from '../shared/editable-message-stream.mjs';
|
|||
import { ImagePromptError } from '../shared/image-prompt.mjs';
|
||||
import { trackOutboundArtifactProviderPromise } from '../shared/semantic/artifact.mjs';
|
||||
import { createWhatsappBridgeStatus, WhatsappHarnessBridge } from './whatsapp-bridge.mjs';
|
||||
import {
|
||||
WHATSAPP_ACCESS_MODES,
|
||||
normalizeWhatsappAccessPolicy,
|
||||
} from './config-store.mjs';
|
||||
import { createWhatsappWebSession } from './whatsapp-web-session.mjs';
|
||||
|
||||
const IMAGE_MEDIA_TYPES = new Set(['image/jpeg', 'image/png', 'image/webp', 'image/gif']);
|
||||
|
|
@ -181,6 +185,7 @@ export function normalizeWhatsappMessage(message, accountJid, {
|
|||
&& [remoteJid, alternateRemoteJid].some((jid) => jid && areJidsSameUser(jid, accountJid));
|
||||
if (fromMe && !selfChat) return null;
|
||||
const senderJid = selfChat ? accountJid : group ? message.key.participant : remoteJid;
|
||||
const senderAlternateJid = group ? message.key.participantAlt : alternateRemoteJid;
|
||||
if (typeof senderJid !== 'string' || !senderJid) return null;
|
||||
const viewOnce = hasViewOnceWrapper(message.message);
|
||||
const content = normalizeMessageContent(message.message);
|
||||
|
|
@ -194,6 +199,7 @@ export function normalizeWhatsappMessage(message, accountJid, {
|
|||
messageId: `${remoteJid}:${messageId}`,
|
||||
providerMessageId: messageId,
|
||||
senderId: senderJid,
|
||||
senderAlternateId: typeof senderAlternateJid === 'string' ? senderAlternateJid : '',
|
||||
senderIsBot: false,
|
||||
kind: group ? 'group' : 'direct',
|
||||
conversationId: remoteJid,
|
||||
|
|
@ -205,6 +211,22 @@ export function normalizeWhatsappMessage(message, accountJid, {
|
|||
};
|
||||
}
|
||||
|
||||
export function whatsappInboundAllowed(message, {
|
||||
accessMode = WHATSAPP_ACCESS_MODES.selfOnly,
|
||||
allowedNumbers = new Set(),
|
||||
} = {}) {
|
||||
if (accessMode === WHATSAPP_ACCESS_MODES.open) return true;
|
||||
if (message?.kind !== 'direct') return false;
|
||||
if (message.selfChat === true) return true;
|
||||
if (accessMode !== WHATSAPP_ACCESS_MODES.privateAllowlist
|
||||
|| !(allowedNumbers instanceof Set)) return false;
|
||||
const senderJids = [message.senderId, message.senderAlternateId]
|
||||
.filter((jid) => typeof jid === 'string' && jid.endsWith('@s.whatsapp.net'));
|
||||
return [...allowedNumbers].some((number) => senderJids.some((jid) => (
|
||||
areJidsSameUser(jid, `${number}@s.whatsapp.net`)
|
||||
)));
|
||||
}
|
||||
|
||||
class RecentWhatsappOutboundIds {
|
||||
#ids = new Map();
|
||||
|
||||
|
|
@ -390,6 +412,8 @@ export class WhatsappRuntime {
|
|||
#replyTimeoutMs;
|
||||
#connectTimeoutMs;
|
||||
#mediaUploadTimeoutMs;
|
||||
#accessMode;
|
||||
#allowedPrivateNumbers;
|
||||
#createSession;
|
||||
#status = createWhatsappRuntimeStatus();
|
||||
#abortController = null;
|
||||
|
|
@ -427,12 +451,21 @@ export class WhatsappRuntime {
|
|||
WHATSAPP_MEDIA_UPLOAD_TIMEOUT_MS,
|
||||
);
|
||||
this.#createSession = createSession;
|
||||
this.setAccessPolicy(config);
|
||||
}
|
||||
|
||||
get status() {
|
||||
return structuredClone(this.#status);
|
||||
}
|
||||
|
||||
setAccessPolicy(value) {
|
||||
const policy = normalizeWhatsappAccessPolicy(value);
|
||||
this.#accessMode = policy.accessMode;
|
||||
this.#allowedPrivateNumbers = new Set(policy.allowedNumbers);
|
||||
this.#config = { ...this.#config, ...policy };
|
||||
return policy;
|
||||
}
|
||||
|
||||
async start() {
|
||||
if (this.#status.ready && this.#session) return this.status;
|
||||
if (this.#starting) return this.#starting;
|
||||
|
|
@ -466,6 +499,14 @@ export class WhatsappRuntime {
|
|||
const message = normalizeWhatsappMessage(raw, this.#config.accountJid);
|
||||
if (!message || outboundIds.has(message.providerMessageId) || !this.#bridge) return;
|
||||
this.#status.lastCheckedAt = Date.now();
|
||||
if (!whatsappInboundAllowed(message, {
|
||||
accessMode: this.#accessMode,
|
||||
allowedNumbers: this.#allowedPrivateNumbers,
|
||||
})) {
|
||||
this.#status.messagesRejected += 1;
|
||||
this.#status.lastRejectedAt = new Date().toISOString();
|
||||
return;
|
||||
}
|
||||
await this.#bridge.accept(message);
|
||||
},
|
||||
onDisconnect: ({ error }) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue