Skip to content

fix: extract LID-PN mappings from conversation objects in history sync - #2282

Merged
purpshell merged 2 commits into
masterfrom
fix-lid-pn-mapping-from-history-sync-conversations
Jan 22, 2026
Merged

fix: extract LID-PN mappings from conversation objects in history sync#2282
purpshell merged 2 commits into
masterfrom
fix-lid-pn-mapping-from-history-sync-conversations

Conversation

@jlucaso1

Copy link
Copy Markdown
Collaborator

Fixes an issue where LID-PN mappings from conversation objects in history sync were not being extracted and stored.

Related Issue: #2263
Related Comment: #2263 (comment)

Problem

@Jeferson-Ramos-Einov reported receiving chats in messaging-history.set with:

  • id: "152230971891797@lid" (LID format)
  • pnJid: "554199088675@s.whatsapp.net" (phone number available)

The LID-PN mapping was not being stored, preventing resolution of LID to phone number.

Root cause: Baileys only extracted mappings from the phoneNumberToLidMappings array at the top level of the history sync proto, but NOT from individual conversation objects.

How WhatsApp Web Handles This

Analysis of captured WhatsApp Web JavaScript (ftEKVbCt5NT.js, lines 109356-109386) shows they extract LID-PN mappings from both sources:

if (u.isUser()) {
  if (u.isLid()) {
    // Case 1: Chat ID is LID, extract pnJid
    var c = n.pnJid;
    if (c != null) {
      T.push({ lid: u, pn: createUserWidOrThrow(c) });
    }
  } else if (n.lidJid != null) {
    // Case 2: Chat ID is PN, extract lidJid
    T.push({ lid: createUserLidOrThrow(n.lidJid), pn: u });
  }
}

Solution

Added extraction logic in processHistoryMessage() to match WhatsApp Web:

const chatId = chat.id!
const isLid = isLidUser(chatId) || isHostedLidUser(chatId)
const isPn = isPnUser(chatId) || isHostedPnUser(chatId)
if (isLid && chat.pnJid) {
    lidPnMappings.push({ lid: chatId, pn: chat.pnJid })
} else if (isPn && chat.lidJid) {
    lidPnMappings.push({ lid: chat.lidJid, pn: chatId })
}

@whiskeysockets-bot

whiskeysockets-bot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor

Thanks for opening this pull request and contributing to the project!

The next step is for the maintainers to review your changes. If everything looks good, it will be approved and merged into the main branch.

In the meantime, anyone in the community is encouraged to test this pull request and provide feedback.

✅ How to confirm it works

If you’ve tested this PR, please comment below with:

Tested and working ✅

This helps us speed up the review and merge process.

📦 To test this PR locally:

# NPM
npm install @whiskeysockets/baileys@WhiskeySockets/Baileys#fix-lid-pn-mapping-from-history-sync-conversations

# Yarn (v2+)
yarn add @whiskeysockets/baileys@WhiskeySockets/Baileys#fix-lid-pn-mapping-from-history-sync-conversations

# PNPM
pnpm add @whiskeysockets/baileys@WhiskeySockets/Baileys#fix-lid-pn-mapping-from-history-sync-conversations

If you encounter any issues or have feedback, feel free to comment as well.

rsalcara pushed a commit to rsalcara/InfiniteAPI that referenced this pull request Jan 20, 2026
WhatsApp provides LID-PN mappings in two locations within history sync:
1. Top-level `phoneNumberToLidMappings` array (already processed)
2. Individual conversation objects with `lidJid`/`pnJid` properties (new)

This change adds extraction from conversation objects, ensuring maximum
mapping coverage regardless of sync type or payload structure.

Key improvements:
- Add `extractLidPnFromConversation()` function with comprehensive JSDoc
- Use Map for O(1) deduplication of mappings across both sources
- Handle all JID formats: @lid, @hosted.lid, @s.whatsapp.net, @HosteD
- Normalize JIDs using `jidNormalizedUser()` for consistency
- Skip group chats (@g.us) that don't have LID-PN mappings

