diff --git a/src/Socket/groups.ts b/src/Socket/groups.ts index 0c4716da326..18cab5c642b 100644 --- a/src/Socket/groups.ts +++ b/src/Socket/groups.ts @@ -343,11 +343,13 @@ export const extractGroupMetadata = (result: BinaryNode) => { let descId: string | undefined let descOwner: string | undefined let descOwnerPn: string | undefined + let descOwnerUsername: string | undefined let descTime: number | undefined if (descChild) { desc = getBinaryNodeChildString(descChild, 'body') descOwner = descChild.attrs.participant ? jidNormalizedUser(descChild.attrs.participant) : undefined descOwnerPn = descChild.attrs.participant_pn ? jidNormalizedUser(descChild.attrs.participant_pn) : undefined + descOwnerUsername = descChild.attrs.participant_username || undefined descTime = +descChild.attrs.t! descId = descChild.attrs.id } @@ -362,16 +364,19 @@ export const extractGroupMetadata = (result: BinaryNode) => { subject: group.attrs.subject!, subjectOwner: group.attrs.s_o, subjectOwnerPn: group.attrs.s_o_pn, + subjectOwnerUsername: group.attrs.s_o_username, subjectTime: +(group.attrs.s_t ?? '0'), size: group.attrs.size ? +group.attrs.size : getBinaryNodeChildren(group, 'participant').length, creation: +(group.attrs.creation ?? '0'), owner: group.attrs.creator ? jidNormalizedUser(group.attrs.creator) : undefined, ownerPn: group.attrs.creator_pn ? jidNormalizedUser(group.attrs.creator_pn) : undefined, + ownerUsername: group.attrs.creator_username || undefined, owner_country_code: group.attrs.creator_country_code, desc, descId, descOwner, descOwnerPn, + descOwnerUsername, descTime, linkedParent: getBinaryNodeChild(group, 'linked_parent')?.attrs.jid || undefined, restrict: !!getBinaryNodeChild(group, 'locked'), @@ -386,6 +391,7 @@ export const extractGroupMetadata = (result: BinaryNode) => { id: attrs.jid!, phoneNumber: isLidUser(attrs.jid) && isPnUser(attrs.phone_number) ? attrs.phone_number : undefined, lid: isPnUser(attrs.jid) && isLidUser(attrs.lid) ? attrs.lid : undefined, + username: attrs.participant_username || attrs.username || undefined, admin: (attrs.type || null) as GroupParticipant['admin'] } }), diff --git a/src/Socket/messages-recv.ts b/src/Socket/messages-recv.ts index 51f9c5e1879..53723194903 100644 --- a/src/Socket/messages-recv.ts +++ b/src/Socket/messages-recv.ts @@ -2223,6 +2223,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { fromMe, participant: node.attrs.participant, participantAlt, + participantUsername: node.attrs.participant_username, addressingMode, id: node.attrs.id, ...(msg.key || {}) @@ -2231,6 +2232,10 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { msg.messageTimestamp = +node.attrs.t! const fullMsg = proto.WebMessageInfo.fromObject(msg) as WAMessage + // Preserve custom WAMessageKey fields (participantAlt, participantUsername, + // addressingMode) that proto.WebMessageInfo.fromObject strips because + // they aren't part of the proto.MessageKey schema. + fullMsg.key = msg.key await upsertMessage(fullMsg, 'append') } }) diff --git a/src/Types/Contact.ts b/src/Types/Contact.ts index 315f7e15edc..836185b8125 100644 --- a/src/Types/Contact.ts +++ b/src/Types/Contact.ts @@ -9,6 +9,8 @@ export interface Contact { name?: string /** name of the contact, the contact has set on their own on WA */ notify?: string + /** username associated with this contact, when provided by WA */ + username?: string /** I have no idea */ verifiedName?: string // Baileys Added diff --git a/src/Types/Events.ts b/src/Types/Events.ts index 96a14096a10..5bea4e29ca9 100644 --- a/src/Types/Events.ts +++ b/src/Types/Events.ts @@ -81,6 +81,7 @@ export type BaileysEventMap = { id: string author: string authorPn?: string + authorUsername?: string participants: GroupParticipant[] action: ParticipantAction } @@ -88,6 +89,7 @@ export type BaileysEventMap = { id: string author: string authorPn?: string + authorUsername?: string participant: string participantPn?: string action: RequestJoinAction diff --git a/src/Types/GroupMetadata.ts b/src/Types/GroupMetadata.ts index 97bbe1a8587..4465e47efda 100644 --- a/src/Types/GroupMetadata.ts +++ b/src/Types/GroupMetadata.ts @@ -20,17 +20,20 @@ export interface GroupMetadata { addressingMode?: WAMessageAddressingMode owner: string | undefined ownerPn?: string | undefined + ownerUsername?: string | undefined owner_country_code?: string | undefined subject: string /** group subject owner */ subjectOwner?: string subjectOwnerPn?: string + subjectOwnerUsername?: string /** group subject modification date */ subjectTime?: number creation?: number desc?: string descOwner?: string descOwnerPn?: string + descOwnerUsername?: string descId?: string descTime?: number /** if this group is part of a community, it returns the jid of the community to which it belongs */ @@ -56,6 +59,7 @@ export interface GroupMetadata { /** the person who added you to group or changed some setting in group */ author?: string authorPn?: string + authorUsername?: string } export interface WAGroupCreateResponse { diff --git a/src/Types/Message.ts b/src/Types/Message.ts index ce8273c1435..a6717e491df 100644 --- a/src/Types/Message.ts +++ b/src/Types/Message.ts @@ -19,7 +19,9 @@ export type WAContactMessage = proto.Message.IContactMessage export type WAContactsArrayMessage = proto.Message.IContactsArrayMessage export type WAMessageKey = proto.IMessageKey & { remoteJidAlt?: string + remoteJidUsername?: string participantAlt?: string + participantUsername?: string server_id?: string addressingMode?: string isViewOnce?: boolean // TODO: remove out of the message key, place in WebMessageInfo diff --git a/src/Utils/chat-utils.ts b/src/Utils/chat-utils.ts index 99e4072541a..6c8e8a1b7bb 100644 --- a/src/Utils/chat-utils.ts +++ b/src/Utils/chat-utils.ts @@ -1083,6 +1083,7 @@ export const processSyncAction = ( action.lidContactAction.firstName || action.lidContactAction.username || undefined, + username: action.lidContactAction.username || undefined, lid: id!, phoneNumber: undefined } diff --git a/src/Utils/decode-wa-message.ts b/src/Utils/decode-wa-message.ts index 4f00b1b9b93..a88e06be3e8 100644 --- a/src/Utils/decode-wa-message.ts +++ b/src/Utils/decode-wa-message.ts @@ -242,10 +242,14 @@ export function decodeMessageNode(stanza: BinaryNode, meId: string, meLid: strin const key: WAMessageKey = { remoteJid: chatId, remoteJidAlt: !isJidGroup(chatId) ? addressingContext.senderAlt : undefined, + remoteJidUsername: !isJidGroup(chatId) + ? stanza.attrs.peer_recipient_username || stanza.attrs.recipient_username + : undefined, fromMe, id: msgId, participant, participantAlt: isJidGroup(chatId) ? addressingContext.senderAlt : undefined, + participantUsername: stanza.attrs.participant ? stanza.attrs.participant_username : undefined, addressingMode: addressingContext.addressingMode, ...(msgType === 'newsletter' && stanza.attrs.server_id ? { server_id: stanza.attrs.server_id } : {}) } diff --git a/src/Utils/history.ts b/src/Utils/history.ts index e58aa8b988d..5021ae04a97 100644 --- a/src/Utils/history.ts +++ b/src/Utils/history.ts @@ -315,6 +315,7 @@ export const processHistoryMessage = (item: proto.IHistorySync, logger?: ILogger contacts.push({ id: chatId, name: chat.displayName || chat.name || chat.username || undefined, + username: chat.username || undefined, lid: chat.lidJid || chat.accountLid || undefined, phoneNumber: chat.pnJid || undefined }) diff --git a/src/Utils/process-message.ts b/src/Utils/process-message.ts index 19b95a2b6ea..04ec7f5e305 100644 --- a/src/Utils/process-message.ts +++ b/src/Utils/process-message.ts @@ -763,12 +763,19 @@ const processMessage = async ( id: jid, author: message.key.participant!, authorPn: message.key.participantAlt!, + authorUsername: message.key.participantUsername!, participants, action }) const emitGroupUpdate = (update: Partial) => { ev.emit('groups.update', [ - { id: jid, ...update, author: message.key.participant ?? undefined, authorPn: message.key.participantAlt } + { + id: jid, + ...update, + author: message.key.participant ?? undefined, + authorPn: message.key.participantAlt, + authorUsername: message.key.participantUsername + } ]) } @@ -777,6 +784,7 @@ const processMessage = async ( id: jid, author: message.key.participant!, authorPn: message.key.participantAlt!, + authorUsername: message.key.participantUsername!, participant: participant.lid, participantPn: participant.pn, action, diff --git a/src/Utils/sync-action-utils.ts b/src/Utils/sync-action-utils.ts index 2c4ac1a3bd8..c1f0317403e 100644 --- a/src/Utils/sync-action-utils.ts +++ b/src/Utils/sync-action-utils.ts @@ -46,6 +46,7 @@ export const processContactAction = ( { id, name: action.fullName || action.firstName || action.username || undefined, + username: action.username || undefined, lid: lidJid || undefined, phoneNumber } diff --git a/src/WAUSync/Protocols/USyncContactProtocol.ts b/src/WAUSync/Protocols/USyncContactProtocol.ts index 13472e11d95..539b01ae15d 100644 --- a/src/WAUSync/Protocols/USyncContactProtocol.ts +++ b/src/WAUSync/Protocols/USyncContactProtocol.ts @@ -13,11 +13,37 @@ export class USyncContactProtocol implements USyncQueryProtocol { } getUserElement(user: USyncUser): BinaryNode { - //TODO: Implement type / username fields (not yet supported) + if (user.phone) { + return { + tag: 'contact', + attrs: {}, + content: user.phone + } + } + + if (user.username) { + return { + tag: 'contact', + attrs: { + username: user.username, + ...(user.usernameKey ? { pin: user.usernameKey } : {}), + ...(user.lid ? { lid: user.lid } : {}) + } + } + } + + if (user.type) { + return { + tag: 'contact', + attrs: { + type: user.type + } + } + } + return { tag: 'contact', - attrs: {}, - content: user.phone + attrs: {} } } diff --git a/src/WAUSync/Protocols/USyncUsernameProtocol.ts b/src/WAUSync/Protocols/USyncUsernameProtocol.ts new file mode 100644 index 00000000000..dff58c9aa55 --- /dev/null +++ b/src/WAUSync/Protocols/USyncUsernameProtocol.ts @@ -0,0 +1,28 @@ +import type { USyncQueryProtocol } from '../../Types/USync' +import { assertNodeErrorFree, type BinaryNode } from '../../WABinary' +import { USyncUser } from '../USyncUser' + +export class USyncUsernameProtocol implements USyncQueryProtocol { + name = 'username' + + getQueryElement(): BinaryNode { + return { + tag: 'username', + attrs: {} + } + } + + getUserElement(user: USyncUser): BinaryNode | null { + void user + return null + } + + parser(node: BinaryNode): string | null { + if (node.tag === 'username') { + assertNodeErrorFree(node) + return typeof node.content === 'string' ? node.content : null + } + + return null + } +} diff --git a/src/WAUSync/Protocols/index.ts b/src/WAUSync/Protocols/index.ts index c6e6442a0f9..2e5afaaa0e5 100644 --- a/src/WAUSync/Protocols/index.ts +++ b/src/WAUSync/Protocols/index.ts @@ -2,3 +2,4 @@ export * from './USyncDeviceProtocol' export * from './USyncContactProtocol' export * from './USyncStatusProtocol' export * from './USyncDisappearingModeProtocol' +export * from './USyncUsernameProtocol' diff --git a/src/WAUSync/USyncQuery.ts b/src/WAUSync/USyncQuery.ts index 39b8b9e2e28..a25951e7180 100644 --- a/src/WAUSync/USyncQuery.ts +++ b/src/WAUSync/USyncQuery.ts @@ -6,7 +6,8 @@ import { USyncContactProtocol, USyncDeviceProtocol, USyncDisappearingModeProtocol, - USyncStatusProtocol + USyncStatusProtocol, + USyncUsernameProtocol } from './Protocols' import { USyncUser } from './USyncUser' @@ -137,4 +138,9 @@ export class USyncQuery { this.protocols.push(new USyncLIDProtocol()) return this } + + withUsernameProtocol() { + this.protocols.push(new USyncUsernameProtocol()) + return this + } } diff --git a/src/WAUSync/USyncUser.ts b/src/WAUSync/USyncUser.ts index 8cfc364bd68..2ae1e3a354f 100644 --- a/src/WAUSync/USyncUser.ts +++ b/src/WAUSync/USyncUser.ts @@ -2,6 +2,8 @@ export class USyncUser { id?: string lid?: string phone?: string + username?: string + usernameKey?: string type?: string personaId?: string @@ -20,6 +22,16 @@ export class USyncUser { return this } + withUsername(username: string) { + this.username = username + return this + } + + withUsernameKey(usernameKey: string) { + this.usernameKey = usernameKey + return this + } + withType(type: string) { this.type = type return this