Fix WhatsApp selfChatMode sending to wrong person (#49)

* Fix WhatsApp selfChatMode sending to wrong person

Two safety fixes:

1. Fail-safe on unknown LID - refuse to send instead of letting baileys
   resolve it to potentially the wrong person

2. Improve self-chat detection - remove !senderPn requirement which can
   fail in some cases, causing messages to leak to other contacts

Written by Cameron ◯ Letta Code

"Better to fail loudly than succeed silently at the wrong thing."

* Default selfChatMode to true for WhatsApp and Signal

- main.ts: WhatsApp now uses !== 'false' pattern (like Signal)
- config/io.ts: Only set env var if explicitly false
- onboard.ts: Default to 'personal' in config initialization

Written by Cameron ◯ Letta Code
This commit is contained in:
Cameron
2026-01-30 16:24:38 -08:00
committed by GitHub
parent 1d66f42dad
commit 20ab73cc25
4 changed files with 12 additions and 9 deletions

View File

@@ -228,13 +228,12 @@ Ask the bot owner to approve with:
const remoteJid = m.key.remoteJid || '';
// Detect self-chat: message from ourselves to ourselves
// For self-chat, senderPn is undefined, so we detect by: fromMe + LID + selfChatMode
const senderPn = (m.key as any).senderPn as string | undefined;
const isSelfChat = m.key.fromMe && (
remoteJid === this.myJid ||
remoteJid.replace(/@.*/, '') === this.myNumber ||
// In selfChatMode, fromMe + LID (with no senderPn) = self-chat
(this.config.selfChatMode && remoteJid.includes('@lid') && !senderPn)
// In selfChatMode, fromMe + LID = self-chat (don't require !senderPn as it can vary)
(this.config.selfChatMode && remoteJid.includes('@lid'))
);
// Track self-chat LID for reply conversion
@@ -336,8 +335,11 @@ Ask the bot owner to approve with:
} else if (this.lidToJid.has(targetJid)) {
// Friend LID -> their real JID from senderPn
targetJid = this.lidToJid.get(targetJid)!;
} else {
// FAIL SAFE: Don't send to unknown LID - could go to wrong person
console.error(`[WhatsApp] Cannot send to unknown LID: ${targetJid}`);
throw new Error(`Cannot send to unknown LID - no mapping found`);
}
// If no mapping, keep as-is and hope baileys handles it
}
try {

View File

@@ -123,8 +123,9 @@ export function configToEnv(config: LettaBotConfig): Record<string, string> {
}
if (config.channels.whatsapp?.enabled) {
env.WHATSAPP_ENABLED = 'true';
if (config.channels.whatsapp.selfChat) {
env.WHATSAPP_SELF_CHAT_MODE = 'true';
// WhatsApp selfChat defaults to true, so only set env if explicitly false
if (config.channels.whatsapp.selfChat === false) {
env.WHATSAPP_SELF_CHAT_MODE = 'false';
}
}
if (config.channels.signal?.phone) {

View File

@@ -161,7 +161,7 @@ const config = {
sessionPath: process.env.WHATSAPP_SESSION_PATH || './data/whatsapp-session',
dmPolicy: (process.env.WHATSAPP_DM_POLICY || 'pairing') as 'pairing' | 'allowlist' | 'open',
allowedUsers: process.env.WHATSAPP_ALLOWED_USERS?.split(',').filter(Boolean) || [],
selfChatMode: process.env.WHATSAPP_SELF_CHAT_MODE === 'true',
selfChatMode: process.env.WHATSAPP_SELF_CHAT_MODE !== 'false', // Default true
},
signal: {
enabled: !!process.env.SIGNAL_PHONE_NUMBER,

View File

@@ -1395,13 +1395,13 @@ export async function onboard(options?: { nonInteractive?: boolean }): Promise<v
},
whatsapp: {
enabled: existingConfig.channels.whatsapp?.enabled || false,
selfChat: existingConfig.channels.whatsapp?.selfChat,
selfChat: existingConfig.channels.whatsapp?.selfChat ?? true, // Default true
dmPolicy: existingConfig.channels.whatsapp?.dmPolicy,
},
signal: {
enabled: existingConfig.channels.signal?.enabled || false,
phone: existingConfig.channels.signal?.phone,
selfChat: existingConfig.channels.signal?.selfChat,
selfChat: existingConfig.channels.signal?.selfChat ?? true, // Default true
dmPolicy: existingConfig.channels.signal?.dmPolicy,
},
google: {