Includes 22 comprehensive tests covering:
- LID chat with pnJid extraction
- PN chat with lidJid extraction
- Hosted format handling
- Deduplication between sources
- Edge cases (nulls, groups, missing data)
- All conversation sync types

Related: WhiskeySockets#2263
See-also: WhiskeySockets#2282
rsalcara pushed a commit to rsalcara/InfiniteAPI that referenced this pull request Jan 21, 2026
…ys PR

This folder contains the files ready for upstream WhiskeySockets/Baileys PR:

Changes to src/Utils/history.ts:
- Add isPersonJid() helper to validate JID types for mapping eligibility
- Add extractLidPnFromConversation() for conversation-level mapping extraction
- Add extractLidPnFromMessage() for message-level mapping extraction
- Modify processHistoryMessage() to extract from 3 sources with deduplication
- Fix validation bug: use || (OR) instead of && (AND) to prevent poisoned mappings

Changes to src/__tests__/Utils/history.test.ts:
- 55 comprehensive tests covering all new functions and edge cases
- Tests for all JID formats (@lid, @hosted.lid, @s.whatsapp.net, @HosteD)
- Tests for skipped JIDs (@g.us, @broadcast, @newsletter)
- Tests for bug fix validation (person + group, person + broadcast, etc.)
- Tests for deduplication across all three sources

Related issues:
- Closes WhiskeySockets#2282
- Partially addresses WhiskeySockets#2281
@Jeferson-Ramos-Einov

Copy link
Copy Markdown

@jlucaso1 Amigo tenho um caso onde pnJid não existe porem dentro da mensagem o remoteJid esta presente:

{ "participant": [], "id": "211071956705386@lid", "unreadCount": 0, "readOnly": false, "ephemeralExpiration": 0, "ephemeralSettingTimestamp": { "low": 0, "high": 0, "unsigned": false }, "conversationTimestamp": { "low": 1768320044, "high": 0, "unsigned": true }, "notSpam": true, "archived": false, "disappearingMode": { "initiator": "CHANGED_IN_CHAT", "trigger": "CHAT_SETTING", "initiatedByMe": false }, "unreadMentionCount": 0, "tcToken": { "type": "Buffer", "data": [ 4, 1, 30, 107, 55, 30, 173, 70, 144, 141, 52 ] }, "tcTokenTimestamp": { "low": 1768320009, "high": 0, "unsigned": true }, "contactPrimaryIdentityKey": { "type": "Buffer", "data": [ 217, 18, 128, 144, 15, 104, 255, 252, 32, 172, 103, 5, 223, 134, 11, 166, 224, 81, 78, 195, 38, 115, 184, 155, 135, 241, 149, 119, 152, 114, 80, 38 ] }, "tcTokenSenderTimestamp": { "low": 1768311770, "high": 0, "unsigned": true }, "terminated": false, "isDefaultSubgroup": false, "shareOwnPn": false, "locked": false, "limitSharing": false, "limitSharingSettingTimestamp": { "low": 0, "high": 0, "unsigned": false }, "limitSharingTrigger": 0, "limitSharingInitiatedByMe": false, "messages": [ { "message": { "key": { "remoteJid": "211071956705386@lid", "fromMe": true, "id": "3EB052FF8D9D00646C9994" }, "message": { "extendedTextMessage": { "text": "Oi, João!", "contextInfo": { "expiration": 0, "ephemeralSettingTimestamp": "1768147242" } } }, "messageTimestamp": "1768320044", "status": "READ", "userReceipt": [ { "userJid": "551838211855@s.whatsapp.net", "receiptTimestamp": "1768320045", "readTimestamp": "1768327083", "playedTimestamp": "0", "deliveredDeviceJid": [ "551838211855:0@s.whatsapp.net", "551838211855:93@s.whatsapp.net" ] } ], "originalSelfAuthorUserJidString": "188472275030054@lid", "interactiveMessageAdditionalMetadata": { "isGalaxyFlowCompleted": false } } } ], "lastMessageRecvTimestamp": 1768320009 }

