refactor(retry): improve message encryption and retry logic (#2055)
This commit is contained in:
@@ -1200,7 +1200,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
|||||||
await processingMutex.mutex(async () => {
|
await processingMutex.mutex(async () => {
|
||||||
await decrypt()
|
await decrypt()
|
||||||
// message failed to decrypt
|
// message failed to decrypt
|
||||||
if (msg.messageStubType === proto.WebMessageInfo.StubType.CIPHERTEXT) {
|
if (msg.messageStubType === proto.WebMessageInfo.StubType.CIPHERTEXT && msg.category !== 'peer') {
|
||||||
if (msg?.messageStubParameters?.[0] === MISSING_KEYS_ERROR_TEXT) {
|
if (msg?.messageStubParameters?.[0] === MISSING_KEYS_ERROR_TEXT) {
|
||||||
return sendMessageAck(node, NACK_REASONS.ParsingError)
|
return sendMessageAck(node, NACK_REASONS.ParsingError)
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-47
@@ -572,6 +572,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
const isStatus = jid === statusJid
|
const isStatus = jid === statusJid
|
||||||
const isLid = server === 'lid'
|
const isLid = server === 'lid'
|
||||||
const isNewsletter = server === 'newsletter'
|
const isNewsletter = server === 'newsletter'
|
||||||
|
const isGroupOrStatus = isGroup || isStatus
|
||||||
const finalJid = jid
|
const finalJid = jid
|
||||||
|
|
||||||
msgId = msgId || generateMessageIDV2(meId)
|
msgId = msgId || generateMessageIDV2(meId)
|
||||||
@@ -639,7 +640,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
extraAttrs['decrypt-fail'] = 'hide' // todo: expand for reactions and other types
|
extraAttrs['decrypt-fail'] = 'hide' // todo: expand for reactions and other types
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGroup || isStatus) {
|
if (isGroupOrStatus && !isRetryResend) {
|
||||||
const [groupData, senderKeyMap] = await Promise.all([
|
const [groupData, senderKeyMap] = await Promise.all([
|
||||||
(async () => {
|
(async () => {
|
||||||
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined // todo: should we rely on the cache specially if the cache is outdated and the metadata has new fields?
|
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined // todo: should we rely on the cache specially if the cache is outdated and the metadata has new fields?
|
||||||
@@ -663,28 +664,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
})()
|
})()
|
||||||
])
|
])
|
||||||
|
|
||||||
if (!participant) {
|
const participantsList = groupData ? groupData.participants.map(p => p.id) : []
|
||||||
const participantsList = []
|
|
||||||
if (isStatus) {
|
|
||||||
if (statusJidList?.length) participantsList.push(...statusJidList)
|
|
||||||
} else {
|
|
||||||
// default to LID based groups
|
|
||||||
let groupAddressingMode = 'lid'
|
|
||||||
if (groupData) {
|
|
||||||
participantsList.push(...groupData.participants.map(p => p.id))
|
|
||||||
groupAddressingMode = groupData?.addressingMode || groupAddressingMode
|
|
||||||
}
|
|
||||||
|
|
||||||
// default to lid addressing mode in a group
|
|
||||||
additionalAttributes = {
|
|
||||||
...additionalAttributes,
|
|
||||||
addressing_mode: groupAddressingMode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
|
|
||||||
devices.push(...additionalDevices)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
||||||
additionalAttributes = {
|
additionalAttributes = {
|
||||||
@@ -693,6 +673,20 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isStatus && statusJidList) {
|
||||||
|
participantsList.push(...statusJidList)
|
||||||
|
}
|
||||||
|
|
||||||
|
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
|
||||||
|
devices.push(...additionalDevices)
|
||||||
|
|
||||||
|
if (isGroup) {
|
||||||
|
additionalAttributes = {
|
||||||
|
...additionalAttributes,
|
||||||
|
addressing_mode: groupData?.addressingMode || 'lid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const patched = await patchMessageBeforeSending(message)
|
const patched = await patchMessageBeforeSending(message)
|
||||||
if (Array.isArray(patched)) {
|
if (Array.isArray(patched)) {
|
||||||
throw new Boom('Per-jid patching is not supported in groups')
|
throw new Boom('Per-jid patching is not supported in groups')
|
||||||
@@ -744,30 +738,13 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
participants.push(...result.nodes)
|
participants.push(...result.nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRetryResend) {
|
binaryNodeContent.push({
|
||||||
const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
|
tag: 'enc',
|
||||||
data: bytes,
|
attrs: { v: '2', type: 'skmsg', ...extraAttrs },
|
||||||
jid: participant?.jid!
|
content: ciphertext
|
||||||
})
|
})
|
||||||
|
|
||||||
binaryNodeContent.push({
|
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } })
|
||||||
tag: 'enc',
|
|
||||||
attrs: {
|
|
||||||
v: '2',
|
|
||||||
type,
|
|
||||||
count: participant!.count.toString()
|
|
||||||
},
|
|
||||||
content: encryptedContent
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
binaryNodeContent.push({
|
|
||||||
tag: 'enc',
|
|
||||||
attrs: { v: '2', type: 'skmsg', ...extraAttrs },
|
|
||||||
content: ciphertext
|
|
||||||
})
|
|
||||||
|
|
||||||
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } })
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
||||||
// TODO: investigate if this is true
|
// TODO: investigate if this is true
|
||||||
@@ -781,7 +758,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
|
|
||||||
const { user: ownUser } = jidDecode(ownId)!
|
const { user: ownUser } = jidDecode(ownId)!
|
||||||
|
|
||||||
if (!participant) {
|
if (!isRetryResend) {
|
||||||
const targetUserServer = isLid ? 'lid' : 's.whatsapp.net'
|
const targetUserServer = isLid ? 'lid' : 's.whatsapp.net'
|
||||||
devices.push({
|
devices.push({
|
||||||
user,
|
user,
|
||||||
@@ -869,6 +846,35 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isRetryResend) {
|
||||||
|
const isParticipantLid = isLidUser(participant!.jid)
|
||||||
|
const isMe = areJidsSameUser(participant!.jid, isParticipantLid ? meLid : meId)
|
||||||
|
|
||||||
|
const encodedMessageToSend = isMe
|
||||||
|
? encodeWAMessage({
|
||||||
|
deviceSentMessage: {
|
||||||
|
destinationJid,
|
||||||
|
message
|
||||||
|
}
|
||||||
|
})
|
||||||
|
: encodeWAMessage(message)
|
||||||
|
|
||||||
|
const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
|
||||||
|
data: encodedMessageToSend,
|
||||||
|
jid: participant!.jid
|
||||||
|
})
|
||||||
|
|
||||||
|
binaryNodeContent.push({
|
||||||
|
tag: 'enc',
|
||||||
|
attrs: {
|
||||||
|
v: '2',
|
||||||
|
type,
|
||||||
|
count: participant!.count.toString()
|
||||||
|
},
|
||||||
|
content: encryptedContent
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (participants.length) {
|
if (participants.length) {
|
||||||
if (additionalAttributes?.['category'] === 'peer') {
|
if (additionalAttributes?.['category'] === 'peer') {
|
||||||
const peerNode = participants[0]?.content?.[0] as BinaryNode
|
const peerNode = participants[0]?.content?.[0] as BinaryNode
|
||||||
|
|||||||
@@ -8,7 +8,12 @@ import type { CacheStore } from './Socket'
|
|||||||
|
|
||||||
// export the WAMessage Prototypes
|
// export the WAMessage Prototypes
|
||||||
export { proto as WAProto }
|
export { proto as WAProto }
|
||||||
export type WAMessage = proto.IWebMessageInfo & { key: WAMessageKey; messageStubParameters?: any }
|
export type WAMessage = proto.IWebMessageInfo & {
|
||||||
|
key: WAMessageKey
|
||||||
|
messageStubParameters?: any
|
||||||
|
category?: string
|
||||||
|
retryCount?: number
|
||||||
|
}
|
||||||
export type WAMessageContent = proto.IMessage
|
export type WAMessageContent = proto.IMessage
|
||||||
export type WAContactMessage = proto.Message.IContactMessage
|
export type WAContactMessage = proto.Message.IContactMessage
|
||||||
export type WAContactsArrayMessage = proto.Message.IContactsArrayMessage
|
export type WAContactsArrayMessage = proto.Message.IContactsArrayMessage
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ export function decodeMessageNode(stanza: BinaryNode, meId: string, meLid: strin
|
|||||||
|
|
||||||
const fullMessage: WAMessage = {
|
const fullMessage: WAMessage = {
|
||||||
key,
|
key,
|
||||||
|
category: stanza.attrs.category,
|
||||||
messageTimestamp: +stanza.attrs.t!,
|
messageTimestamp: +stanza.attrs.t!,
|
||||||
pushName: pushname,
|
pushName: pushname,
|
||||||
broadcast: isJidBroadcast(from)
|
broadcast: isJidBroadcast(from)
|
||||||
@@ -248,6 +249,10 @@ export const decryptMessageNode = (
|
|||||||
fullMessage.key.isViewOnce = true // TODO: remove from here and add a STUB TYPE
|
fullMessage.key.isViewOnce = true // TODO: remove from here and add a STUB TYPE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attrs.count && tag === 'enc') {
|
||||||
|
fullMessage.retryCount = Number(attrs.count)
|
||||||
|
}
|
||||||
|
|
||||||
if (tag !== 'enc' && tag !== 'plaintext') {
|
if (tag !== 'enc' && tag !== 'plaintext') {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -333,7 +338,7 @@ export const decryptMessageNode = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if nothing was found to decrypt
|
// if nothing was found to decrypt
|
||||||
if (!decryptables) {
|
if (!decryptables && !fullMessage.key?.isViewOnce) {
|
||||||
fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT
|
fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT
|
||||||
fullMessage.messageStubParameters = [NO_MESSAGE_FOUND_ERROR_TEXT]
|
fullMessage.messageStubParameters = [NO_MESSAGE_FOUND_ERROR_TEXT]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user