From 432c26a07c43c087e0b70d74b28e7aa7b4cd6f65 Mon Sep 17 00:00:00 2001 From: vini Date: Thu, 8 Jan 2026 17:07:11 -0300 Subject: [PATCH] fix(messages): handle encryption failures per recipient and fail when all fail (#2226) --- src/Socket/messages-send.ts | 88 +++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/src/Socket/messages-send.ts b/src/Socket/messages-send.ts index 36e65446..1202e87d 100644 --- a/src/Socket/messages-send.ts +++ b/src/Socket/messages-send.ts @@ -541,52 +541,62 @@ export const makeMessagesSocket = (config: SocketConfig) => { const encryptionPromises = (patchedMessages as any).map( async ({ recipientJid: jid, message: patchedMessage }: any) => { - if (!jid) return null - let msgToEncrypt = patchedMessage - if (dsmMessage) { - const { user: targetUser } = jidDecode(jid)! - const { user: ownPnUser } = jidDecode(meId)! - const ownLidUser = meLidUser - const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser) - const isExactSenderDevice = jid === meId || (meLid && jid === meLid) - if (isOwnUser && !isExactSenderDevice) { - msgToEncrypt = dsmMessage - logger.debug({ jid, targetUser }, 'Using DSM for own device') - } - } + try { + if (!jid) return null - const bytes = encodeWAMessage(msgToEncrypt) - const mutexKey = jid - const node = await encryptionMutex.mutex(mutexKey, async () => { - const { type, ciphertext } = await signalRepository.encryptMessage({ - jid, - data: bytes + let msgToEncrypt = patchedMessage + + if (dsmMessage) { + const { user: targetUser } = jidDecode(jid)! + const { user: ownPnUser } = jidDecode(meId)! + const ownLidUser = meLidUser + + const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser) + const isExactSenderDevice = jid === meId || (meLid && jid === meLid) + + if (isOwnUser && !isExactSenderDevice) { + msgToEncrypt = dsmMessage + logger.debug({ jid, targetUser }, 'Using DSM for own device') + } + } + + const bytes = encodeWAMessage(msgToEncrypt) + const mutexKey = jid + + const node = await encryptionMutex.mutex(mutexKey, async () => { + const { type, ciphertext } = await signalRepository.encryptMessage({ jid, data: bytes }) + + if (type === 'pkmsg') { + shouldIncludeDeviceIdentity = true + } + + return { + tag: 'to', + attrs: { jid }, + content: [ + { + tag: 'enc', + attrs: { v: '2', type, ...(extraAttrs || {}) }, + content: ciphertext + } + ] + } }) - if (type === 'pkmsg') { - shouldIncludeDeviceIdentity = true - } - return { - tag: 'to', - attrs: { jid }, - content: [ - { - tag: 'enc', - attrs: { - v: '2', - type, - ...(extraAttrs || {}) - }, - content: ciphertext - } - ] - } - }) - return node + return node + } catch (err) { + logger.error({ jid, err }, 'Failed to encrypt for recipient') + return null + } } ) const nodes = (await Promise.all(encryptionPromises)).filter(node => node !== null) as BinaryNode[] + + if (recipientJids.length > 0 && nodes.length === 0) { + throw new Boom('All encryptions failed', { statusCode: 500 }) + } + return { nodes, shouldIncludeDeviceIdentity } }