@jlucaso1

Copy link
Copy Markdown
Collaborator Author

@Jeferson-Ramos-Einov added this edge case too. Thank you <3

@jlucaso1
jlucaso1 force-pushed the fix-lid-pn-mapping-from-history-sync-conversations branch from 1d24433 to 83d8a08 Compare January 21, 2026 13:06
@Jeferson-Ramos-Einov

Copy link
Copy Markdown

@jlucaso1 Cara a ultima acredito eu, existem casos onde o remoteJid não existe nesse mesmo contexto

{ "participant": [], "id": "213142651035807@lid", "unreadCount": 0, "readOnly": false, "ephemeralExpiration": 0, "ephemeralSettingTimestamp": { "low": 0, "high": 0, "unsigned": false }, "conversationTimestamp": { "low": 1767872448, "high": 0, "unsigned": true }, "notSpam": true, "archived": false, "disappearingMode": { "initiator": "CHANGED_IN_CHAT", "trigger": "CHAT_SETTING", "initiatedByMe": false }, "unreadMentionCount": 0, "tcToken": { "type": "Buffer", "data": [ 4, 1, 30, 112, 146, 199, 182, 102, 138, 59, 47 ] }, "tcTokenTimestamp": { "low": 1767872448, "high": 0, "unsigned": true }, "tcTokenSenderTimestamp": { "low": 1767731406, "high": 0, "unsigned": true }, "terminated": false, "isDefaultSubgroup": false, "shareOwnPn": false, "locked": false, "limitSharing": false, "limitSharingSettingTimestamp": { "low": 0, "high": 0, "unsigned": false }, "limitSharingTrigger": 0, "limitSharingInitiatedByMe": false, "messages": [ { "message": { "key": { "remoteJid": "213142651035807@lid", "fromMe": false, "id": "2A5B8A5FF1E97E688A1C" }, "messageTimestamp": "1768936342", "messageStubType": "BIZ_PRIVACY_MODE_TO_FB", "messageStubParameters": [ "" ], "interactiveMessageAdditionalMetadata": { "isGalaxyFlowCompleted": false } } } ], "lastMessageRecvTimestamp": 1768936342 }

@jlucaso1

Copy link
Copy Markdown
Collaborator Author

@jlucaso1 Cara a ultima acredito eu, existem casos onde o remoteJid não existe nesse mesmo contexto

{ "participant": [], "id": "213142651035807@lid", "unreadCount": 0, "readOnly": false, "ephemeralExpiration": 0, "ephemeralSettingTimestamp": { "low": 0, "high": 0, "unsigned": false }, "conversationTimestamp": { "low": 1767872448, "high": 0, "unsigned": true }, "notSpam": true, "archived": false, "disappearingMode": { "initiator": "CHANGED_IN_CHAT", "trigger": "CHAT_SETTING", "initiatedByMe": false }, "unreadMentionCount": 0, "tcToken": { "type": "Buffer", "data": [ 4, 1, 30, 112, 146, 199, 182, 102, 138, 59, 47 ] }, "tcTokenTimestamp": { "low": 1767872448, "high": 0, "unsigned": true }, "tcTokenSenderTimestamp": { "low": 1767731406, "high": 0, "unsigned": true }, "terminated": false, "isDefaultSubgroup": false, "shareOwnPn": false, "locked": false, "limitSharing": false, "limitSharingSettingTimestamp": { "low": 0, "high": 0, "unsigned": false }, "limitSharingTrigger": 0, "limitSharingInitiatedByMe": false, "messages": [ { "message": { "key": { "remoteJid": "213142651035807@lid", "fromMe": false, "id": "2A5B8A5FF1E97E688A1C" }, "messageTimestamp": "1768936342", "messageStubType": "BIZ_PRIVACY_MODE_TO_FB", "messageStubParameters": [ "" ], "interactiveMessageAdditionalMetadata": { "isGalaxyFlowCompleted": false } } } ], "lastMessageRecvTimestamp": 1768936342 }

