diff --git a/src/Socket/chats.ts b/src/Socket/chats.ts index 433e2ce..b29c7ab 100644 --- a/src/Socket/chats.ts +++ b/src/Socket/chats.ts @@ -2,7 +2,7 @@ import NodeCache from '@cacheable/node-cache' import { Boom } from '@hapi/boom' import { proto } from '../../WAProto' import { DEFAULT_CACHE_TTLS, PROCESSABLE_HISTORY_TYPES } from '../Defaults' -import { ALL_WA_PATCH_NAMES, ChatModification, ChatMutation, LTHashState, MessageUpsertType, PresenceData, SocketConfig, WABusinessHoursConfig, WABusinessProfile, WAMediaUpload, WAMessage, WAPatchCreate, WAPatchName, WAPresence, WAPrivacyCallValue, WAPrivacyGroupAddValue, WAPrivacyMessagesValue, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '../Types' +import { ALL_WA_PATCH_NAMES, BotListInfo, ChatModification, ChatMutation, LTHashState, MessageUpsertType, PresenceData, SocketConfig, WABusinessHoursConfig, WABusinessProfile, WAMediaUpload, WAMessage, WAPatchCreate, WAPatchName, WAPresence, WAPrivacyCallValue, WAPrivacyGroupAddValue, WAPrivacyMessagesValue, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '../Types' import { LabelActionBody } from '../Types/Label' import { chatModificationToAppPatch, ChatMutationMap, decodePatches, decodeSyncdSnapshot, encodeSyncdPatch, extractSyncdPatches, generateProfilePicture, getHistoryMsg, newLTHashState, processSyncAction } from '../Utils' import { makeMutex } from '../Utils/make-mutex' @@ -10,7 +10,6 @@ import processMessage from '../Utils/process-message' import { BinaryNode, getBinaryNodeChild, getBinaryNodeChildren, jidNormalizedUser, reduceBinaryNodeToDictionary, S_WHATSAPP_NET } from '../WABinary' import { USyncQuery, USyncUser } from '../WAUSync' import { makeUSyncSocket } from './usync' - const MAX_SYNC_ATTEMPTS = 2 export const makeChatsSocket = (config: SocketConfig) => { @@ -144,6 +143,39 @@ export const makeChatsSocket = (config: SocketConfig) => { }) } + const getBotListV2 = async() => { + const resp = await query({ + tag: 'iq', + attrs: { + xmlns: 'bot', + to: S_WHATSAPP_NET, + type: 'get' + }, + content: [{ + tag: 'bot', + attrs: { + v: '2' + } + }] + }) + + const botNode = getBinaryNodeChild(resp, 'bot') + + const botList: BotListInfo[] = [] + for(const section of getBinaryNodeChildren(botNode, 'section')) { + if(section.attrs.type === 'all') { + for(const bot of getBinaryNodeChildren(section, 'bot')) { + botList.push({ + jid: bot.attrs.jid, + personaId: bot.attrs['persona_id'] + }) + } + } + } + + return botList + } + const onWhatsApp = async(...jids: string[]) => { const usyncQuery = new USyncQuery() .withContactProtocol() @@ -979,6 +1011,7 @@ export const makeChatsSocket = (config: SocketConfig) => { return { ...sock, + getBotListV2, processingMutex, fetchPrivacySettings, upsertMessage, diff --git a/src/Types/Chat.ts b/src/Types/Chat.ts index 32b8af0..e9b80da 100644 --- a/src/Types/Chat.ts +++ b/src/Types/Chat.ts @@ -31,6 +31,11 @@ export interface PresenceData { lastSeen?: number } +export type BotListInfo = { + jid: string + personaId: string +} + export type ChatMutation = { syncAction: proto.ISyncActionData index: string[] diff --git a/src/WAUSync/Protocols/UsyncBotProfileProtocol.ts b/src/WAUSync/Protocols/UsyncBotProfileProtocol.ts new file mode 100644 index 0000000..cc8cd87 --- /dev/null +++ b/src/WAUSync/Protocols/UsyncBotProfileProtocol.ts @@ -0,0 +1,77 @@ +import { USyncQueryProtocol } from '../../Types/USync' +import { BinaryNode, getBinaryNodeChild, getBinaryNodeChildren, getBinaryNodeChildString } from '../../WABinary' +import { USyncUser } from '../USyncUser' + +export type BotProfileCommand = { + name: string + description: string +} + +export type BotProfileInfo = { + jid: string + name: string + attributes: string + description: string + category: string + isDefault: boolean + prompts: string[] + personaId: string + commands: BotProfileCommand[] + commandsDescription: string +} + +export class USyncBotProfileProtocol implements USyncQueryProtocol { + name = 'bot' + + getQueryElement(): BinaryNode { + return { + tag: 'bot', + attrs: { }, + content: [{ tag: 'profile', attrs: { v: '1' } }] + } + } + + getUserElement(user: USyncUser): BinaryNode { + return { + tag: 'bot', + attrs: { }, + content: [{ tag: 'profile', attrs: { 'persona_id': user.personaId } }] + } + } + + parser(node: BinaryNode): BotProfileInfo { + const botNode = getBinaryNodeChild(node, 'bot') + const profile = getBinaryNodeChild(botNode, 'profile') + + const commandsNode = getBinaryNodeChild(profile, 'commands') + const promptsNode = getBinaryNodeChild(profile, 'prompts') + + const commands: BotProfileCommand[] = [] + const prompts: string[] = [] + + for(const command of getBinaryNodeChildren(commandsNode, 'command')) { + commands.push({ + name: getBinaryNodeChildString(command, 'name')!, + description: getBinaryNodeChildString(command, 'description')! + }) + } + + for(const prompt of getBinaryNodeChildren(promptsNode, 'prompt')) { + prompts.push(`${getBinaryNodeChildString(prompt, 'emoji')!} ${getBinaryNodeChildString(prompt, 'text')!}`) + } + + + return { + isDefault: !!getBinaryNodeChild(profile, 'default'), + jid: node.attrs.jid, + name: getBinaryNodeChildString(profile, 'name')!, + attributes: getBinaryNodeChildString(profile, 'attributes')!, + description: getBinaryNodeChildString(profile, 'description')!, + category: getBinaryNodeChildString(profile, 'category')!, + personaId: profile!.attrs['persona_id'], + commandsDescription: getBinaryNodeChildString(commandsNode, 'description')!, + commands, + prompts + } + } +} diff --git a/src/WAUSync/USyncUser.ts b/src/WAUSync/USyncUser.ts index 0bd4b8a..169e10b 100644 --- a/src/WAUSync/USyncUser.ts +++ b/src/WAUSync/USyncUser.ts @@ -3,6 +3,7 @@ export class USyncUser { lid: string phone: string type: string + personaId: string withId(id: string) { this.id = id @@ -24,4 +25,8 @@ export class USyncUser { return this } -} \ No newline at end of file + withPersonaId(personaId: string) { + this.personaId = personaId + return this + } +}