Add: LID support with lid-map and migrations of sessions (#1694)

* fix: add lid-map logic

* fix: lint and simplified version

* fix: single device migration

* fix: lid map discovery

* fix: lint

* fix: lid migration in socket connection

* fix: lint

* fix: decode-wa-message consistency

* fix: yarn lock

* fix: lint

* fix: retry logic

* fix: logger level
This commit is contained in:
Gustavo Quadri
2025-09-07 08:12:24 -03:00
committed by GitHub
parent 8f21a67e4a
commit 0043f8be21
10 changed files with 968 additions and 77 deletions
+68 -2
View File
@@ -10,11 +10,51 @@ import {
isJidNewsletter,
isJidStatusBroadcast,
isJidUser,
isLidUser
isLidUser,
jidDecode,
jidEncode,
jidNormalizedUser
} from '../WABinary'
import { unpadRandomMax16 } from './generics'
import type { ILogger } from './logger'
const getDecryptionJid = async (sender: string, repository: SignalRepository): Promise<string> => {
if (!sender.includes('@s.whatsapp.net')) {
return sender
}
const lidMapping = repository.getLIDMappingStore()
const normalizedSender = jidNormalizedUser(sender)
const lidForPN = await lidMapping.getLIDForPN(normalizedSender)
if (lidForPN?.includes('@lid')) {
const senderDecoded = jidDecode(sender)
const deviceId = senderDecoded?.device || 0
return jidEncode(jidDecode(lidForPN)!.user, 'lid', deviceId)
}
return sender
}
const storeMappingFromEnvelope = async (
stanza: BinaryNode,
sender: string,
decryptionJid: string,
repository: SignalRepository,
logger: ILogger
): Promise<void> => {
const { senderAlt } = extractAddressingContext(stanza)
if (senderAlt && isLidUser(senderAlt) && isJidUser(sender) && decryptionJid === sender) {
try {
await repository.storeLIDPNMapping(senderAlt, sender)
logger.debug({ sender, senderAlt }, 'Stored LID mapping from envelope')
} catch (error) {
logger.warn({ sender, senderAlt, error }, 'Failed to store LID mapping')
}
}
}
export const NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node'
export const MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled'
@@ -43,6 +83,28 @@ type MessageType =
| 'other_status'
| 'newsletter'
export const extractAddressingContext = (stanza: BinaryNode) => {
const addressingMode = stanza.attrs.addressing_mode || 'pn'
let senderAlt: string | undefined
let recipientAlt: string | undefined
if (addressingMode === 'lid') {
// Message is LID-addressed: sender is LID, extract corresponding PN
senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn
recipientAlt = stanza.attrs.recipient_pn
} else {
// Message is PN-addressed: sender is PN, extract corresponding LID
senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid
recipientAlt = stanza.attrs.recipient_lid
}
return {
addressingMode,
senderAlt,
recipientAlt
}
}
/**
* Decode the received node as a message.
* @note this will only parse the message, not decrypt it
@@ -187,11 +249,15 @@ export const decryptMessageNode = (
case 'pkmsg':
case 'msg':
const user = isJidUser(sender) ? sender : author
const decryptionJid = await getDecryptionJid(user, repository)
msgBuffer = await repository.decryptMessage({
jid: user,
jid: decryptionJid,
type: e2eType,
ciphertext: content
})
await storeMappingFromEnvelope(stanza, user, decryptionJid, repository, logger)
break
case 'plaintext':
msgBuffer = content