Nesse caso não tem nada que possamos fazer, o chat é apenas LID, não tem como extrair o PN nessse caso.

@purpshell

Copy link
Copy Markdown
Member

Nesse caso não tem nada que possamos fazer, o chat é apenas LID, não tem como extrair o PN nessse caso.

other than to use requestPhoneNumber message

@purpshell

Copy link
Copy Markdown
Member

BIZ_PRIVACY_MODE_TO_FB

This is a Meta Ads chat, WhatsApp hides the phone number for the privacy of the users involved in this chat, as you can see on the app there exists a "+55•••••••4534" phone number

@purpshell
purpshell merged commit f829b6d into master Jan 22, 2026
4 checks passed
@Jeferson-Ramos-Einov

Copy link
Copy Markdown

@purpshell I can locate the chat on WhatsApp Web by the message content. Within WhatsApp Web, this chat has a phone number.

rsalcara pushed a commit to rsalcara/InfiniteAPI that referenced this pull request Jan 22, 2026
Add extractPnFromMessages() function to extract phone numbers from
userReceipt fields when pnJid is missing in LID conversations.

This is a cherry-pick of the functionality from upstream PR WhiskeySockets#2282
(commit f829b6d) integrated with our existing LID-PN extraction logic.

Closes: WhiskeySockets#2282
ViperTecCorporation pushed a commit to ViperTecCorporation/Baileys that referenced this pull request Jan 23, 2026
WhiskeySockets#2282)

* fix: extract LID-PN mappings from conversation objects in history sync

* fix: extract PN from userReceipt when pnJid is missing for LID chats
purpshell added a commit that referenced this pull request Feb 24, 2026
* Add Feature LabelMember (Based on #2164) (#2198)

* fix: improve message resend logic by adding checks for message IDs

* Revert "fix: improve message resend logic by adding checks for message IDs"

This reverts commit c03f9d8.

* feat: add group member label update functionality and event emission

* feat: refactor updateMemberLabel function for improved readability

* feat: use optional chaining for label association message in processMessage

* feat: add updateMemberLabel to makeMessagesSocket for enhanced functionality

* fix: correct log message for group member tag update event

Co-authored-by: FgsiDev

* feat: Verify leaf signature (#2208)

* Update WA_CERT_DETAILS with issuer and public key

* certificate validation

* fix:lint

* padding

* lint: fix tab

---------

Co-authored-by: skidy89 <tutorialesyg310@gmail.com>

* implement message reporting tokens (#1906)

* feat: implement message reporting tokens and privacy token handling

* feat: add support for privacy tokens in profile picture requests and history sync

* chore: pr feedback purpshell

* fix: improve privacy token handling and error messaging in socket configuration

* feat: enhance privacy token handling with improved sender mapping

* chore: removing tc token in favor of #2080

* chore: revert some unecessary changes

* feat(reporting): enhance reporting token extraction and compilation logic

* feat(reporting): add unit tests for reporting token utilities

* fix(reporting): streamline reporting token attachment logic in message sending

* fix: adjust reporting token inclusion logic to prevent retries

* chore: add return type to shouldIncludeReportingToken and improve getToken function type safety

* fix: getmessagetype to ensure consistency with whatsapp behavior (#2245)

* fix: avoid variable shadowing and preserve empty business profile fields (#2183)

* Update business.ts

* chore: fix lint issues

* feat: add support for FB and Interop JID encoding/decoding and empty strings (#2189)

* fix(messages): handle encryption failures per recipient and fail when all fail (#2226)

* fix(WAProto): Handle string values in long fields during JSON serialization (#1991)

* feat: add patch-tojson functionality for improved proto serialization

* Remove patch-tojson functionality and its import from the main index file to streamline the codebase.

* refactor: simplify longToString and longToNumber functions for better readability and performance

* feat: implement automated WhatsApp version update workflow and related scripts (#2130)

* feat: implement automated WhatsApp version update workflow and related scripts

* change cron to weekly

---------

Co-authored-by: Rajeh Taher <rajeh@reforward.dev>

* feat: send tctoken to profile update and presence subscribe (#2257)

* fix: improve message resend logic by adding checks for message IDs

* Revert "fix: improve message resend logic by adding checks for message IDs"

This reverts commit c03f9d8.

* feat(tc-token): implement buildTcTokenFromJid utility and integrate into chats socket

* fix(tc-token): ensure consistent return value when tcTokenBuffer is absent

* fix(chats): update import path for buildTcTokenFromJid utility

* moved retryCount before validating the session (#2167)

* fix(messages): enhance nullish value checks in message content generation (#2180)

* Feat improve testing coverage e2e (#1799)

* fix: ensure proper socket closure and await connection termination in tests

* feat(tests): enhance E2E tests for image and video message handling, including downloads and group interactions

* chore: lint+bugfix

* messages-recv: decrease PDO response timeout

* gitignore: fix ignoring logs coming from example file

* messages-send: revamp message type function

* process-message: remove timeout before event emit

* Fix critical memory leak in event buffer (#2160)

* fix(proto-extract): regenerate corrupted yarn.lock to restore install process (#1981)

* fix(proto-extract): regenerate corrupted yarn.lock to restore install process

* chore(proto-extract): update acorn parser to latest version for compatibility with new WhatsApp JS syntax

* Update baileys version to 2.3000.1029027441

* Update version number in Defaults index

* Revert WAProto.proto to resolve merge conflict and restore expected structure

---------

Co-authored-by: Vrypt <vryptt@gmail.com>
Co-authored-by: Rajeh Taher <rajeh@reforward.dev>

* connection-deadlock, socket: improve socket end conditions

* chore: lint

* example: improve ping-pong

* example: customizable socket URL

* example: revamp example and add options for unit tests

* chore: update WhatsApp Web version (#2269)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* fix: resolve race condition in decodeFrame handling and improve encryption integrity (#2182)

* fix: resolve race condition in decodeFrame handling and improve encryption integrity

* chore: pr feedback

* chore: Add messageTimestamp to message updates in messages-recv when receiving a message status update (#2277)

* fix: extract LID-PN mappings from history sync phoneNumberToLidMappings (#2268)

* fix: store LID-PN mapping from contactAction sync (#2266)

* fix: store LID-PN mapping from contactAction sync

* chore: improve testing of sync actions

* Add groupStatusMessage checks in message handling (#2258)

* Cache the children after a getBinaryNodeChild/ren call to avoid traversing arrays (#2093)

* generic-utils: cache the get

* generic-utils: increased type safety

* chore: lint

* fix(utils.normalizeMessageContent): add associatedChildMessage as one of the options to normalize (#1874)

Co-authored-by: Rajeh Taher <rajeh@reforward.dev>

* chore(tests): lint

* chat-utils,sync-action-utils: provide alternatives for the contact name

* example: revamp logging for example

* defaults, index: change shouldSyncHistoryMessage behavior

* history: fortify contact data

* history: add proper logging support in history

* example: cleanup

* socket: no sync warning!!!!!

* Fix connection showing "Online" but disconnected (#2132) (#2264)

* fix(messages): handle identity change notifications correctly (#2132)

* fix: tests and linting, add a helper like waweb

* fix: skip retry for expired status messages over 24 hours old (#2280)

* fix: optimize getLIDsForPNs and add getPNsForLIDs (#2274)

* fix: optimize lid-mapping and add getpnsforlids

* fix: lint

* fix: reintroduce store and fix partial returns

* fix: lint

* fix: extract LID-PN mappings from conversation objects in history sync (#2282)

* fix: extract LID-PN mappings from conversation objects in history sync

* fix: extract PN from userReceipt when pnJid is missing for LID chats

* feat: send unified session (#2294)

* fix: improve message resend logic by adding checks for message IDs

* Revert "fix: improve message resend logic by adding checks for message IDs"

This reverts commit c03f9d8.

* feat: add unified session handling and time constants

* refactor: improve socket variable destructuring and presence update logic

* fix: remove unnecessary semicolons in socket and time constants definitions

* fix: handle invalid server time offset parsing in makeSocket function

* fix: align noise-handler buffer types for Baileys build (#2284)

* fix: align noise-handler buffer types for Baileys build

* Align noise handler buffer types

* Clarify noise handler buffer typing

* perf: reduce DB calls during sync with caching and batching (#2316)

* perf: reduce DB calls during sync with caching and batching

* refactor: clean up comments and improve LID-PN mapping storage during history sync

* feat: replace async crypto with sync Rust WASM for app state sync (#2315)

* feat: replace async crypto with sync Rust WASM for app state sync

* fix: remove unecessary buffer copying

* fix: update whatsapp-rust-bridge to version 0.5.2 and refactor async calls to sync. HKDF and MD5 in rust

* fix: detect identity key changes and reset sessions (align with WA Web) (#2307)

* feat(signal): add RetryReason enum and MAC error-based session recreation

* feat(signal): add identity change detection with automatic session clearing

* fix(signal): integrate identity change detection with pkmsg decryption

This completes the identity change detection implementation by actually
calling saveIdentity() during pkmsg decryption, which is CRITICAL for
the feature to work.

Changes:
- Add extractIdentityFromPkmsg() function that parses PreKeyWhisperMessage
  protobuf to extract sender's identity key (33 bytes)
- Call saveIdentity() BEFORE decryption in decryptMessage() for pkmsg type
- Log when identity change is detected

Flow:
1. Receive pkmsg from sender
2. Extract identity key from PreKeyWhisperMessage protobuf
3. Call storage.saveIdentity() which compares with stored key
4. If key changed → session is cleared atomically
5. Decryption proceeds with re-established session

This matches WhatsApp Web's behavior where extractIdentityKey is called
before handleNewSession (GysEGRAXCvh.js:40917, 48815).

Ref: WhatsApp Web's extractIdentityKey (GysEGRAXCvh.js:48976-48998)

* chore: update WhatsApp Web version (#2330)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* feat(call): add caller phone number to offer call event (#2190)

* fix: request placeholder resend for messages without encryption (CTWAads) (#2334)

* fix: request placeholder resend for messages without encryption (CTWA ads)

* fix: implement placeholder resend cache management and metadata preservation

---------

Co-authored-by: Matheus Filype <67132916+Santosl2@users.noreply.github.com>
Co-authored-by: Skid <112231743+Skidy89@users.noreply.github.com>
Co-authored-by: skidy89 <tutorialesyg310@gmail.com>
Co-authored-by: João Lucas de Oliveira Lopes <55464917+jlucaso1@users.noreply.github.com>
Co-authored-by: Gustavo Quadri <87215048+gusquadri@users.noreply.github.com>
Co-authored-by: Ibrahim Pelumi Lasisi <113442282+ibrahimpelumi6142@users.noreply.github.com>
Co-authored-by: vini <viniwarrior4@gmail.com>
Co-authored-by: YonkoSam <161728760+YonkoSam@users.noreply.github.com>
Co-authored-by: Vrypt <keriptozzzzz@gmail.com>
Co-authored-by: Vrypt <vryptt@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Luiz Braga <btmluiz@outlook.com>
Co-authored-by: David ??? <86541514+DavidModzz@users.noreply.github.com>
Co-authored-by: Enzo Nascimento <143226080+devenzonascimento@users.noreply.github.com>
Co-authored-by: Ahmed Alwahib <aalwheep@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants