UNPKG

wabot

Version:

Whatsapp Bot Module for automate response and interact whit users

1,444 lines (1,269 loc) 98.9 kB
/** * WAPI.js is taken from https://github.com/mukulhase/WebWhatsapp-Wrapper/blob/master/webwhatsapi/js/wapi.js * A Python library which is worth checking out. * The new WAPI is made from https://github.com/Theblood/Wapi_NEW/blob/master/wapi.js */ /** * This script contains WAPI functions that need to be run in the context of the webpage */ /** * Auto discovery the webpack object references of instances that contains all functions used by the WAPI * functions and creates the Store object. */ if (!window.Store) { function getStore (){ window.mR = moduleRaid(); window.Store = Object.assign({}, window.mR.findModule(m => m.default && m.default.Chat)[0].default); window.Store.addAndSendMsgToChat = window.mR.findModule('addAndSendMsgToChat')[0].addAndSendMsgToChat; window.Store.AppState = window.mR.findModule('Socket')[0].Socket; window.Store.Conn = window.mR.findModule('Conn')[0].Conn; window.Store.BlockContact = window.mR.findModule('blockContact')[0]; window.Store.Call = window.mR.findModule('CallCollection')[0].CallCollection; window.Store.Cmd = window.mR.findModule('Cmd')[0].Cmd; window.Store.CreateGroup = window.mR.findModule('createGroup')[0].createGroup; window.Store.CryptoLib = window.mR.findModule('decryptE2EMedia')[0]; window.Store.DownloadManager = window.mR.findModule('downloadManager')[0].downloadManager; window.Store.Features = window.mR.findModule('FEATURE_CHANGE_EVENT').length > 0 ? window.mR.findModule('FEATURE_CHANGE_EVENT')[0].LegacyPhoneFeatures : null; window.Store.GroupMetadata = window.mR.findModule('GroupMetadata')[0].default.GroupMetadata; window.Store.Invite = window.mR.findModule('resetGroupInviteCode')[0]; window.Store.InviteInfo = window.mR.findModule('queryGroupInvite')[0]; window.Store.Label = window.mR.findModule('LabelCollection')[0].LabelCollection; window.Store.MediaPrep = window.mR.findModule('MediaPrep')[0]; window.Store.MediaObject = window.mR.findModule('getOrCreateMediaObject')[0]; window.Store.NumberInfo = window.mR.findModule('formattedPhoneNumber')[0]; window.Store.MediaTypes = window.mR.findModule('msgToMediaType')[0]; window.Store.MediaUpload = window.mR.findModule('uploadMedia')[0]; window.Store.MDBackend = window.mR.findModule('isMDBackend').length > 0 ? window.mR.findModule('isMDBackend')[0].isMDBackend() : true; window.Store.MsgKey = window.mR.findModule((module) => module.default && module.default.fromString)[0].default; window.Store.MessageInfo = window.mR.findModule('sendQueryMsgInfo')[0]; window.Store.OpaqueData = window.mR.findModule(module => module.default && module.default.createFromData)[0].default; window.Store.QueryExists = window.mR.findModule('queryExists')[0].queryExists; window.Store.QueryExist = window.mR.findModule('queryExists')[0].queryExists; window.Store.QueryLinkPreview = window.mR.findModule('queryLinkPreview').length > 0 ? window.mR.findModule('queryLinkPreview')[0].queryLinkPreview : null; window.Store.QueryProduct = window.mR.findModule('queryProduct')[0]; window.Store.QueryOrder = window.mR.findModule('queryOrder')[0]; window.Store.SendClear = window.mR.findModule('sendClear')[0]; window.Store.SendDelete = window.mR.findModule('sendDelete')[0]; window.Store.SendMessage = window.mR.findModule('addAndSendMsgToChat')[0]; window.Store.SendSeen = window.mR.findModule('sendSeen')[0]; window.Store.User = window.mR.findModule('getMaybeMeUser')[0]; window.Store.UploadUtils = window.mR.findModule((module) => (module.default && module.default.encryptAndUpload) ? module.default : null)[0].default; window.Store.UserConstructor = window.mR.findModule((module) => (module.default && module.default.prototype && module.default.prototype.isServer && module.default.prototype.isUser) ? module.default : null)[0].default; window.Store.Validators = window.mR.findModule('findLinks')[0]; window.Store.VCard = window.mR.findModule('vcardFromContactModel')[0]; window.Store.Wap = window.mR.findModule('queryLinkPreview').length > 0 ? window.mR.findModule('queryLinkPreview')[0].default : null; window.Store.WidFactory = window.mR.findModule('createWid')[0]; window.Store.ProfilePic = window.mR.findModule('profilePicResync')[0]; window.Store.PresenceUtils = window.mR.findModule('sendPresenceAvailable')[0]; window.Store.ChatStates = window.mR.findModule('sendChatStateComposing')[0]; window.Store.ChatState = window.mR.findModule('sendChatStateComposing')[0]; window.Store.GroupParticipants = window.mR.findModule('promoteParticipants')[1]; window.Store.JoinInviteV4 = window.mR.findModule('sendJoinGroupViaInviteV4')[0]; window.Store.findCommonGroups = window.mR.findModule('findCommonGroups')[0].findCommonGroups; window.Store.StatusUtils = window.mR.findModule('setMyStatus')[0]; window.Store.ConversationMsgs = window.mR.findModule('loadEarlierMsgs')[0]; window.Store.sendReactionToMsg = window.mR.findModule('sendReactionToMsg')[0].sendReactionToMsg; window.Store.createOrUpdateReactionsModule = window.mR.findModule('createOrUpdateReactions')[0]; window.Store.EphemeralFields = window.mR.findModule('getEphemeralFields')[0]; window.Store.ReplyUtils = window.mR.findModule('canReplyMsg').length > 0 && window.mR.findModule('canReplyMsg')[0]; window.Store.MsgActionChecks = window.mR.findModule('canSenderRevokeMsg')[0]; window.Store.QuotedMsg = window.mR.findModule('getQuotedMsgObj')[0]; window.Store.Socket = window.mR.findModule('deprecatedSendIq')[0]; window.Store.SocketWap = window.mR.findModule('wap')[0]; window.Store.SendTextMsgToChat = window.mR.findModule('sendTextMsgToChat')[0].sendTextMsgToChat; window.Store.sendReactionToMsg = window.mR.findModule('sendReactionToMsg')[0].sendReactionToMsg; window.Store.Participants = window.mR.findModule('addParticipants')[0]; window.Store.StickerTools = { ...window.mR.findModule('toWebpSticker')[0], ...window.mR.findModule('addWebpMetadata')[0] }; window.Store.GroupUtils = { ...window.mR.findModule('sendCreateGroup')[0], ...window.mR.findModule('sendSetGroupSubject')[0], ...window.mR.findModule('markExited')[0] }; Store.Sticker = window.mR.findModule('StickerCollection')[0].StickerCollection; //Store.Sticker = Object.values(window.mR.modules).find(module => module !== undefined && module.default && module.default.Sticker).default.Sticker; Store.MediaCollection = Object.values(window.mR.modules).find(module => (module !== undefined && module.default && module.default.prototype && (module.default.prototype.processFiles !== undefined||module.default.prototype.processAttachments !== undefined))).default; if(window.Store.MediaCollection) window.Store.MediaCollection.prototype.processFiles = window.Store.MediaCollection.prototype.processFiles || window.Store.MediaCollection.prototype.processAttachments; //Store.WapQuery = Object.values(window.mR.modules).find(module => module && module.default && module.default.queryExist).default; if (!window.Store.Chat._find) { window.Store.Chat._find = e => { const target = window.Store.Chat.get(e); return target ? Promise.resolve(target) : Promise.resolve({ id: e }); }; } window.Store.Chat.modelClass.prototype.sendMessage = function (e) { window.Store.SendTextMsgToChat(this, ...arguments); } window.Store.Msg.models = Store.Msg._models; }; getStore(); } window.WAPI = {}; window._WAPI = {}; window.WAPI._serializeRawObj = (obj) => { if (obj && obj.toJSON) { return obj.toJSON(); } return {} }; /** * Serializes a chat object * * @param rawChat Chat object * @returns {{}} */ window.WAPI._serializeChatObj = (obj) => { if (obj == undefined) { return null; } return Object.assign(window.WAPI._serializeRawObj(obj), { kind: obj.kind, isGroup: obj.isGroup, formattedTitle: obj.formattedTitle, contact: obj['contact'] ? window.WAPI._serializeContactObj(obj['contact']) : null, groupMetadata: obj["groupMetadata"] ? window.WAPI._serializeRawObj(obj["groupMetadata"]) : null, presence: obj["presence"] ? window.WAPI._serializeRawObj(obj["presence"]) : null, msgs: null }); }; window.WAPI._serializeContactObj = (obj) => { if (obj == undefined) { return null; } return Object.assign(window.WAPI._serializeRawObj(obj), { formattedName: obj.formattedName, isHighLevelVerified: obj.isHighLevelVerified, isMe: obj.isMe, isMyContact: obj.isMyContact, isPSA: obj.isPSA, isUser: obj.isUser, isVerified: obj.isVerified, isWAContact: obj.isWAContact, profilePicThumbObj: obj.profilePicThumb ? WAPI._serializeProfilePicThumb(obj.profilePicThumb) : {}, statusMute: obj.statusMute, msgs: null }); }; window.WAPI._serializeMessageObj = (obj) => { if (obj == undefined) { return null; } const _chat = obj['chat'] ? WAPI._serializeChatObj(obj['chat']) : {}; if(obj.quotedMsg) obj.quotedMsgObj(); return Object.assign(window.WAPI._serializeRawObj(obj), { id: obj.id._serialized, from: obj.from._serialized, quotedParticipant: obj.quotedParticipant? obj.quotedParticipant._serialized ? obj.quotedParticipant._serialized : undefined : undefined, author: obj.author? obj.author._serialized ? obj.author._serialized : undefined : undefined, chatId: obj.chatId? obj.chatId._serialized ? obj.chatId._serialized : undefined : undefined, to: obj.to? obj.to._serialized ? obj.to._serialized : undefined : undefined, fromMe: obj.id.fromMe, sender: obj["senderObj"] ? WAPI._serializeContactObj(obj["senderObj"]) : null, timestamp: obj["t"], content: obj["body"], isGroupMsg: obj.isGroupMsg, isLink: obj.isLink, isMMS: obj.isMMS, isMedia: obj.isMedia, isNotification: obj.isNotification, isPSA: obj.isPSA, type: obj.type, chat: _chat, isOnline: _chat.isOnline, lastSeen: _chat.lastSeen, chatId: obj.id.remote, quotedMsgObj: WAPI._serializeMessageObj(obj['_quotedMsgObj']), mediaData: window.WAPI._serializeRawObj(obj['mediaData']), reply: body => window.WAPI.reply(_chat.id._serialized, body, obj) }); }; window.WAPI._serializeNumberStatusObj = (obj) => { if (obj == undefined) { return null; } return Object.assign({}, { id: obj.jid, status: obj.status, isBusiness: (obj.biz === true), canReceiveMessage: (obj.status === 200) }); }; window.WAPI._serializeProfilePicThumb = (obj) => { if (obj == undefined) { return null; } return Object.assign({}, { eurl: obj.eurl, id: obj.id, img: obj.img, imgFull: obj.imgFull, raw: obj.raw, tag: obj.tag }); } window.WAPI.createGroup = async function (name, contactsId) { if (!Array.isArray(contactsId)) { contactsId = [contactsId]; } return await window.Store.CreateGroup(name, contactsId); }; /** * Sends the command for your device to leave a group. * @param groupId stirng, the is for the group. * returns Promise<void> */ window.WAPI.leaveGroup = function (groupId) { groupId = typeof groupId == "string" ? groupId : groupId._serialized; var group = WAPI.getChat(groupId); return Store.GroupActions.sendExitGroup(group) }; window.WAPI.getAllContacts = function () { return window.Store.Contact.map((contact) => WAPI._serializeContactObj(contact)); }; /** * Fetches all contact objects from store, filters them * * @returns {Array|*} List of contacts */ window.WAPI.getMyContacts = function () { return window.Store.Contact.filter((contact) => contact.isMyContact === true).map((contact) => WAPI._serializeContactObj(contact)); }; /** * Fetches contact object from store by ID * * @param id ID of contact * @returns {T|*} Contact object */ window.WAPI.getContact = function (id) { const found = window.Store.Contact.get(id); return window.WAPI._serializeContactObj(found); }; window.WAPI.syncContacts = function() { Store.Contact.sync() return true; } /** * Fetches all chat objects from store * * @returns {Array|*} List of chats */ window.WAPI.getAllChats = function () { return window.Store.Chat.map((chat) => WAPI._serializeChatObj(chat)); }; window.WAPI.haveNewMsg = function (chat) { return chat.unreadCount > 0; }; window.WAPI.getAllChatsWithNewMsg = function () { return window.Store.Chat.filter(window.WAPI.haveNewMsg).map((chat) => WAPI._serializeChatObj(chat)); }; /** * Fetches all chat IDs from store * * @returns {Array|*} List of chat id's */ window.WAPI.getAllChatIds = function () { return window.Store.Chat.map((chat) => chat.id._serialized || chat.id); }; window.WAPI.getAllNewMessages = async function () { return JSON.stringify(WAPI.getAllChatsWithNewMsg().map(c => WAPI.getChat(c.id._serialized)).map(c => c.msgs._models.filter(x => x.isNewMsg)) || []) } // nnoo longer determined by x.ack==-1 window.WAPI.getAllUnreadMessages = async function () { return Store.Chat.models.filter(chat=>chat.unreadCount&&chat.unreadCount>0).map(unreadChat=>unreadChat.msgs.models.slice(-1*unreadChat.unreadCount)).flat().map(WAPI._serializeMessageObj) } window.WAPI.getIndicatedNewMessages = async function () { return JSON.stringify(Store.Chat.models.filter(chat=>chat.unreadCount).map(chat=>{return {id:chat.id,indicatedNewMessages: chat.msgs.models.slice(Math.max(chat.msgs.length - chat.unreadCount, 0)).filter(msg=>!msg.id.fromMe)}})) } window.WAPI.getSingleProperty = function (namespace,id,property){ if(Store[namespace] && Store[namespace].get(id) && Object.keys(Store[namespace].get(id)).find(x=>x.includes(property))) return Store[namespace].get(id)[property]; return 404 } window.WAPI.getAllChatsWithMessages = async function (onlyNew) { let x = []; if (onlyNew) { x.push(WAPI.getAllChatsWithNewMsg().map(c => WAPI.getChat(c.id._serialized))); } else { x.push(WAPI.getAllChatIds().map((c) => WAPI.getChat(c))); } const result = (await Promise.all(x)).flatMap(x => x); return JSON.stringify(result); } /** * Fetches all groups objects from store * * @returns {Array|*} List of chats */ window.WAPI.getAllGroups = function () { return window.Store.Chat.filter((chat) => chat.isGroup); }; /** * Sets the chat state * * @param {0|1|2} chatState The state you want to set for the chat. Can be TYPING (1), RECRDING (2) or PAUSED (3); * returns {boolean} */ window.WAPI.sendChatstate = async function (state, chatId) { switch(state) { case 0: await window.Store.ChatStates.sendChatStateComposing(chatId); break; case 1: await window.Store.ChatStates.sendChatStateRecording(chatId); break; case 2: await window.Store.ChatStates.sendChatStatePaused(chatId); break; default: return false } return true; }; /** * Fetches chat object from store by ID * * @param id ID of chat * @returns {T|*} Chat object */ window.WAPI.getChat = function (id) { if (!id) return false; id = typeof id == "string" ? id : id._serialized; const found = window.Store.Chat.get(id); if (found) found.sendMessage = (found.sendMessage) ? found.sendMessage : function () { return window.Store.sendMessage.apply(this, arguments); }; return found; } /** * Get your status * @param {string} to '000000000000@c.us' * returns: {string,string} and string -"Hi, I am using WA" */ window.WAPI.getStatus = async (id) => { return await Store.MyStatus.getStatus(id) } window.WAPI.getChatByName = function (name) { return window.Store.Chat.find((chat) => chat.name === name); }; window.WAPI.sendImageFromDatabasePicBot = function (picId, chatId, caption) { var chatDatabase = window.WAPI.getChatByName('DATABASEPICBOT'); var msgWithImg = chatDatabase.msgs.find((msg) => msg.caption == picId); if (msgWithImg === undefined) { return false; } var chatSend = WAPI.getChat(chatId); if (chatSend === undefined) { return false; } const oldCaption = msgWithImg.caption; msgWithImg.id.id = window.WAPI.getNewId(); msgWithImg.id.remote = chatId; msgWithImg.t = Math.ceil(new Date().getTime() / 1000); msgWithImg.to = chatId; if (caption !== undefined && caption !== '') { msgWithImg.caption = caption; } else { msgWithImg.caption = ''; } msgWithImg.collection.send(msgWithImg).then(function (e) { msgWithImg.caption = oldCaption; }); return true; }; window.WAPI.getGeneratedUserAgent = function (useragent) { if (!useragent.includes('WhatsApp')) return 'WhatsApp/0.4.315 ' + useragent; return useragent.replace(useragent.match(/WhatsApp\/([.\d])*/g)[0].match(/[.\d]*/g).find(x => x), window.Debug.VERSION) } window.WAPI.getWAVersion = function () { return window.Debug.VERSION; } /** * Automatically sends a link with the auto generated link preview. You can also add a custom message to be added. * @param chatId * @param url string A link, for example for youtube. e.g https://www.youtube.com/watch?v=61O-Galzc5M * @param text string Custom text as body of the message, this needs to include the link or it will be appended after the link. */ window.WAPI.sendLinkWithAutoPreview = async function (chatId, url, text, quotedMsg) { var chatSend = WAPI.getChat(chatId); if (chatSend === undefined) { return false; } const link = window.Store.Validators.findLink(url); const linkPreview = await Store.QueryLinkPreview(link.url); return (await chatSend.sendMessage(text.includes(url) ? text : `${url}\n${text}`, {linkPreview: linkPreview, quotedMsg: quotedMsg}))=='success' } window.WAPI._sendMessageWithThumb = function (thumb, url, title, description, text, chatId) { var chatSend = WAPI.getChat(chatId); if (chatSend === undefined) { return false; } var linkPreview = { canonicalUrl: url, description: description, matchedText: url, title: title, thumbnail: thumb // Thumbnail max size allowed: 200x200 }; chatSend.sendMessage(text.includes(url) ? text : `${url}\n${text}`, { linkPreview: linkPreview, mentionedJidList: [], quotedMsg: null, quotedMsgAdminGroupJid: null }); return true; }; window.WAPI.sendMessageWithThumb = function (thumb, url, title, description, chatId, quotedMsg, done) { var chatSend = WAPI.getChat(chatId); if (chatSend === undefined) { if (done !== undefined) done(false); return false; } var linkPreview = { canonicalUrl: url, description: description, matchedText: url, title: title, thumbnail: thumb }; if (quotedMsg && quotedMsg !== '') { if (typeof quotedMsg !== "object") quotedMsg = Store.Msg.get(quotedMsg); } chatSend.sendMessage(url, { linkPreview: linkPreview, mentionedJidList: [], quotedMsg: quotedMsg, quotedMsgAdminGroupJid: null }); if (done !== undefined) done(true); return true; }; window.WAPI.revokeGroupInviteLink = async function (chatId) { var chat = Store.Chat.get(chatId); if(!chat.isGroup) return false; await Store.GroupInvite.revokeGroupInvite(chat); return true; } window.WAPI.getGroupInviteLink = async function (chatId) { var chat = Store.Chat.get(chatId); if(!chat.isGroup) return false; await Store.GroupInvite.queryGroupInviteCode(chat); return `https://chat.whatsapp.com/${chat.inviteCode}` } window.WAPI.getNewId = function () { var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for (var i = 0; i < 20; i++) text += possible.charAt(Math.floor(Math.random() * possible.length)); return text; }; window.WAPI.getChatById = function (id) { let found = WAPI.getChat(id); if (found) { found = WAPI._serializeChatObj(found); } else { found = false; } return found; }; /** * I return all unread messages from an asked chat and mark them as read. * * :param id: chat id * :type id: string * * :param includeMe: indicates if user messages have to be included * :type includeMe: boolean * * :param includeNotifications: indicates if notifications have to be included * :type includeNotifications: boolean * * :returns: list of unread messages from asked chat * :rtype: object */ window.WAPI.getUnreadMessagesInChat = function (id, includeMe, includeNotifications) { // get chat and its messages let chat = WAPI.getChat(id); let messages = chat.msgs._models; // initialize result list let output = []; // look for unread messages, newest is at the end of array for (let i = messages.length - 1; i >= 0; i--) { // system message: skip it if (i === "remove") { continue; } // get message let messageObj = messages[i]; // found a read message: stop looking for others if (typeof (messageObj.isNewMsg) !== "boolean" || messageObj.isNewMsg === false) { continue; } else { messageObj.isNewMsg = false; // process it let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications); // save processed message on result list if (message) output.push(message); } } // return result list return output; }; /** * Load more messages in chat object from server. Use this in a while loop * * @param id ID of chat * @returns None */ window.WAPI.loadEarlierMessages = async function (id) { const chat = WAPI.getChat(id); if(chat){ const someEarlierMessages = await chat.loadEarlierMsgs(); if(someEarlierMessages) return someEarlierMessages.map(WAPI._serializeMessageObj); } return false; }; /** * Load more messages in chat object from store by ID * * @param id ID of chat * @returns None */ window.WAPI.loadAllEarlierMessages = async function (id) { const found = WAPI.getChat(id); while (!found.msgs.msgLoadState.noEarlierMsgs) { console.log('loading more messages') await found.loadEarlierMsgs(); } return true }; window.WAPI.asyncLoadAllEarlierMessages = async function (id) { return await window.WAPI.loadAllEarlierMessages(id); }; window.WAPI.areAllMessagesLoaded = function (id) { const found = WAPI.getChat(id); if (!found.msgs.msgLoadState.noEarlierMsgs) { return false } return true }; /** * Load more messages in chat object from store by ID till a particular date * * @param id ID of chat * @param lastMessage UTC timestamp of last message to be loaded * @returns None */ window.WAPI.loadEarlierMessagesTillDate = async function (id, lastMessage) { const found = WAPI.getChat(id); x = async function () { if (found.msgs.models[0].t > lastMessage && !found.msgs.msgLoadState.noEarlierMsgs) { return await found.loadEarlierMsgs().then(x); } else { return true } }; return await x(); }; /** * Fetches all group metadata objects from store * * @returns {Array|*} List of group metadata */ window.WAPI.getAllGroupMetadata = function () { return window.Store.GroupMetadata.map((groupData) => groupData.all); }; /** * Fetches group metadata object from store by ID * * @param id ID of group * @returns {T|*} Group metadata object */ window.WAPI.getGroupMetadata = async function (id) { return window.Store.GroupMetadata.find(id); }; /** * Fetches group participants * * @param id ID of group * @returns {Promise.<*>} Yields group metadata * @private */ window.WAPI._getGroupParticipants = async function (id) { return (await WAPI.getGroupMetadata(id)).participants; }; /** * Fetches IDs of group participants * * @param id ID of group * @returns {Promise.<Array|*>} Yields list of IDs */ window.WAPI.getGroupParticipantIDs = async function (id) { return (await WAPI._getGroupParticipants(id)) .map((participant) => participant.id); }; window.WAPI.getGroupAdmins = async function (id) { return (await WAPI._getGroupParticipants(id)) .filter((participant) => participant.isAdmin) .map((admin) => admin.id); }; /** * Returns an object with all of your host device details */ window.WAPI.getMe = function(){ return {...WAPI.quickClean({ ...Store.Contact.get(Store.Me.wid).attributes, ...Store.Me.attributes }), me:Store.Me.me}; } window.WAPI.isLoggedIn = function () { // Contact always exists when logged in const isLogged = window.Store.Contact && window.Store.Contact.checksum !== undefined; return isLogged; }; window.WAPI.isConnected = function () { // Phone Disconnected icon appears when phone is disconnected from the tnternet const isConnected = document.querySelector('*[data-icon="alert-phone"]') !== null ? false : true; return isConnected; }; //I dont think this will work for group chats. window.WAPI.isChatOnline = async function (id) { return Store.Chat.get(id)?await Store.Chat.get(id).presence.subscribe().then(_=>Store.Chat.get(id).presence.attributes.isOnline):false; } window.WAPI.processMessageObj = function (messageObj, includeMe, includeNotifications) { if (messageObj.isNotification) { if (includeNotifications) return WAPI._serializeMessageObj(messageObj); else return; // System message // (i.e. "Messages you send to this chat and calls are now secured with end-to-end encryption...") } else if (messageObj.id.fromMe === false || includeMe) { return WAPI._serializeMessageObj(messageObj); } return; }; window.WAPI.getAllMessagesInChat = function (id, includeMe, includeNotifications) { const chat = WAPI.getChat(id); let output = []; const messages = chat.msgs._models; for (const i in messages) { if (i === "remove") { continue; } const messageObj = messages[i]; let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications) if (message) output.push(message); } return WAPI.quickClean(output); }; window.WAPI.loadAndGetAllMessagesInChat = function (id, includeMe, includeNotifications) { return WAPI.loadAllEarlierMessages(id).then(_ => { const chat = WAPI.getChat(id); let output = []; const messages = chat.msgs._models; for (const i in messages) { if (i === "remove") { continue; } const messageObj = messages[i]; let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications) if (message) output.push(message); } return output; }) }; window.WAPI.getAllMessageIdsInChat = function (id, includeMe, includeNotifications) { const chat = WAPI.getChat(id); let output = []; const messages = chat.msgs._models; for (const i in messages) { if ((i === "remove") || (!includeMe && messages[i].isMe) || (!includeNotifications && messages[i].isNotification)) { continue; } output.push(messages[i].id._serialized); } return output; }; window.WAPI.getMessageById = function (id) { let result = false; try { let msg = window.Store.Msg.get(id); if (msg) { result = WAPI.processMessageObj(msg, true, true); } } catch (err) { } return result; }; window.WAPI.sendMessageWithMentions = async function (ch, body) { var chat = ch.id ? ch : Store.Chat.get(ch); var chatId = chat.id._serialized; var msgIveSent = chat.msgs.filter(msg => msg.__x_isSentByMe)[0]; if(!msgIveSent) return chat.sendMessage(body); var tempMsg = Object.create(msgIveSent); var newId = window.WAPI.getNewMessageId(chatId); var mentionedJidList = body.match(/@(\d*)/g).filter(x=>x.length>5).map(x=>Store.Contact.get(x.replace("@","")+"@c.us") ? new Store.WidFactory.createUserWid(x.replace("@","")) : '') || undefined; var extend = { ack: 0, id: newId, local: !0, self: "out", t: parseInt(new Date().getTime() / 1000), to: new Store.WidFactory.createWid(chatId), isNewMsg: !0, type: "chat", body, quotedMsg:null, mentionedJidList }; Object.assign(tempMsg, extend); await Store.addAndSendMsgToChat(chat, tempMsg) return newId._serialized; } window.WAPI.sendMessageReturnId = async function (ch, body) { var chat = ch.id ? ch : Store.Chat.get(ch); var chatId = chat.id._serialized; var msgIveSent = chat.msgs.filter(msg => msg.__x_isSentByMe)[0]; if(!msgIveSent) return chat.sendMessage(body); var tempMsg = Object.create(msgIveSent); var newId = window.WAPI.getNewMessageId(chatId); var extend = { ack: 0, id: newId, local: !0, self: "out", t: parseInt(new Date().getTime() / 1000), to: new Store.WidFactory.createWid(chatId), isNewMsg: !0, type: "chat", body, quotedMsg:null }; Object.assign(tempMsg, extend); await Store.addAndSendMsgToChat(chat, tempMsg) return newId._serialized; } window.WAPI.sendMessage = async function (id, message) { if(id==='status@broadcast') return false; let chat = WAPI.getChat(id); if(!chat && !id.includes('g')) { var contact = WAPI.getContact(id) if(!contact) return false; await Store.Chat.find(contact.id) chat = WAPI.getChat(id); } if (chat !== undefined) { // return WAPI.sendMessageReturnId(chat,message).then(id=>{return id}) return await chat.sendMessage(message).then(_=>chat.lastReceivedKey._serialized); } return false; }; window.WAPI.ReplyMessage = function (idMessage, message, done) { var messageObject = window.Store.Msg.get(idMessage); if (messageObject === undefined) { if (done !== undefined) done(false); return false; } messageObject = messageObject.valueOf(); let params = { linkPreview : null, mentionedJidList : null, quotedMsg : messageObject, quotedMsgAdminGroupJid : null }; const chat = WAPI.getChat(messageObject.chat.id) if (chat !== undefined) { if (done !== undefined) { chat.sendMessage(message, params, messageObject).then(function () { function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } var trials = 0; function check() { for (let i = chat.msgs.models.length - 1; i >= 0; i--) { let msg = chat.msgs.models[i]; if (!msg.senderObj.isMe || msg.body != message) { continue; } done(WAPI._serializeMessageObj(msg)); return True; } trials += 1; console.log(trials); if (trials > 30) { done(true); return; } sleep(500).then(check); } check(); }); return true; } else { chat.sendMessage(message, params, messageObject); return true; } } else { if (done !== undefined) done(false); return false; } }; window.WAPI.sendMessage2 = function (id, message) { var chat = WAPI.getChat(id); if (chat !== undefined) { try { chat.sendMessage(message); return true; } catch (error) { return false; } } return false; }; window.WAPI.sendSeen = async function (id) { if (!id) return false; var chat = window.WAPI.getChat(id); if (chat !== undefined) { await Store.SendSeen.sendSeen(chat, false); return true; } return false; }; window.WAPI.markAsUnread = async function (id) { var chat = window.WAPI.getChat(id); if (chat !== undefined) { await Store.SendSeen.markUnread(chat, true); return true; } return false; }; function isChatMessage(message) { if (message.isSentByMe) { return false; } if (message.isNotification) { return false; } if (!message.isUserCreatedType) { return false; } return true; } window.WAPI.setPresence = function (available) { if(available)Store._Presence.setPresenceAvailable(); else Store._Presence.setPresenceUnavailable(); } window.WAPI.getUnreadMessages = function (includeMe, includeNotifications, use_unread_count) { const chats = window.Store.Chat.models; let output = []; for (let chat in chats) { if (isNaN(chat)) { continue; } let messageGroupObj = chats[chat]; let messageGroup = WAPI._serializeChatObj(messageGroupObj); messageGroup.messages = []; const messages = messageGroupObj.msgs._models; for (let i = messages.length - 1; i >= 0; i--) { let messageObj = messages[i]; if (typeof (messageObj.isNewMsg) != "boolean" || messageObj.isNewMsg === false) { continue; } else { messageObj.isNewMsg = false; let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications); if (message) { messageGroup.messages.push(message); } } } if (messageGroup.messages.length > 0) { output.push(messageGroup); } else { // no messages with isNewMsg true if (use_unread_count) { let n = messageGroupObj.unreadCount; // will use unreadCount attribute to fetch last n messages from sender for (let i = messages.length - 1; i >= 0; i--) { let messageObj = messages[i]; if (n > 0) { if (!messageObj.isSentByMe) { let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications); messageGroup.messages.unshift(message); n -= 1; } } else if (n === -1) { // chat was marked as unread so will fetch last message as unread if (!messageObj.isSentByMe) { let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications); messageGroup.messages.unshift(message); break; } } else { // unreadCount = 0 break; } } if (messageGroup.messages.length > 0) { messageGroupObj.unreadCount = 0; // reset unread counter output.push(messageGroup); } } } } return output; }; window.WAPI.getGroupOwnerID = async function (id) { const output = (await WAPI.getGroupMetadata(id)).owner.id; return output; }; window.WAPI.getCommonGroups = async function (id) { let output = []; groups = window.WAPI.getAllGroups(); for (let idx in groups) { try { participants = await window.WAPI.getGroupParticipantIDs(groups[idx].id); if (participants.filter((participant) => participant == id).length) { output.push(groups[idx]); } } catch (err) { console.log("Error in group:"); console.log(groups[idx]); console.log(err); } } return output; }; window.WAPI.getProfilePicFromServer = function (id) { return Store.ProfilePic.profilePicFind(id).then(x => x.eurl); } window.WAPI.getProfilePicSmallFromId = async function (id) { return await window.Store.ProfilePicThumb.find(id).then(async d=> { if (d.img !== undefined) { return await window.WAPI.downloadFileWithCredentials(d.img); } else { return false } }, function (e) { return false }) }; window.WAPI.getProfilePicFromId = async function (id) { return await window.Store.ProfilePicThumb.find(id).then(async d => { if (d.imgFull !== undefined) { return await window.WAPI.downloadFileWithCredentials(d.imgFull); } else { return false } }, function (e) { return false }) }; window.WAPI.downloadFileWithCredentials = async function (url) { if(!axios || !url) return false; const ab = (await axios.get(url,{responseType: 'arraybuffer'})).data return btoa(new Uint8Array(ab).reduce((data, byte) => data + String.fromCharCode(byte), '')); }; window.WAPI.downloadFile = async function (url) { return await new Promise((resolve,reject) => { let xhr = new XMLHttpRequest(); xhr.onload = function () { if (xhr.readyState == 4) { if (xhr.status == 200) { let reader = new FileReader(); reader.readAsDataURL(xhr.response); reader.onload = function (e) { resolve(reader.result.substr(reader.result.indexOf(',') + 1)) }; } else { console.error(xhr.statusText); } } else { console.log(err); resolve(false); } }; xhr.open("GET", url, true); xhr.responseType = 'blob'; xhr.send(null); }) }; window.WAPI.downloadFileBuffer = function (url, done) { let xhr = new XMLHttpRequest(); xhr.onload = function () { if (xhr.readyState == 4) { if (xhr.status == 200) { done(xhr.response); } else { console.error(xhr.statusText); } } else { console.log(err); done(false); } }; xhr.open("GET", url, true); xhr.responseType = 'arraybuffer'; xhr.send(null); }; window.WAPI.arrayBufferToBase64 = (arrayBuffer) => { let binary = ''; const bytes = new Uint8Array(arrayBuffer); const len = bytes.byteLength; for (let i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } return window.btoa(binary); }; window.WAPI.downloadFileAndDecryptNew = async function (msgId) { const msg = window.Store.Msg.get(msgId); if (msg.mediaData.mediaStage != 'RESOLVED') { // try to resolve media await msg.downloadMedia({ downloadEvenIfExpensive: true, rmrReason: 1 }); } if (msg.mediaData.mediaStage.includes('ERROR') || msg.mediaData.mediaStage === 'FETCHING') { // media could not be downloaded return undefined; } try { const decryptedMedia = await window.Store.DownloadManager.downloadAndDecrypt({ directPath: msg.directPath, encFilehash: msg.encFilehash, filehash: msg.filehash, mediaKey: msg.mediaKey, mediaKeyTimestamp: msg.mediaKeyTimestamp, type: msg.type, signal: (new AbortController).signal }); const data = window.WAPI.arrayBufferToBase64(decryptedMedia); return { data, mimetype: msg.mimetype, filename: msg.filename }; } catch (e) { if(e.status && e.status === 404) return undefined; throw e; } } window.WAPI.downloadFileAndDecrypt = function (url, type, mediaKey, mimetype, callbackFunction) { window.WAPI.downloadFileBuffer(url, async function(result) { let a = await Store.CryptoLib.decryptE2EMedia(type || "image", result, mediaKey, mimetype); const reader = new FileReader(); reader.addEventListener('loadend', (e) => { callbackFunction(e.target); }); reader.readAsDataURL(a._blob); }); }; window.WAPI.fileToBase64 = (file) => new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result); reader.onerror = error => reject(error); }); function uploadEncryptedMediaFile(url, hash, data) { return new Promise((resolve, reject) => { let xhr = new XMLHttpRequest(); xhr.onload = function () { if (xhr.readyState == 4) { if (xhr.status == 200) { resolve(JSON.parse(xhr.responseText)); } else { reject(xhr.statusText); } } else { reject(err); } }; let formData = new FormData(); formData.append('hash', hash); formData.append('file', data , 'blob'); xhr.open("POST", url + '?f=j', true); xhr.send(formData); }); }; window.WAPI.getBatteryLevel = function () { return Store.Conn.battery; }; window.WAPI.getIsPlugged = function () { return Store.Conn.plugged; }; window.WAPI.deleteConversation = async function (chatId) { let userId = new window.Store.UserConstructor(chatId, { intentionallyUsePrivateConstructor: true }); let conversation = WAPI.getChat(userId); if (!conversation) { return false; } return await window.Store.sendDelete(conversation, false).then(() => { return true; }).catch(() => { return false; }); }; window.WAPI.smartDeleteMessages = async function (chatId, messageArray, onlyLocal) { var userId = new Store.WidFactory.createWid(chatId); let conversation = WAPI.getChat(userId); if (!conversation) return false; if (!Array.isArray(messageArray)) { messageArray = [messageArray]; } let messagesToDelete = messageArray.map(msgId => (typeof msgId == 'string')?window.Store.Msg.get(msgId):msgId).filter(x=>x); if(messagesToDelete.length==0) return true; let jobs = onlyLocal ? [conversation.sendDeleteMsgs(messagesToDelete,conversation)] :[ conversation.sendRevokeMsgs(messagesToDelete.filter(msg=>msg.isSentByMe),conversation), conversation.sendDeleteMsgs(messagesToDelete.filter(msg=>!msg.isSentByMe),conversation) ] return Promise.all(jobs).then(_=>true) }; window.WAPI.deleteMessage = async function (chatId, messageArray, revoke = false) { let userId = new window.Store.UserConstructor(chatId, { intentionallyUsePrivateConstructor: true }); let conversation = WAPI.getChat(userId); if (!conversation)return false; if (!Array.isArray(messageArray)) { messageArray = [messageArray]; } let messagesToDelete = messageArray.map(msgId => window.Store.Msg.get(msgId)); if (revoke) { conversation.sendRevokeMsgs(messagesToDelete, conversation); } else { conversation.sendDeleteMsgs(messagesToDelete, conversation); } return true; }; window.WAPI.clearChat = async function (id) { return await Store.ChatUtil.sendClear(Store.Chat.get(id),true); } /** * @param id The id of the conversation * @param archive boolean true => archive, false => unarchive * @return boolean true: worked, false: didnt work (probably already in desired state) */ window.WAPI.archiveChat = async function (id, archive) { return await Store.Archive.setArchive(Store.Chat.get(id),archive).then(_=>true).catch(_=>false) } /** * Extracts vcards from a message * @param id string id of the message to extract the vcards from * @returns [vcard] * ``` * [ * { * displayName:"Contact name", * vcard: "loong vcard string" * } * ] * ``` or false if no valid vcards found */ window.WAPI.getVCards = function(id) { var msg = Store.Msg.get(id); if(msg) { if(msg.type=='vcard') { return [ { displayName:msg.subtype, vcard:msg.body } ] } else if (msg.type=='multi_vcard') { return msg.vcardList } else return false; } else { return false } } window.WAPI.checkNumberStatus = async function (id) { try { const result = await window.Store.QueryExist(id); if (result.jid === undefined) throw 404; const data = window.WAPI._serializeNumberStatusObj(result); if (data.status == 200) data.numberExists = true return data; } catch (e) { return window.WAPI._serializeNumberStatusObj({ status: e, jid: id }); } }; /** * New messages observable functions. */ window._WAPI._newMessagesQueue = []; window._WAPI._newMessagesBuffer = (sessionStorage.getItem('saved_msgs') != null) ? JSON.parse(sessionStorage.getItem('saved_msgs')) : []; window._WAPI._newMessagesDebouncer = null; window._WAPI._newMessagesCallbacks = []; window.Store.Msg.off('add'); sessionStorage.removeItem('saved_msgs'); window._WAPI._newMessagesListener = window.Store.Msg.on('add', (newMessage) => { if (newMessage && newMessage.isNewMsg && !newMessage.isSentByMe && !newMessage.isStatusV3) { let message = window.WAPI.processMessageObj(newMessage, false, false); if (message) { window._WAPI._newMessagesQueue.push(message); window._WAPI._newMessagesBuffer.push(message); } // Starts debouncer time to don't call a callback for each message if more than one message arrives // in the same second if (!window._WAPI._newMessagesDebouncer && window._WAPI._newMessagesQueue.length > 0) { window._WAPI._newMessagesDebouncer = setTimeout(() => { let queuedMessages = window._WAPI._newMessagesQueue; window._WAPI._newMessagesDebouncer = null; window._WAPI._newMessagesQueue = []; let removeCallbacks = []; window._WAPI._newMessagesCallbacks.forEach(function (callbackObj) { if (callbackObj.callback !== undefined) { callbackObj.callback(queuedMessages); } if (callbackObj.rmAfterUse === true) { removeCallbacks.push(callbackObj); } }); // Remove removable callbacks. removeCallbacks.forEach(function (rmCallbackObj) { let callbackIndex = window._WAPI._newMessagesCallbacks.indexOf(rmCallbackObj); window._WAPI._newMessagesCallbacks.splice(callbackIndex, 1); }); }, 1000); } } }); window.WAPI._unloadInform = (event) => { // Save in the buffer the ungot unreaded messages window._WAPI._newMessagesBuffer.forEach((message) => { Object.keys(message).forEach(key => message[key] === undefined ? delete message[key] : ''); }); sessionStorage.setItem("saved_msgs", JSON.stringify(window._WAPI._newMessagesBuffer)); // Inform callbacks that the page will be reloaded. window._WAPI._newMessagesCallbacks.forEach(function (callbackObj) { if (callbackObj.callback !== undefined) { callbackObj.callback({ status: -1, message: 'page will be reloaded, wait and register callback again.' }); } }); }; window.addEventListener("unload", window.WAPI._unloadInform, false); window.addEventListener("beforeunload", window.WAPI._unloadInform, false); window.addEventListener("pageunload", window.WAPI._unloadInform, false); /** * Registers a callback to be called when a new message arrives the WAPI. * @param rmCallbackAfterUse - Boolean - Specify if the callback need to be executed only once * @param callback - function - Callback function to be called when a new message arrives. * @returns {boolean} */ window.WAPI.waitNewMessages = function (rmCallbackAfterUse = true, callback) { window._WAPI._newMessagesCallbacks.push({ callback, rmAfterUse: rmCallbackAfterUse }); return true; }; window.WAPI.addAllNewMessagesListener = callback => window.Store.Msg.on('add', (newMessage) => { if (newMessage && newMessage.isNewMsg) { if(!newMessage.clientUrl && (newMessage.mediaKeyTimestamp || newMessage.filehash)){ const cb = (msg) => { if(msg.id._serialized === newMessage.id._serialized && msg.clientUrl) { callback(WAPI.processMessageObj(msg, true, false)); Store.Msg.off('change:isUnsentMedia',cb); } }; Store.Msg.on('change:isUnsentMedia',cb); } else { let message = window.WAPI.processMessageObj(newMessage, true, false); if (message) { callback(message) } }} }); /** * Registers a callback to be called when a the