mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-10 01:20:49 +08:00
Hide WhatsApp LID ids from session-header peer labels (4.9.1-ops.21).
Resolve nickname/phone via contact LID mapping and show only group title, pushName, and phone. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
37742043a9
commit
a92080e490
5 changed files with 331 additions and 215 deletions
|
|
@ -25,10 +25,56 @@ export function parseConversationKey(key) {
|
|||
return conversationId ? { kind: 'group', conversationId, senderId: null } : null;
|
||||
}
|
||||
|
||||
function contactPushName(grant, phone) {
|
||||
if (!phone || !grant || !Array.isArray(grant.contacts)) return '';
|
||||
const hit = grant.contacts.find((contact) => contact?.phone === phone);
|
||||
return typeof hit?.pushName === 'string' ? hit.pushName.trim() : '';
|
||||
/**
|
||||
* Normalize a WhatsApp LID identity for contact matching.
|
||||
* Accepts `digits@lid`, `digits:device@lid`, or a bare lid token already stored on contacts.
|
||||
* @param {unknown} value
|
||||
* @returns {string|null}
|
||||
*/
|
||||
export function lidFromWhatsappIdentity(value) {
|
||||
if (typeof value !== 'string') return null;
|
||||
const raw = value.trim();
|
||||
if (!raw) return null;
|
||||
const at = raw.indexOf('@');
|
||||
if (at > 0) {
|
||||
const server = raw.slice(at + 1).toLowerCase();
|
||||
if (server !== 'lid' && server !== 'hosted.lid') return null;
|
||||
const user = raw.slice(0, at).split(':')[0].trim();
|
||||
return user ? `${user}@lid` : null;
|
||||
}
|
||||
// Contacts may already store the canonical `digits@lid` form only.
|
||||
return null;
|
||||
}
|
||||
|
||||
function lidsMatch(stored, needle) {
|
||||
if (typeof stored !== 'string' || !needle) return false;
|
||||
const left = lidFromWhatsappIdentity(stored) ?? stored.trim();
|
||||
return left === needle || left === needle.replace(/@lid$/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve contact phone/pushName from grant by PN or LID.
|
||||
* @param {object|null} grant
|
||||
* @param {string|null} identity
|
||||
* @returns {{ phone: string|null, pushName: string|null }}
|
||||
*/
|
||||
export function resolveContactIdentity(grant, identity) {
|
||||
const phone = phoneFromWhatsappJid(identity) ?? normalizeAccessPhone(identity);
|
||||
const lid = lidFromWhatsappIdentity(identity);
|
||||
const contacts = Array.isArray(grant?.contacts) ? grant.contacts : [];
|
||||
const hit = contacts.find((contact) => {
|
||||
if (phone && contact?.phone === phone) return true;
|
||||
if (lid && Array.isArray(contact?.lids) && contact.lids.some((entry) => lidsMatch(entry, lid))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}) ?? null;
|
||||
const resolvedPhone = phone
|
||||
?? (typeof hit?.phone === 'string' && hit.phone ? hit.phone : null);
|
||||
const pushName = typeof hit?.pushName === 'string' && hit.pushName.trim()
|
||||
? hit.pushName.trim()
|
||||
: null;
|
||||
return { phone: resolvedPhone, pushName };
|
||||
}
|
||||
|
||||
function groupTitle(grant, groupJid) {
|
||||
|
|
@ -36,12 +82,21 @@ function groupTitle(grant, groupJid) {
|
|||
return typeof title === 'string' && title.trim() ? title.trim() : '';
|
||||
}
|
||||
|
||||
function phoneFromIdentity(value) {
|
||||
return phoneFromWhatsappJid(value) ?? normalizeAccessPhone(value);
|
||||
/**
|
||||
* Join human-facing label parts. Never includes raw JIDs / LIDs.
|
||||
* @param {...(string|null|undefined)} parts
|
||||
* @returns {string}
|
||||
*/
|
||||
export function formatChannelPeerLabel(...parts) {
|
||||
return parts
|
||||
.map((part) => (typeof part === 'string' ? part.trim() : ''))
|
||||
.filter(Boolean)
|
||||
.join(' · ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a public channel-peer summary for session-header display.
|
||||
* Label shows only group title / nickname / phone — never opaque WhatsApp ids.
|
||||
* @param {{
|
||||
* channel: string,
|
||||
* botId: string,
|
||||
|
|
@ -61,12 +116,9 @@ export function resolveChannelPeerFromBinding(input) {
|
|||
const grant = input.grant && typeof input.grant === 'object' ? input.grant : null;
|
||||
|
||||
if (parsed.kind === 'direct') {
|
||||
const phone = phoneFromIdentity(parsed.conversationId);
|
||||
const pushName = contactPushName(grant, phone);
|
||||
const who = pushName || phone || parsed.conversationId;
|
||||
const label = phone && pushName && pushName !== phone
|
||||
? `${pushName} · ${phone}`
|
||||
: who;
|
||||
const { phone, pushName } = resolveContactIdentity(grant, parsed.conversationId);
|
||||
const label = formatChannelPeerLabel(pushName, phone);
|
||||
if (!label) return null;
|
||||
return Object.freeze({
|
||||
channel,
|
||||
botId,
|
||||
|
|
@ -74,8 +126,8 @@ export function resolveChannelPeerFromBinding(input) {
|
|||
conversationKey,
|
||||
conversationId: parsed.conversationId,
|
||||
senderId: null,
|
||||
phone: phone || null,
|
||||
pushName: pushName || null,
|
||||
phone,
|
||||
pushName,
|
||||
groupTitle: null,
|
||||
label,
|
||||
});
|
||||
|
|
@ -93,13 +145,12 @@ export function resolveChannelPeerFromBinding(input) {
|
|||
phone: null,
|
||||
pushName: null,
|
||||
groupTitle: title,
|
||||
label: `群 · ${title}`,
|
||||
label: title,
|
||||
});
|
||||
}
|
||||
|
||||
const phone = phoneFromIdentity(parsed.senderId);
|
||||
const pushName = contactPushName(grant, phone);
|
||||
const who = pushName || phone || parsed.senderId;
|
||||
const { phone, pushName } = resolveContactIdentity(grant, parsed.senderId);
|
||||
const label = formatChannelPeerLabel(title, pushName, phone) || title;
|
||||
return Object.freeze({
|
||||
channel,
|
||||
botId,
|
||||
|
|
@ -107,9 +158,9 @@ export function resolveChannelPeerFromBinding(input) {
|
|||
conversationKey,
|
||||
conversationId: parsed.conversationId,
|
||||
senderId: parsed.senderId,
|
||||
phone: phone || null,
|
||||
pushName: pushName || null,
|
||||
phone,
|
||||
pushName,
|
||||
groupTitle: title,
|
||||
label: `${title} · ${who}`,
|
||||
label,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue