diff --git a/src/Signal/libsignal.ts b/src/Signal/libsignal.ts index ba756162..72a67d63 100644 --- a/src/Signal/libsignal.ts +++ b/src/Signal/libsignal.ts @@ -128,6 +128,7 @@ export function makeLibSignalRepository( }, async injectE2ESession({ jid, session }) { + logger.trace({ jid }, 'injecting E2EE session') const cipher = new libsignal.SessionBuilder(storage, jidToSignalProtocolAddress(jid)) return parsedKeys.transaction(async () => { await cipher.initOutgoing(session) @@ -350,13 +351,13 @@ function signalStorage( // Shared function to resolve PN signal address to LID if mapping exists const resolveLIDSignalAddress = async (id: string): Promise => { if (id.includes('.')) { - const [deviceId, domainType_] = id.split('_') + const [deviceId, device] = id.split('.') + const [user, domainType_] = deviceId!.split('_') const domainType = parseInt(domainType_ || '0') - const [user, device] = deviceId!.split('.') if (domainType === WAJIDDomains.LID || domainType === WAJIDDomains.HOSTED_LID) return id - const pnJid = `${user!}${device !== '0' ? `:${device}` : ''}@s.whatsapp.net` + const pnJid = `${user!}${device !== '0' ? `:${device}` : ''}@${domainType == WAJIDDomains.HOSTED ? 'hosted' : 's.whatsapp.net'}` let lidForPN = await lidMapping.getLIDForPN(pnJid) if (lidForPN?.includes('@lid')) { @@ -389,7 +390,7 @@ function signalStorage( await keys.set({ session: { [wireJid]: session.serialize() } }) }, isTrustedIdentity: () => { - return true + return true // todo: implement }, loadPreKey: async (id: number | string) => { const keyId = id.toString() diff --git a/src/Signal/lid-mapping.ts b/src/Signal/lid-mapping.ts index e1c89000..2037aad8 100644 --- a/src/Signal/lid-mapping.ts +++ b/src/Signal/lid-mapping.ts @@ -1,7 +1,7 @@ import { LRUCache } from 'lru-cache' import type { LIDMapping, SignalKeyStoreWithTransaction } from '../Types' import type { ILogger } from '../Utils/logger' -import { isJidHostedLidUser, isJidHostedPnUser, isLidUser, isPnUser, jidDecode, jidNormalizedUser } from '../WABinary' +import { isHostedLidUser, isHostedPnUser, isLidUser, isPnUser, jidDecode, jidNormalizedUser } from '../WABinary' export class LIDMappingStore { private readonly mappingCache = new LRUCache({ @@ -93,7 +93,7 @@ export class LIDMappingStore { // mapped from pn to lid mapping to prevent duplication in results later const successfulPairs: { [_: string]: LIDMapping } = {} for (const pn of pns) { - if (!isPnUser(pn)) continue + if (!isPnUser(pn) && !isHostedPnUser(pn)) continue const decoded = jidDecode(pn) if (!decoded) continue @@ -114,7 +114,7 @@ export class LIDMappingStore { this.logger.trace(`No LID mapping found for PN user ${pnUser}; batch getting from USync`) const device = decoded.device || 0 let normalizedPn = jidNormalizedUser(pn) - if (isJidHostedLidUser(normalizedPn) || isJidHostedPnUser(normalizedPn)) { + if (isHostedLidUser(normalizedPn) || isHostedPnUser(normalizedPn)) { normalizedPn = `${pnUser}@s.whatsapp.net` } diff --git a/src/Socket/messages-recv.ts b/src/Socket/messages-recv.ts index 47e471ac..d56d5aa1 100644 --- a/src/Socket/messages-recv.ts +++ b/src/Socket/messages-recv.ts @@ -45,6 +45,7 @@ import { makeMutex } from '../Utils/make-mutex' import { areJidsSameUser, type BinaryNode, + binaryNodeToString, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, @@ -1272,7 +1273,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { }) ]) } catch (error) { - logger.error({ error, node }, 'error in handling message') + logger.error({ error, node: binaryNodeToString(node) }, 'error in handling message') } } diff --git a/src/Socket/messages-send.ts b/src/Socket/messages-send.ts index a380fd06..80e9aafd 100644 --- a/src/Socket/messages-send.ts +++ b/src/Socket/messages-send.ts @@ -44,8 +44,8 @@ import { getBinaryNodeChildren, getServerFromDomainType, isJidGroup, - isJidHostedLidUser, - isJidHostedPnUser, + isHostedLidUser, + isHostedPnUser, isLidUser, isPnUser, jidDecode, @@ -381,6 +381,8 @@ export const makeMessagesSocket = (config: SocketConfig) => { const uniqueJids = [...new Set(jids)] // Deduplicate JIDs const jidsRequiringFetch: string[] = [] + logger.debug({ jids }, 'assertSessions call with jids') + // Check peerSessionsCache and validate sessions using libsignal loadSession for (const jid of uniqueJids) { const signalId = signalRepository.jidToSignalProtocolAddress(jid) @@ -404,10 +406,10 @@ export const makeMessagesSocket = (config: SocketConfig) => { if (jidsRequiringFetch.length) { // LID if mapped, otherwise original const wireJids = [ - ...jidsRequiringFetch.filter(jid => !!jid.includes('@lid')), + ...jidsRequiringFetch.filter(jid => !!jid.includes('@lid') || !!jid.includes('@hosted.lid')), ...( (await signalRepository.lidMapping.getLIDsForPNs( - jidsRequiringFetch.filter(jid => !!jid.includes('@s.whatsapp.net')) + jidsRequiringFetch.filter(jid => !!jid.includes('@s.whatsapp.net') || !!jid.includes('@hosted')) )) || [] ).map(a => a.lid) ] @@ -715,8 +717,8 @@ export const makeMessagesSocket = (config: SocketConfig) => { const hasKey = !!senderKeyMap[deviceJid] if ( (!hasKey || !!participant) && - !isJidHostedLidUser(deviceJid) && - !isJidHostedPnUser(deviceJid) && + !isHostedLidUser(deviceJid) && + !isHostedPnUser(deviceJid) && device.device !== 99 ) { //todo: revamp all this logic @@ -839,7 +841,7 @@ export const makeMessagesSocket = (config: SocketConfig) => { } // Check if this is our device (could match either PN or LID user) - const isMe = user === mePnUser || (meLidUser && user === meLidUser) + const isMe = user === mePnUser || user === meLidUser if (isMe) { meRecipients.push(jid) diff --git a/src/Socket/socket.ts b/src/Socket/socket.ts index f46283cc..d6582cf2 100644 --- a/src/Socket/socket.ts +++ b/src/Socket/socket.ts @@ -423,7 +423,7 @@ export const makeSocket = (config: SocketConfig) => { let lastUploadTime = 0 /** generates and uploads a set of pre-keys to the server */ - const uploadPreKeys = async (count = INITIAL_PREKEY_COUNT, retryCount = 0) => { + const uploadPreKeys = async (count = MIN_PREKEY_COUNT, retryCount = 0) => { // Check minimum interval (except for retries) if (retryCount === 0) { const timeSinceLastUpload = Date.now() - lastUploadTime @@ -457,7 +457,7 @@ export const makeSocket = (config: SocketConfig) => { logger.info({ count }, 'uploaded pre-keys successfully') lastUploadTime = Date.now() } catch (uploadError) { - logger.error({ uploadError, count }, 'Failed to upload pre-keys to server') + logger.error({ uploadError: (uploadError as Error).toString(), count }, 'Failed to upload pre-keys to server') // Exponential backoff retry (max 3 retries) if (retryCount < 3) { @@ -500,13 +500,16 @@ export const makeSocket = (config: SocketConfig) => { const uploadPreKeysToServerIfRequired = async () => { try { + let count = 0 const preKeyCount = await getAvailablePreKeysOnServer() + if (preKeyCount == 0) count = INITIAL_PREKEY_COUNT + else count = MIN_PREKEY_COUNT const { exists: currentPreKeyExists, currentPreKeyId } = await verifyCurrentPreKeyExists() logger.info(`${preKeyCount} pre-keys found on server`) logger.info(`Current prekey ID: ${currentPreKeyId}, exists in storage: ${currentPreKeyExists}`) - const lowServerCount = preKeyCount <= MIN_PREKEY_COUNT + const lowServerCount = preKeyCount <= count const missingCurrentPreKey = !currentPreKeyExists && currentPreKeyId > 0 const shouldUpload = lowServerCount || missingCurrentPreKey @@ -517,7 +520,7 @@ export const makeSocket = (config: SocketConfig) => { if (missingCurrentPreKey) reasons.push(`current prekey ${currentPreKeyId} missing from storage`) logger.info(`Uploading PreKeys due to: ${reasons.join(', ')}`) - await uploadPreKeys() + await uploadPreKeys(count) } else { logger.info(`PreKey validation passed - Server: ${preKeyCount}, Current prekey ${currentPreKeyId} exists`) } diff --git a/src/Utils/decode-wa-message.ts b/src/Utils/decode-wa-message.ts index d4eb2d61..8e406876 100644 --- a/src/Utils/decode-wa-message.ts +++ b/src/Utils/decode-wa-message.ts @@ -7,8 +7,8 @@ import { type BinaryNode, isJidBroadcast, isJidGroup, - isJidHostedLidUser, - isJidHostedPnUser, + isHostedLidUser, + isHostedPnUser, isJidMetaAI, isJidNewsletter, isJidStatusBroadcast, @@ -134,7 +134,7 @@ export function decodeMessageNode(stanza: BinaryNode, meId: string, meLid: strin const isMe = (jid: string) => areJidsSameUser(jid, meId) const isMeLid = (jid: string) => areJidsSameUser(jid, meLid) - if (isPnUser(from) || isLidUser(from) || isJidHostedLidUser(from) || isJidHostedPnUser(from)) { + if (isPnUser(from) || isLidUser(from) || isHostedLidUser(from) || isHostedPnUser(from)) { if (recipient && !isJidMetaAI(recipient)) { if (!isMe(from!) && !isMeLid(from!)) { throw new Boom('receipient present, but msg not from me', { data: stanza }) diff --git a/src/Utils/process-message.ts b/src/Utils/process-message.ts index a8f817bb..df1759e3 100644 --- a/src/Utils/process-message.ts +++ b/src/Utils/process-message.ts @@ -20,8 +20,8 @@ import { getContentType, normalizeMessageContent } from '../Utils/messages' import { areJidsSameUser, isJidBroadcast, - isJidHostedLidUser, - isJidHostedPnUser, + isHostedLidUser, + isHostedPnUser, isJidStatusBroadcast, jidDecode, jidEncode, @@ -55,19 +55,19 @@ const REAL_MSG_REQ_ME_STUB_TYPES = new Set([WAMessageStubType.GROUP_PARTICIPANT_ /** Cleans a received message to further processing */ export const cleanMessage = (message: WAMessage, meId: string) => { // ensure remoteJid and participant doesn't have device or agent in it - if (isJidHostedPnUser(message.key.remoteJid!) || isJidHostedLidUser(message.key.remoteJid!)) { + if (isHostedPnUser(message.key.remoteJid!) || isHostedLidUser(message.key.remoteJid!)) { message.key.remoteJid = jidEncode( jidDecode(message.key?.remoteJid!)?.user!, - isJidHostedPnUser(message.key.remoteJid!) ? 's.whatsapp.net' : 'lid' + isHostedPnUser(message.key.remoteJid!) ? 's.whatsapp.net' : 'lid' ) } else { message.key.remoteJid = jidNormalizedUser(message.key.remoteJid!) } - if (isJidHostedPnUser(message.key.participant!) || isJidHostedLidUser(message.key.participant!)) { + if (isHostedPnUser(message.key.participant!) || isHostedLidUser(message.key.participant!)) { message.key.participant = jidEncode( jidDecode(message.key.participant!)?.user!, - isJidHostedPnUser(message.key.participant!) ? 's.whatsapp.net' : 'lid' + isHostedPnUser(message.key.participant!) ? 's.whatsapp.net' : 'lid' ) } else { message.key.participant = jidNormalizedUser(message.key.participant!) diff --git a/src/WABinary/jid-utils.ts b/src/WABinary/jid-utils.ts index 8a11c57c..d6995879 100644 --- a/src/WABinary/jid-utils.ts +++ b/src/WABinary/jid-utils.ts @@ -102,9 +102,9 @@ export const isJidStatusBroadcast = (jid: string) => jid === 'status@broadcast' /** is the jid a newsletter */ export const isJidNewsletter = (jid: string | undefined) => jid?.endsWith('@newsletter') /** is the jid a hosted PN */ -export const isJidHostedPnUser = (jid: string | undefined) => jid?.endsWith('@hosted') +export const isHostedPnUser = (jid: string | undefined) => jid?.endsWith('@hosted') /** is the jid a hosted LID */ -export const isJidHostedLidUser = (jid: string | undefined) => jid?.endsWith('@hosted.lid') +export const isHostedLidUser = (jid: string | undefined) => jid?.endsWith('@hosted.lid') const botRegexp = /^1313555\d{4}$|^131655500\d{2}$/