fix(WhatsApp): resolve LID jids through jid_map for 1:1 and group messages by AndroidIosForensik · Pull Request #1453 · abrignoni/ALEAPP · GitHub
Skip to content

fix(WhatsApp): resolve LID jids through jid_map for 1:1 and group messages - #1453

Merged
abrignoni merged 1 commit into
abrignoni:mainfrom
AndroidIosForensik:fix/whatsapp-lid-contacts
Sep 28, 2026
Merged

abrignoni merged 1 commit into
abrignoni:mainfrom
AndroidIosForensik:fix/whatsapp-lid-contacts

Conversation

@AndroidIosForensik

Copy link
Copy Markdown
Contributor

Problem

Newer WhatsApp msgstore.db files key 1:1 chats, and the sender of group messages, by a LID jid (…@lid). wa.db's wa_contacts.jid holds the …@s.whatsapp.net form.

  • WhatsApp - One To One Messages joined wa_contacts on the chat's own jid.raw_string with an inner JOIN. Every message in a LID-keyed chat was dropped, and so was every message in a chat with no wa_contacts row. On the device below the artifact produced no output at all although msgstore.db holds 29 1:1 messages.
  • WhatsApp - Group Messages kept the rows (it already used LEFT JOIN), but Sending Party was empty for every LID sender.

Change

msgstore.db has a jid_map table (lid_row_id INTEGER PRIMARY KEY, jid_row_id INTEGER, sort_id INTEGER) linking a LID jid row to a phone-number jid row. A new helper _contact_jid() adds LEFT JOIN jid_map / LEFT JOIN jid AS mapped_jid and matches wa_contacts.jid against COALESCE(mapped_jid.raw_string, jid.raw_string). When jid_map does not exist (older databases) the query is the same as before apart from the points below.

  • 1:1: the wa_contacts join is now a LEFT JOIN, so messages whose chat matches no contact are reported instead of dropped.
  • 1:1 Other Participant WA User Name and group Sending Party: when no contact matches, or wa_name is NULL/empty, the value falls back to the jid (mapped phone-number jid if there is one, otherwise the chat's/sender's own jid). This follows the jid fallback get_whatsapp_contacts already uses for Name, and keeps distinct chats distinct in the conversation view instead of merging every nameless chat under an empty discriminator.
  • Sending Party JID falls back the same way when no contact matches.
  • notes and last_update_date updated for both artifacts. Headers and column order are unchanged.

Evidence

Data-proven on one device: Pixel 10, Android 17, com.whatsapp versionName 2.26.36.74 (vc 263607422), full-file-system extraction. Counts measured with direct SQL on msgstore.db/wa.db and compared against ALEAPP output before and after:

before after direct SQL
One To One Messages rows 0 (artifact not produced) 29 in 6 chats 29 messages with recipient_count=0
of which chat keyed by @lid 0 26 26, all 26 with a jid_map row whose mapped jid is in wa_contacts
of which chat keyed by @s.whatsapp.net without contact 0 3 3
Group Messages rows 19 19
incoming group rows with empty Sending Party 7 of 7 0 of 7 7 senders keyed by @lid, all resolved through jid_map

On this device 18 of the 29 1:1 rows show a jid as participant name (the 3 contactless rows plus rows whose contact has no wa_name).

What jid_map means is inferred from its column names, its jid_bd_for_jid_map_trigger (DELETE FROM jid_map WHERE jid_row_id=old._id OR lid_row_id=old._id) and the result above; no WhatsApp source documents it. The mapping is evidenced on this one device only.

Tests

admin/test/scripts/test_whatsapp_lid_contacts.py builds synthetic msgstore.db/wa.db files (no real evidence bytes): a LID-keyed chat with a jid_map row, a phone-keyed chat, a contactless chat and a group with a LID sender, plus a variant without jid_map. All three tests fail on main and pass with this change.

  • Full unittest discover -s admin/test/scripts (rebased on fb0518e): 547 tests, the only failures are 5 in test_dependency_compatibility / test_sourcepath_helper, which fail identically on unmodified main on this Windows machine (WinError 32 file lock in temp cleanup).
  • pylint --disable=C,R on both files: 10.00/10; lint_changed.py --base-ref origin/main: no new warnings.
  • check_claim_language, check_conversation_column_order, check_artifact_paths, check_implicit_concat, check_artifact_descriptions, check_artifact_returns, check_source_path, check_html_safety: pass. check_source_file_column reports data_headers is not literal for the two message artifacts, same as on main.

Not covered

  • The sample_data row counts were not re-measured; images whose chats are LID-keyed will report more 1:1 rows.
  • get_whatsapp_call_logs still uses an inner JOIN wa_contacts ON wa_contacts.jid=jid.raw_string, so LID-keyed calls would be dropped the same way. Not changed here: the test device has no call log rows, so the fix would be unexercised.
  • whatsAppExtended.py already uses LEFT JOINs, so no rows are lost there, but its contact names are not resolved for LID jids.
  • The 1 message with recipient_count NULL on this device is excluded by both queries, as before.
  • iLEAPP's WhatsApp artifact reads iOS ChatStorage.sqlite, a different schema; not checked for an equivalent issue.

🤖 Generated with Claude Code

…sages

Newer msgstore.db files key 1:1 chats and group senders by a LID jid
(...@lid), while wa.db's wa_contacts.jid holds the ...@s.whatsapp.net form.
The 1:1 artifact inner-joined wa_contacts on the chat's own jid, so every
message in a LID-keyed chat, and in any chat without a contact row, was
dropped. The group artifact kept its rows but left Sending Party empty for
LID senders.

Match wa_contacts through msgstore.db jid_map (lid_row_id -> jid_row_id)
when that table exists, make the 1:1 contact join a LEFT JOIN, and fall
back to the jid when no contact or WhatsApp name is found.

On one Pixel 10 / Android 17 / WhatsApp 2.26.36.74 extraction: 1:1 rows
0 -> 29 (29 in msgstore.db), group rows with an empty sender 7 -> 0.
Synthetic-database tests added; they fail on the previous code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

@github-actions github-actions Bot added the fixture-needed Cites a public image; a maintainer can generate the fixture label Sep 27, 2026
@abrignoni
abrignoni merged commit 69d6c32 into abrignoni:main Sep 28, 2026
1 check passed
@AndroidIosForensik
AndroidIosForensik deleted the fix/whatsapp-lid-contacts branch September 28, 2026 20:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fixture-needed Cites a public image; a maintainer can generate the fixture

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants