lid, wip: Support LIDs in Baileys (#1747)
* lid-mapping: get missing lid from usync * lid-mapping, jid-utils: change to isPnUser and store multiple mappings * process-message: parse protocolMsg mapping, and store from new msgs * types: lid-mapping event, addressing enum, alt, contact, group types * validate, decode: use lid for identity, better logic * lid: final commit * linting * linting * linting * linting * misc: fix testing and also remove version json * lint: IDE fucking up lint * lid-mapping: fix build error on NPM * message-retry: fix proto import
This commit is contained in:
@@ -19,14 +19,7 @@ import {
|
||||
LabelAssociationType,
|
||||
type MessageLabelAssociation
|
||||
} from '../Types/LabelAssociation'
|
||||
import {
|
||||
type BinaryNode,
|
||||
getBinaryNodeChild,
|
||||
getBinaryNodeChildren,
|
||||
isJidGroup,
|
||||
isJidUser,
|
||||
jidNormalizedUser
|
||||
} from '../WABinary'
|
||||
import { type BinaryNode, getBinaryNodeChild, getBinaryNodeChildren, isJidGroup, jidNormalizedUser } from '../WABinary'
|
||||
import { aesDecrypt, aesEncrypt, hkdf, hmacSign } from './crypto'
|
||||
import { toNumber } from './generics'
|
||||
import type { ILogger } from './logger'
|
||||
@@ -845,7 +838,7 @@ export const processSyncAction = (
|
||||
id: id!,
|
||||
name: action.contactAction.fullName!,
|
||||
lid: action.contactAction.lidJid || undefined,
|
||||
jid: isJidUser(id) ? id : undefined
|
||||
phoneNumber: action.contactAction.pnJid || undefined
|
||||
}
|
||||
])
|
||||
} else if (action?.pushNameSetting) {
|
||||
|
||||
@@ -6,14 +6,12 @@ import {
|
||||
type BinaryNode,
|
||||
isJidBroadcast,
|
||||
isJidGroup,
|
||||
isJidMetaIa,
|
||||
isJidMetaAI,
|
||||
isJidNewsletter,
|
||||
isJidStatusBroadcast,
|
||||
isJidUser,
|
||||
isLidUser,
|
||||
jidDecode,
|
||||
jidEncode,
|
||||
jidNormalizedUser
|
||||
isPnUser,
|
||||
transferDevice
|
||||
} from '../WABinary'
|
||||
import { unpadRandomMax16 } from './generics'
|
||||
import type { ILogger } from './logger'
|
||||
@@ -23,17 +21,7 @@ const getDecryptionJid = async (sender: string, repository: SignalRepository): P
|
||||
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
|
||||
return (await repository.getLIDMappingStore().getLIDForPN(sender))!
|
||||
}
|
||||
|
||||
const storeMappingFromEnvelope = async (
|
||||
@@ -45,7 +33,7 @@ const storeMappingFromEnvelope = async (
|
||||
): Promise<void> => {
|
||||
const { senderAlt } = extractAddressingContext(stanza)
|
||||
|
||||
if (senderAlt && isLidUser(senderAlt) && isJidUser(sender) && decryptionJid === sender) {
|
||||
if (senderAlt && isLidUser(senderAlt) && isPnUser(sender) && decryptionJid === sender) {
|
||||
try {
|
||||
await repository.storeLIDPNMapping(senderAlt, sender)
|
||||
logger.debug({ sender, senderAlt }, 'Stored LID mapping from envelope')
|
||||
@@ -95,14 +83,23 @@ export const extractAddressingContext = (stanza: BinaryNode) => {
|
||||
let senderAlt: string | undefined
|
||||
let recipientAlt: string | undefined
|
||||
|
||||
const sender = stanza.attrs.participant || stanza.attrs.from
|
||||
|
||||
if (addressingMode === 'lid') {
|
||||
// Message is LID-addressed: sender is LID, extract corresponding PN
|
||||
senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn
|
||||
// without device data
|
||||
senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn
|
||||
recipientAlt = stanza.attrs.recipient_pn
|
||||
// with device data
|
||||
if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
|
||||
} else {
|
||||
// Message is PN-addressed: sender is PN, extract corresponding LID
|
||||
senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid
|
||||
// without device data
|
||||
senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid
|
||||
recipientAlt = stanza.attrs.recipient_lid
|
||||
|
||||
//with device data
|
||||
if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -126,11 +123,13 @@ export function decodeMessageNode(stanza: BinaryNode, meId: string, meLid: strin
|
||||
const participant: string | undefined = stanza.attrs.participant
|
||||
const recipient: string | undefined = stanza.attrs.recipient
|
||||
|
||||
const addressingContext = extractAddressingContext(stanza)
|
||||
|
||||
const isMe = (jid: string) => areJidsSameUser(jid, meId)
|
||||
const isMeLid = (jid: string) => areJidsSameUser(jid, meLid)
|
||||
|
||||
if (isJidUser(from) || isLidUser(from)) {
|
||||
if (recipient && !isJidMetaIa(recipient)) {
|
||||
if (isPnUser(from) || isLidUser(from)) {
|
||||
if (recipient && !isJidMetaAI(recipient)) {
|
||||
if (!isMe(from!) && !isMeLid(from!)) {
|
||||
throw new Boom('receipient present, but msg not from me', { data: stanza })
|
||||
}
|
||||
@@ -177,13 +176,11 @@ export function decodeMessageNode(stanza: BinaryNode, meId: string, meLid: strin
|
||||
|
||||
const key: WAMessageKey = {
|
||||
remoteJid: chatId,
|
||||
remoteJidAlt: !isJidGroup(chatId) ? addressingContext.senderAlt : undefined,
|
||||
fromMe,
|
||||
id: msgId,
|
||||
senderLid: stanza?.attrs?.sender_lid,
|
||||
senderPn: stanza?.attrs?.sender_pn || stanza?.attrs?.peer_recipient_pn,
|
||||
participant,
|
||||
participantPn: stanza?.attrs?.participant_pn,
|
||||
participantLid: stanza?.attrs?.participant_lid,
|
||||
participantAlt: isJidGroup(chatId) ? addressingContext.senderAlt : undefined,
|
||||
...(msgType === 'newsletter' && stanza.attrs.server_id ? { server_id: stanza.attrs.server_id } : {})
|
||||
}
|
||||
|
||||
@@ -228,7 +225,7 @@ export const decryptMessageNode = (
|
||||
}
|
||||
|
||||
if (tag === 'unavailable' && attrs.type === 'view_once') {
|
||||
fullMessage.key.isViewOnce = true
|
||||
fullMessage.key.isViewOnce = true // TODO: remove from here and add a STUB TYPE
|
||||
}
|
||||
|
||||
if (tag !== 'enc' && tag !== 'plaintext') {
|
||||
@@ -243,6 +240,12 @@ export const decryptMessageNode = (
|
||||
|
||||
let msgBuffer: Uint8Array
|
||||
|
||||
const user = isPnUser(sender) ? sender : author // TODO: flaky logic
|
||||
const decryptionJid = await getDecryptionJid(user, repository)
|
||||
if (tag !== 'plaintext') {
|
||||
await storeMappingFromEnvelope(stanza, user, decryptionJid, repository, logger)
|
||||
}
|
||||
|
||||
try {
|
||||
const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type
|
||||
|
||||
@@ -256,16 +259,11 @@ export const decryptMessageNode = (
|
||||
break
|
||||
case 'pkmsg':
|
||||
case 'msg':
|
||||
const user = isJidUser(sender) ? sender : author
|
||||
const decryptionJid = await getDecryptionJid(user, repository)
|
||||
|
||||
msgBuffer = await repository.decryptMessage({
|
||||
jid: decryptionJid,
|
||||
type: e2eType,
|
||||
ciphertext: content
|
||||
})
|
||||
|
||||
await storeMappingFromEnvelope(stanza, user, decryptionJid, repository, logger)
|
||||
break
|
||||
case 'plaintext':
|
||||
msgBuffer = content
|
||||
|
||||
@@ -3,8 +3,7 @@ import axios, { type AxiosRequestConfig } from 'axios'
|
||||
import { createHash, randomBytes } from 'crypto'
|
||||
import { platform, release } from 'os'
|
||||
import { proto } from '../../WAProto/index.js'
|
||||
import version from '../Defaults/baileys-version.json' with { type: 'json' }
|
||||
const baileysVersion = version.version
|
||||
const baileysVersion = [2, 3000, 1023223821]
|
||||
import type {
|
||||
BaileysEventEmitter,
|
||||
BaileysEventMap,
|
||||
|
||||
@@ -4,7 +4,6 @@ import { inflate } from 'zlib'
|
||||
import { proto } from '../../WAProto/index.js'
|
||||
import type { Chat, Contact } from '../Types'
|
||||
import { WAMessageStubType } from '../Types'
|
||||
import { isJidUser } from '../WABinary'
|
||||
import { toNumber } from './generics'
|
||||
import { normalizeMessageContent } from './messages'
|
||||
import { downloadContentFromMessage } from './messages-media'
|
||||
@@ -42,7 +41,7 @@ export const processHistoryMessage = (item: proto.IHistorySync) => {
|
||||
id: chat.id,
|
||||
name: chat.name || undefined,
|
||||
lid: chat.lidJid || undefined,
|
||||
jid: isJidUser(chat.id) ? chat.id : undefined
|
||||
phoneNumber: chat.pnJid || undefined
|
||||
})
|
||||
|
||||
const msgs = chat.messages || []
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LRUCache } from 'lru-cache'
|
||||
import { proto } from '../../WAProto'
|
||||
import type { proto } from '../../WAProto/index.js'
|
||||
import type { ILogger } from './logger'
|
||||
|
||||
/** Number of sent messages to cache in memory for handling retry receipts */
|
||||
|
||||
@@ -9,7 +9,8 @@ import type {
|
||||
ParticipantAction,
|
||||
RequestJoinAction,
|
||||
RequestJoinMethod,
|
||||
SignalKeyStoreWithTransaction
|
||||
SignalKeyStoreWithTransaction,
|
||||
SignalRepository
|
||||
} from '../Types'
|
||||
import { WAMessageStubType } from '../Types'
|
||||
import { getContentType, normalizeMessageContent } from '../Utils/messages'
|
||||
@@ -27,6 +28,7 @@ type ProcessMessageContext = {
|
||||
ev: BaileysEventEmitter
|
||||
logger?: ILogger
|
||||
options: AxiosRequestConfig<{}>
|
||||
signalRepository: SignalRepository
|
||||
}
|
||||
|
||||
const REAL_MSG_STUB_TYPES = new Set([
|
||||
@@ -145,7 +147,16 @@ export function decryptPollVote(
|
||||
|
||||
const processMessage = async (
|
||||
message: proto.IWebMessageInfo,
|
||||
{ shouldProcessHistoryMsg, placeholderResendCache, ev, creds, keyStore, logger, options }: ProcessMessageContext
|
||||
{
|
||||
shouldProcessHistoryMsg,
|
||||
placeholderResendCache,
|
||||
ev,
|
||||
creds,
|
||||
signalRepository,
|
||||
keyStore,
|
||||
logger,
|
||||
options
|
||||
}: ProcessMessageContext
|
||||
) => {
|
||||
const meId = creds.me!.id
|
||||
const { accountSettings } = creds
|
||||
@@ -292,6 +303,19 @@ const processMessage = async (
|
||||
}
|
||||
])
|
||||
break
|
||||
case proto.Message.ProtocolMessage.Type.LID_MIGRATION_MAPPING_SYNC:
|
||||
const lidMappingStore = signalRepository.getLIDMappingStore()
|
||||
const encodedPayload = protocolMsg.lidMigrationMappingSyncMessage?.encodedMappingPayload!
|
||||
const { pnToLidMappings, chatDbMigrationTimestamp } =
|
||||
proto.LIDMigrationMappingSyncPayload.decode(encodedPayload)
|
||||
logger?.debug({ pnToLidMappings, chatDbMigrationTimestamp }, 'got lid mappings and chat db migration timestamp')
|
||||
const pairs = []
|
||||
for (const { pn, latestLid, assignedLid } of pnToLidMappings) {
|
||||
const lid = latestLid || assignedLid
|
||||
pairs.push({ lid: `${lid}@lid`, pn: `${pn}@s.whatsapp.net` })
|
||||
}
|
||||
|
||||
await lidMappingStore.storeLIDPNMappings(pairs)
|
||||
}
|
||||
} else if (content?.reactionMessage) {
|
||||
const reaction: proto.IReaction = {
|
||||
|
||||
@@ -133,6 +133,7 @@ export const configureSuccessfulPairing = (
|
||||
|
||||
const bizName = businessNode?.attrs.name
|
||||
const jid = deviceNode.attrs.jid
|
||||
const lid = deviceNode.attrs.lid
|
||||
|
||||
const { details, hmac, accountType } = proto.ADVSignedDeviceIdentityHMAC.decode(deviceIdentityNode.content as Buffer)
|
||||
const isHostedAccount = accountType !== undefined && accountType === proto.ADVEncryptionType.HOSTED
|
||||
@@ -154,7 +155,7 @@ export const configureSuccessfulPairing = (
|
||||
const deviceMsg = Buffer.concat([devicePrefix, deviceDetails, signedIdentityKey.public, accountSignatureKey])
|
||||
account.deviceSignature = Curve.sign(signedIdentityKey.private, deviceMsg)
|
||||
|
||||
const identity = createSignalIdentity(jid!, accountSignatureKey)
|
||||
const identity = createSignalIdentity(lid!, accountSignatureKey)
|
||||
const accountEnc = encodeSignedDeviceIdentity(account, false)
|
||||
|
||||
const deviceIdentity = proto.ADVDeviceIdentity.decode(account.details)
|
||||
@@ -183,7 +184,7 @@ export const configureSuccessfulPairing = (
|
||||
|
||||
const authUpdate: Partial<AuthenticationCreds> = {
|
||||
account,
|
||||
me: { id: jid!, name: bizName },
|
||||
me: { id: jid!, name: bizName, lid },
|
||||
signalIdentities: [...(signalIdentities || []), identity],
|
||||
platform: platformNode?.attrs.name
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user