diff --git a/src/Socket/communities.ts b/src/Socket/communities.ts index 6d58a8f2..f9d206b3 100644 --- a/src/Socket/communities.ts +++ b/src/Socket/communities.ts @@ -465,6 +465,7 @@ export const extractCommunityMetadata = (result: BinaryNode) => { memberAddMode, participants: getBinaryNodeChildren(community, 'participant').map(({ attrs }) => { return { + // TODO: IMPLEMENT THE PN/LID FIELDS HERE!! id: attrs.jid!, admin: (attrs.type || null) as GroupParticipant['admin'] } diff --git a/src/Socket/groups.ts b/src/Socket/groups.ts index 4ff1a99b..6a9bf5cb 100644 --- a/src/Socket/groups.ts +++ b/src/Socket/groups.ts @@ -344,6 +344,7 @@ export const extractGroupMetadata = (result: BinaryNode) => { joinApprovalMode: !!getBinaryNodeChild(group, 'membership_approval_mode'), memberAddMode, participants: getBinaryNodeChildren(group, 'participant').map(({ attrs }) => { + // TODO: Store LID MAPPINGS return { id: attrs.jid!, phoneNumber: isLidUser(attrs.jid) && isPnUser(attrs.phone_number) ? attrs.phone_number : undefined, diff --git a/src/Socket/messages-recv.ts b/src/Socket/messages-recv.ts index fd89e973..91158250 100644 --- a/src/Socket/messages-recv.ts +++ b/src/Socket/messages-recv.ts @@ -5,6 +5,8 @@ import Long from 'long' import { proto } from '../../WAProto/index.js' import { DEFAULT_CACHE_TTLS, KEY_BUNDLE_TYPE, MIN_PREKEY_COUNT } from '../Defaults' import type { + GroupParticipant, + LIDMapping, MessageReceiptType, MessageRelayOptions, MessageUserReceipt, @@ -28,6 +30,7 @@ import { derivePairingCodeKey, encodeBigEndian, encodeSignedDeviceIdentity, + extractAddressingContext, getCallStatusFromNode, getHistoryMsg, getNextPreKeys, @@ -51,6 +54,7 @@ import { isJidGroup, isJidStatusBroadcast, isLidUser, + isPnUser, jidDecode, jidNormalizedUser, S_WHATSAPP_NET @@ -550,16 +554,22 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { } } - const handleGroupNotification = (participant: string, child: BinaryNode, msg: Partial) => { - const participantJid = getBinaryNodeChild(child, 'participant')?.attrs?.jid || participant - // TODO: Add participant LID + const handleGroupNotification = (fullNode: BinaryNode, child: BinaryNode, msg: Partial) => { + // TODO: Support PN/LID (Here is only LID now) + + const actingParticipantLid = fullNode.attrs.participant + const actingParticipantPn = fullNode.attrs.participant_pn + + const affectedParticipantLid = getBinaryNodeChild(child, 'participant')?.attrs?.jid || actingParticipantLid! + const affectedParticipantPn = getBinaryNodeChild(child, 'participant')?.attrs?.phone_number || actingParticipantPn! + switch (child?.tag) { case 'create': const metadata = extractGroupMetadata(child) msg.messageStubType = WAMessageStubType.GROUP_CREATE msg.messageStubParameters = [metadata.subject] - msg.key = { participant: metadata.owner } + msg.key = { participant: metadata.owner, participantAlt: metadata.ownerPn } ev.emit('chats.upsert', [ { @@ -571,7 +581,8 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { ev.emit('groups.upsert', [ { ...metadata, - author: participant + author: actingParticipantLid, + authorPn: actingParticipantPn } ]) break @@ -597,12 +608,22 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { const stubType = `GROUP_PARTICIPANT_${child.tag.toUpperCase()}` msg.messageStubType = WAMessageStubType[stubType as keyof typeof WAMessageStubType] - const participants = getBinaryNodeChildren(child, 'participant').map(p => p.attrs.jid!) + const participants = getBinaryNodeChildren(child, 'participant').map(({ attrs }) => { + // TODO: Store LID MAPPINGS + return { + 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, + admin: (attrs.type || null) as GroupParticipant['admin'] + } + }) + if ( participants.length === 1 && // if recv. "remove" message and sender removed themselves // mark as left - areJidsSameUser(participants[0], participant) && + (areJidsSameUser(participants[0]!.id, actingParticipantLid) || + areJidsSameUser(participants[0]!.id, actingParticipantPn)) && child.tag === 'remove' ) { msg.messageStubType = WAMessageStubType.GROUP_PARTICIPANT_LEAVE @@ -651,12 +672,20 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { break case 'created_membership_requests': msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD - msg.messageStubParameters = [participantJid, 'created', child.attrs.request_method!] + msg.messageStubParameters = [ + { lid: affectedParticipantLid, pn: affectedParticipantPn } as LIDMapping, + 'created', + child.attrs.request_method! + ] break case 'revoked_membership_requests': - const isDenied = areJidsSameUser(participantJid, participant) + const isDenied = areJidsSameUser(affectedParticipantLid, actingParticipantLid) + // TODO: LIDMAPPING SUPPORT msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD - msg.messageStubParameters = [participantJid, isDenied ? 'revoked' : 'rejected'] + msg.messageStubParameters = [ + { lid: affectedParticipantLid, pn: affectedParticipantPn } as LIDMapping, + isDenied ? 'revoked' : 'rejected' + ] break } } @@ -690,7 +719,8 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { await handleMexNewsletterNotification(node) break case 'w:gp2': - handleGroupNotification(node.attrs.participant!, child!, result) + // TODO: HANDLE PARTICIPANT_PN + handleGroupNotification(node, child!, result) break case 'mediaretry': const event = decodeMediaRetryNode(node) @@ -1083,10 +1113,13 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { const msg = await processNotification(node) if (msg) { const fromMe = areJidsSameUser(node.attrs.participant || remoteJid, authState.creds.me!.id) + const { senderAlt: participantAlt, addressingMode } = extractAddressingContext(node) msg.key = { remoteJid, fromMe, participant: node.attrs.participant, + participantAlt, + addressingMode, id: node.attrs.id, ...(msg.key || {}) } diff --git a/src/Types/Events.ts b/src/Types/Events.ts index b66eb5b3..3f23cad8 100644 --- a/src/Types/Events.ts +++ b/src/Types/Events.ts @@ -4,7 +4,13 @@ import type { AuthenticationCreds } from './Auth' import type { WACallEvent } from './Call' import type { Chat, ChatUpdate, PresenceData } from './Chat' import type { Contact } from './Contact' -import type { GroupMetadata, ParticipantAction, RequestJoinAction, RequestJoinMethod } from './GroupMetadata' +import type { + GroupMetadata, + GroupParticipant, + ParticipantAction, + RequestJoinAction, + RequestJoinMethod +} from './GroupMetadata' import type { Label } from './Label' import type { LabelAssociation } from './LabelAssociation' import type { MessageUpsertType, MessageUserReceiptUpdate, WAMessage, WAMessageKey, WAMessageUpdate } from './Message' @@ -56,11 +62,19 @@ export type BaileysEventMap = { 'groups.upsert': GroupMetadata[] 'groups.update': Partial[] /** apply an action to participants in a group */ - 'group-participants.update': { id: string; author: string; participants: string[]; action: ParticipantAction } + 'group-participants.update': { + id: string + author: string + authorPn?: string + participants: GroupParticipant[] + action: ParticipantAction + } 'group.join-request': { id: string author: string + authorPn?: string participant: string + participantPn?: string action: RequestJoinAction method: RequestJoinMethod } diff --git a/src/Types/GroupMetadata.ts b/src/Types/GroupMetadata.ts index ab7a354f..97bbe1a8 100644 --- a/src/Types/GroupMetadata.ts +++ b/src/Types/GroupMetadata.ts @@ -55,6 +55,7 @@ export interface GroupMetadata { inviteCode?: string /** the person who added you to group or changed some setting in group */ author?: string + authorPn?: string } export interface WAGroupCreateResponse { diff --git a/src/Types/Message.ts b/src/Types/Message.ts index 5485fe68..4275bd6c 100644 --- a/src/Types/Message.ts +++ b/src/Types/Message.ts @@ -8,7 +8,7 @@ import type { CacheStore } from './Socket' // export the WAMessage Prototypes export { proto as WAProto } -export type WAMessage = proto.IWebMessageInfo & { key: WAMessageKey } +export type WAMessage = proto.IWebMessageInfo & { key: WAMessageKey; messageStubParameters?: any } export type WAMessageContent = proto.IMessage export type WAContactMessage = proto.Message.IContactMessage export type WAContactsArrayMessage = proto.Message.IContactsArrayMessage diff --git a/src/Utils/event-buffer.ts b/src/Utils/event-buffer.ts index 20ca7da8..ba64c277 100644 --- a/src/Utils/event-buffer.ts +++ b/src/Utils/event-buffer.ts @@ -545,7 +545,7 @@ function append( const chatId = message.key.remoteJid! const chat = data.chatUpdates[chatId] || data.chatUpserts[chatId] if ( - isRealMessage(message, '') && + isRealMessage(message) && shouldIncrementChatUnread(message) && typeof chat?.unreadCount === 'number' && chat.unreadCount > 0 diff --git a/src/Utils/process-message.ts b/src/Utils/process-message.ts index a3f16010..af87a27c 100644 --- a/src/Utils/process-message.ts +++ b/src/Utils/process-message.ts @@ -5,6 +5,8 @@ import type { CacheStore, Chat, GroupMetadata, + GroupParticipant, + LIDMapping, ParticipantAction, RequestJoinAction, RequestJoinMethod, @@ -101,14 +103,14 @@ export const cleanMessage = (message: WAMessage, meId: string) => { } } -export const isRealMessage = (message: WAMessage, meId: string) => { +// TODO: target:audit AUDIT THIS FUNCTION AGAIN +export const isRealMessage = (message: WAMessage) => { const normalizedContent = normalizeMessageContent(message.message) const hasSomeContent = !!getContentType(normalizedContent) return ( (!!normalizedContent || REAL_MSG_STUB_TYPES.has(message.messageStubType!) || - (REAL_MSG_REQ_ME_STUB_TYPES.has(message.messageStubType!) && - message.messageStubParameters?.some(p => areJidsSameUser(meId, p)))) && + REAL_MSG_REQ_ME_STUB_TYPES.has(message.messageStubType!)) && hasSomeContent && !normalizedContent?.protocolMessage && !normalizedContent?.reactionMessage && @@ -188,7 +190,7 @@ const processMessage = async ( const { accountSettings } = creds const chat: Partial = { id: jidNormalizedUser(getChatId(message.key)) } - const isRealMsg = isRealMessage(message, meId) + const isRealMsg = isRealMessage(message) if (isRealMsg) { chat.messages = [{ message }] @@ -362,18 +364,34 @@ const processMessage = async ( } else if (message.messageStubType) { const jid = message.key?.remoteJid! //let actor = whatsappID (message.participant) - let participants: string[] + let participants: GroupParticipant[] const emitParticipantsUpdate = (action: ParticipantAction) => - ev.emit('group-participants.update', { id: jid, author: message.participant!, participants, action }) + ev.emit('group-participants.update', { + id: jid, + author: message.key.participant!, + authorPn: message.key.participantAlt!, + participants, + action + }) const emitGroupUpdate = (update: Partial) => { - ev.emit('groups.update', [{ id: jid, ...update, author: message.participant ?? undefined }]) + ev.emit('groups.update', [ + { id: jid, ...update, author: message.key.participant ?? undefined, authorPn: message.key.participantAlt } + ]) } - const emitGroupRequestJoin = (participant: string, action: RequestJoinAction, method: RequestJoinMethod) => { - ev.emit('group.join-request', { id: jid, author: message.participant!, participant, action, method: method! }) + const emitGroupRequestJoin = (participant: LIDMapping, action: RequestJoinAction, method: RequestJoinMethod) => { + ev.emit('group.join-request', { + id: jid, + author: message.key.participant!, + authorPn: message.key.participantAlt!, + participant: participant.lid, + participantPn: participant.pn, + action, + method: method! + }) } - const participantsIncludesMe = () => participants.find(jid => areJidsSameUser(meId, jid)) + const participantsIncludesMe = () => participants.find(jid => areJidsSameUser(meId, jid.phoneNumber)) // ADD SUPPORT FOR LID switch (message.messageStubType) { case WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER: @@ -438,8 +456,8 @@ const processMessage = async ( const approvalMode = message.messageStubParameters?.[0] emitGroupUpdate({ joinApprovalMode: approvalMode === 'on' }) break - case WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD: - const participant = message.messageStubParameters?.[0] as string + case WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD: // TODO: Add other events + const participant = message.messageStubParameters?.[0] as LIDMapping const action = message.messageStubParameters?.[1] as RequestJoinAction const method = message.messageStubParameters?.[2] as RequestJoinMethod emitGroupRequestJoin(participant, action, method)