diff --git a/src/Socket/messages-recv.ts b/src/Socket/messages-recv.ts index 58848a05..9318a1b3 100644 --- a/src/Socket/messages-recv.ts +++ b/src/Socket/messages-recv.ts @@ -2258,17 +2258,6 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { return } - // Handle view-once unavailable sync from primary device. - // When the primary device sends a view-once, linked companions receive - // — no enc content, just a sync signal. - // Acknowledge and skip decryption (nothing to decrypt). - const unavailableNode = getBinaryNodeChild(node, 'unavailable') - if (unavailableNode?.attrs?.type === 'view_once') { - logger.debug({ id: node.attrs.id, from: node.attrs.from }, 'received view_once unavailable sync from primary device') - await sendMessageAck(node) - return - } - const { fullMessage: msg, category, diff --git a/src/Socket/messages-send.ts b/src/Socket/messages-send.ts index d1ec3132..4724c059 100644 --- a/src/Socket/messages-send.ts +++ b/src/Socket/messages-send.ts @@ -1277,21 +1277,32 @@ export const makeMessagesSocket = (config: SocketConfig) => { : otherRecipients const effectiveAllRecipients = [...effectiveMeRecipients, ...effectiveOtherRecipients] - await assertSessions(effectiveAllRecipients) + // P2: detect actual view-once media by checking inner message's viewOnce flag. + // viewOnceMessage wrapper is also used for interactive messages (buttons, lists, etc) + // which do NOT carry viewOnce=true on the media — those must NOT be filtered. + const viewOnceInner = + message.viewOnceMessageV2?.message || + message.viewOnceMessage?.message || + message.viewOnceMessageV2Extension?.message + const isViewOnceMsg = !!( + viewOnceInner?.imageMessage?.viewOnce || + viewOnceInner?.videoMessage?.viewOnce || + viewOnceInner?.audioMessage?.viewOnce + ) // For view-once: only send DSM to primary phone (device=0). // Companion devices (device>0) are omitted — WA server generates // for them automatically. // Sending explicit from a companion is rejected by the server. - const isViewOnceMsg = !!( - message.viewOnceMessageV2 || - message.viewOnceMessage || - message.viewOnceMessageV2Extension - ) const viewOnceMeRecipients = isViewOnceMsg ? effectiveMeRecipients.filter(jid => !jidDecode(jid)?.device) : effectiveMeRecipients + // P3: assert sessions only for recipients we actually encrypt for. + // For view-once, companions are omitted — asserting their sessions is wasteful + // and could block the send if a companion session is corrupted. + await assertSessions([...viewOnceMeRecipients, ...effectiveOtherRecipients]) + const [ { nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }