From d014a2496e84d2254cb99fe31b75800616665937 Mon Sep 17 00:00:00 2001 From: Renato Alcara Date: Sun, 12 Apr 2026 10:02:30 -0300 Subject: [PATCH] fix: allow msmsg decryption and emit view-once unavailable fanout (#355) Two issues found during view-once testing on linked devices: 1. msmsg block removal: The "temporary fix" that discarded all msmsg-type encrypted messages was also blocking legitimate view-once messages. On linked devices, view-once arrives as msmsg encryption type. The block was originally added to prevent crashes from missing messageSecret, but the existing try/catch in the decrypt path already handles those errors gracefully by marking the message as a CIPHERTEXT stub. 2. view_once_unavailable_fanout emission: When a linked device receives a view-once, the WA server sends only (no with actual media content). Previously this was silently acknowledged without emitting any event, so consumers (zpro, astra-api, etc.) never knew a view-once arrived. Now it emits the message as a CIPHERTEXT stub with key.isViewOnce=true so consumers can display "view-once message received" in their UI. Co-Authored-By: Renato Alcara --- src/Socket/messages-recv.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Socket/messages-recv.ts b/src/Socket/messages-recv.ts index ada9fe4a..0b599ecb 100644 --- a/src/Socket/messages-recv.ts +++ b/src/Socket/messages-recv.ts @@ -2251,12 +2251,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { } const encNode = getBinaryNodeChild(node, 'enc') - // TODO: temporary fix for crashes and issues resulting of failed msmsg decryption - if (encNode?.attrs.type === 'msmsg') { - logger.debug({ key: node.attrs.key }, 'ignored msmsg') - await sendMessageAck(node, NACK_REASONS.MissingMessageSecret) - return - } + // msmsg block removed — allow msmsg decryption (required for view-once on linked devices) // Handle view-once unavailable sync from primary device. // When the primary device sends a view-once, linked companions receive @@ -2382,6 +2377,15 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { { msgId: msg.key?.id, messageType }, 'CTWA: Skipping placeholder resend for unavailable fanout type' ) + // For view-once: emit the message as a stub so consumers know it arrived. + // Use 'notify' for live messages so realtime consumers get the event. + if (messageType === 'view_once_unavailable_fanout') { + msg.key.isViewOnce = true + msg.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT + msg.messageStubParameters = ['view_once_unavailable'] + const upsertType = node.attrs.offline ? 'append' : 'notify' + await upsertMessage(msg, upsertType) + } metrics.ctwaRecoveryFailures.inc({ reason: 'unavailable_fanout' }) return sendMessageAck(node) }