wabot
Version:
Whatsapp Bot Module for automate response and interact whit users
1,387 lines (1,223 loc) • 96 kB
JavaScript
/**
* 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||!window.Store.Msg) {
(function () {
function getStore(modules) {
let foundCount = 0;
let neededObjects = [
{ id: "Store", conditions: (module) => (module.default && module.default.Chat && module.default.Msg) ? module.default : null},
{ id: "MediaCollection", conditions: (module) => (module.default && module.default.prototype && (module.default.prototype.processFiles !== undefined||module.default.prototype.processAttachments !== undefined)) ? module.default : null },
{ id: "MediaProcess", conditions: (module) => (module.BLOB) ? module : null },
{ id: "Archive", conditions: (module) => (module.setArchive) ? module : null },
{ id: "Block", conditions: (module) => (module.blockContact && module.unblockContact) ? module : null },
{ id: "ChatUtil", conditions: (module) => (module.sendClear) ? module : null },
{ id: "GroupInvite", conditions: (module) => (module.queryGroupInviteCode) ? module : null },
{ id: "Wap", conditions: (module) => (module.createGroup) ? module : null },
{ id: "ServiceWorker", conditions: (module) => (module.default && module.default.killServiceWorker) ? module : null },
{ id: "State", conditions: (module) => (module.STATE && module.STREAM) ? module : null },
{ id: "Cmd", conditions: (module) => (module.default && module.Cmd) ? module.default : null },
{ id: "_Presence", conditions: (module) => (module.setPresenceAvailable && module.setPresenceUnavailable) ? module : null },
{ id: "WapDelete", conditions: (module) => (module.sendConversationDelete && module.sendConversationDelete.length == 2) ? module : null },
{ id: "Conn", conditions: (module) => (module.default && module.default.ref && module.default.refTTL) ? module.default : null },
{ id: "WapQuery", conditions: (module) => (module.queryExist) ? module : ((module.default && module.default.queryExist) ? module.default : null) },
{ id: "CryptoLib", conditions: (module) => (module.decryptE2EMedia) ? module : null },
{ id: "OpenChat", conditions: (module) => (module.default && module.default.prototype && module.default.prototype.openChat) ? module.default : null },
{ id: "UserConstructor", conditions: (module) => (module.default && module.default.prototype && module.default.prototype.isServer && module.default.prototype.isUser) ? module.default : null },
{ id: "SendTextMsgToChat", conditions: (module) => (module.sendTextMsgToChat) ? module.sendTextMsgToChat : null },
{ id: "ReadSeen", conditions: (module) => (module.sendSeen) ? module : null },
{ id: "sendDelete", conditions: (module) => (module.sendDelete) ? module.sendDelete : null },
{ id: "addAndSendMsgToChat", conditions: (module) => (module.addAndSendMsgToChat) ? module.addAndSendMsgToChat : null },
{ id: "sendMsgToChat", conditions: (module) => (module.sendMsgToChat) ? module.sendMsgToChat : null },
{ id: "Catalog", conditions: (module) => (module.Catalog) ? module.Catalog : null },
{ id: 'Perfil',conditions: (module) => module.__esModule === true && module.setPushname && !module.getComposeContents? module : null},
{ id: "MsgKey", conditions: (module) => (module.default&&module.default.toString().includes('MsgKey error: obj is null/undefined')) ? module.default : null },
{ id: "Parser", conditions: (module) => (module.convertToTextWithoutSpecialEmojis) ? module.default : null },
{ id: "Builders", conditions: (module) => (module.TemplateMessage && module.HydratedFourRowTemplate) ? module : null },
{ id: "Me", conditions: (module) => (module.PLATFORMS && module.Conn) ? module.default : null },
{ id: "CallUtils", conditions: (module) => (module.sendCallEnd && module.parseCall) ? module : null },
{ id: "Identity", conditions: (module) => (module.queryIdentity && module.updateIdentity) ? module : null },
{ id: "MyStatus", conditions: (module) => (module.getStatus && module.setMyStatus) ? module : null },
{ id: "ChatStates", conditions: (module) => (module.sendChatStatePaused && module.sendChatStateRecording && module.sendChatStateComposing) ? module : null },
{ id: "GroupActions", conditions: (module) => (module.sendExitGroup && module.localExitGroup) ? module : null },
{ id: "Features", conditions: (module) => (module.FEATURE_CHANGE_EVENT && module.features) ? module : null },
{ id: "MessageUtils", conditions: (module) => (module.storeMessages && module.appendMessage) ? module : null },
{ id: "WebMessageInfo", conditions: (module) => (module.WebMessageInfo && module.WebFeatures) ? module.WebMessageInfo : null },
{ id: "createMessageKey", conditions: (module) => (module.createMessageKey && module.createDeviceSentMessage) ? module.createMessageKey : null },
{ id: "Participants", conditions: (module) => (module.addParticipants && module.removeParticipants && module.promoteParticipants && module.demoteParticipants) ? module : null },
{ id: "WidFactory", conditions: (module) => (module.isWidlike && module.createWid && module.createWidFromWidLike) ? module : null },
{ id: "Base", conditions: (module) => (module.setSubProtocol && module.binSend && module.actionNode) ? module : null },
{ id: "Versions", conditions: (module) => (module.loadProtoVersions && module.default["15"] && module.default["16"] && module.default["17"]) ? module : null },
{ id: "Sticker", conditions: (module) => (module.default && module.default.Sticker) ? module.default.Sticker : null },
{ id: "MediaUpload", conditions: (module) => (module.default && module.default.mediaUpload) ? module.default : null },
{ id: "UploadUtils", conditions: (module) => (module.default && module.default.encryptAndUpload) ? module.default : null }
];
for (let idx in modules) {
if ((typeof modules[idx] === "object") && (modules[idx] !== null)) {
let first = Object.values(modules[idx])[0];
if ((typeof first === "object") && (first.exports)) {
for (let idx2 in modules[idx]) {
let module = modules(idx2);
// console.log("TCL: getStore -> module", module ? Object.getOwnPropertyNames(module.default || module).filter(item => typeof (module.default || module)[item] === 'function').length ? module.default || module : "":'')
if (!module) {
continue;
}
neededObjects.forEach((needObj) => {
if (!needObj.conditions || needObj.foundedModule)
return;
let neededModule = needObj.conditions(module);
if (neededModule !== null) {
foundCount++;
needObj.foundedModule = neededModule;
}
});
if (foundCount == neededObjects.length) {
break;
}
}
let neededStore = neededObjects.find((needObj) => needObj.id === "Store");
window.Store = neededStore.foundedModule ? neededStore.foundedModule : {};
neededObjects.splice(neededObjects.indexOf(neededStore), 1);
neededObjects.forEach((needObj) => {
if (needObj.foundedModule) {
window.Store[needObj.id] = needObj.foundedModule;
}
});
window.Store.sendMessage = function (e) {
return window.Store.SendTextMsgToChat(this, ...arguments);
}
if(window.Store.MediaCollection) window.Store.MediaCollection.prototype.processFiles = window.Store.MediaCollection.prototype.processFiles || window.Store.MediaCollection.prototype.processAttachments;
return window.Store;
}
}
}
}
const parasite = `parasite${Date.now()}`
// webpackJsonp([], { [parasite]: (x, y, z) => getStore(z) }, [parasite]);
if (typeof webpackJsonp === 'function') webpackJsonp([], {[parasite]: (x, y, z) => getStore(z)}, [parasite]);
else webpackJsonp.push([[parasite],{[parasite]: (x, y, z) => getStore(z)},[[parasite]]]);
})();
}
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.WapQuery.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 linkPreview = await Store.WapQuery.queryLinkPreview(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.ReadSeen.sendSeen(chat, false);
return true;
}
return false;
};
window.WAPI.markAsUnread = async function (id) {
var chat = window.WAPI.getChat(id);
if (chat !== undefined) {
await Store.ReadSeen.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.WapQuery.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.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.WapQuery.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 messag