libsignal,lid-mapping, etc.: Partially fix "No sessions" on hosted JIDs
This commit is contained in:
@@ -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<string> => {
|
||||
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()
|
||||
|
||||
@@ -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<string, string>({
|
||||
@@ -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`
|
||||
}
|
||||
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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`)
|
||||
}
|
||||
|
||||
@@ -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 })
|
||||
|
||||
@@ -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!)
|
||||
|
||||
@@ -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}$/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user