1091 lines
No EOL
45 KiB
HTML
Generated
1091 lines
No EOL
45 KiB
HTML
Generated
<!doctype html>
|
|
<html>
|
|
|
|
<head>
|
|
<meta name="generator" content="JSDoc 3.6.11">
|
|
<meta charset="utf-8">
|
|
<title>whatsapp-web.js 1.28.1-alpha.0 » Source: util/Injected/Utils.js</title>
|
|
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
|
|
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
|
|
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
|
|
<link href="css/baseline.css" rel="stylesheet">
|
|
</head>
|
|
|
|
<body onload="prettyPrint()">
|
|
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
|
|
<div id="jsdoc-navbar-container">
|
|
<div id="jsdoc-navbar-content">
|
|
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>28.<wbr>1-alpha.<wbr>0</a>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
<div id="jsdoc-body-container">
|
|
<div id="jsdoc-content">
|
|
<div id="jsdoc-content-container">
|
|
<div id="jsdoc-banner" role="banner">
|
|
</div>
|
|
<div id="jsdoc-main" role="main">
|
|
<header class="page-header">
|
|
<h1>Source: util/Injected/Utils.js</h1>
|
|
</header>
|
|
<article>
|
|
<pre class="prettyprint linenums"><code>'use strict';
|
|
|
|
exports.LoadUtils = () => {
|
|
window.WWebJS = {};
|
|
|
|
window.WWebJS.forwardMessage = async (chatId, msgId) => {
|
|
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
|
let chat = window.Store.Chat.get(chatId);
|
|
|
|
if (window.compareWwebVersions(window.Debug.VERSION, '>', '2.3000.0')) {
|
|
return window.Store.ForwardUtils.forwardMessagesToChats([msg], [chat], true);
|
|
} else {
|
|
return chat.forwardMessages([msg]);
|
|
}
|
|
};
|
|
|
|
window.WWebJS.sendSeen = async (chatId) => {
|
|
let chat = window.Store.Chat.get(chatId);
|
|
if (chat !== undefined) {
|
|
await window.Store.SendSeen.sendSeen(chat, false);
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
};
|
|
|
|
window.WWebJS.sendMessage = async (chat, content, options = {}) => {
|
|
let attOptions = {};
|
|
if (options.attachment) {
|
|
attOptions = options.sendMediaAsSticker
|
|
? await window.WWebJS.processStickerData(options.attachment)
|
|
: await window.WWebJS.processMediaData(options.attachment, {
|
|
forceVoice: options.sendAudioAsVoice,
|
|
forceDocument: options.sendMediaAsDocument,
|
|
forceGif: options.sendVideoAsGif
|
|
});
|
|
|
|
attOptions.caption = options.caption;
|
|
content = options.sendMediaAsSticker ? undefined : attOptions.preview;
|
|
attOptions.isViewOnce = options.isViewOnce;
|
|
|
|
delete options.attachment;
|
|
delete options.sendMediaAsSticker;
|
|
}
|
|
let quotedMsgOptions = {};
|
|
if (options.quotedMessageId) {
|
|
let quotedMessage = await window.Store.Msg.getMessagesById([options.quotedMessageId]);
|
|
|
|
if (quotedMessage['messages'].length == 1) {
|
|
quotedMessage = quotedMessage['messages'][0];
|
|
|
|
// TODO remove .canReply() once all clients are updated to >= v2.2241.6
|
|
const canReply = window.Store.ReplyUtils ?
|
|
window.Store.ReplyUtils.canReplyMsg(quotedMessage.unsafe()) :
|
|
quotedMessage.canReply();
|
|
|
|
if (canReply) {
|
|
quotedMsgOptions = quotedMessage.msgContextInfo(chat);
|
|
}
|
|
}else{
|
|
if(!options.ignoreQuoteErrors) {
|
|
throw new Error('Could not get the quoted message.');
|
|
}
|
|
}
|
|
|
|
delete options.ignoreQuoteErrors;
|
|
delete options.quotedMessageId;
|
|
}
|
|
|
|
if (options.mentionedJidList) {
|
|
options.mentionedJidList = await Promise.all(
|
|
options.mentionedJidList.map(async (id) => {
|
|
const wid = window.Store.WidFactory.createWid(id);
|
|
if (await window.Store.QueryExist(wid)) {
|
|
return wid;
|
|
}
|
|
})
|
|
);
|
|
options.mentionedJidList = options.mentionedJidList.filter(Boolean);
|
|
}
|
|
|
|
if (options.groupMentions) {
|
|
options.groupMentions = options.groupMentions.map((e) => ({
|
|
groupSubject: e.subject,
|
|
groupJid: window.Store.WidFactory.createWid(e.id)
|
|
}));
|
|
}
|
|
|
|
let locationOptions = {};
|
|
if (options.location) {
|
|
let { latitude, longitude, description, url } = options.location;
|
|
url = window.Store.Validators.findLink(url)?.href;
|
|
url &amp;&amp; !description &amp;&amp; (description = url);
|
|
locationOptions = {
|
|
type: 'location',
|
|
loc: description,
|
|
lat: latitude,
|
|
lng: longitude,
|
|
clientUrl: url
|
|
};
|
|
delete options.location;
|
|
}
|
|
|
|
let _pollOptions = {};
|
|
if (options.poll) {
|
|
const { pollName, pollOptions } = options.poll;
|
|
const { allowMultipleAnswers, messageSecret } = options.poll.options;
|
|
_pollOptions = {
|
|
type: 'poll_creation',
|
|
pollName: pollName,
|
|
pollOptions: pollOptions,
|
|
pollSelectableOptionsCount: allowMultipleAnswers ? 0 : 1,
|
|
messageSecret:
|
|
Array.isArray(messageSecret) &amp;&amp; messageSecret.length === 32
|
|
? new Uint8Array(messageSecret)
|
|
: window.crypto.getRandomValues(new Uint8Array(32))
|
|
};
|
|
delete options.poll;
|
|
}
|
|
|
|
let vcardOptions = {};
|
|
if (options.contactCard) {
|
|
let contact = window.Store.Contact.get(options.contactCard);
|
|
vcardOptions = {
|
|
body: window.Store.VCard.vcardFromContactModel(contact).vcard,
|
|
type: 'vcard',
|
|
vcardFormattedName: contact.formattedName
|
|
};
|
|
delete options.contactCard;
|
|
} else if (options.contactCardList) {
|
|
let contacts = options.contactCardList.map(c => window.Store.Contact.get(c));
|
|
let vcards = contacts.map(c => window.Store.VCard.vcardFromContactModel(c));
|
|
vcardOptions = {
|
|
type: 'multi_vcard',
|
|
vcardList: vcards,
|
|
body: undefined
|
|
};
|
|
delete options.contactCardList;
|
|
} else if (options.parseVCards &amp;&amp; typeof (content) === 'string' &amp;&amp; content.startsWith('BEGIN:VCARD')) {
|
|
delete options.parseVCards;
|
|
try {
|
|
const parsed = window.Store.VCard.parseVcard(content);
|
|
if (parsed) {
|
|
vcardOptions = {
|
|
type: 'vcard',
|
|
vcardFormattedName: window.Store.VCard.vcardGetNameFromParsed(parsed)
|
|
};
|
|
}
|
|
} catch (_) {
|
|
// not a vcard
|
|
}
|
|
}
|
|
|
|
if (options.linkPreview) {
|
|
delete options.linkPreview;
|
|
const link = window.Store.Validators.findLink(content);
|
|
if (link) {
|
|
let preview = await window.Store.LinkPreview.getLinkPreview(link);
|
|
if (preview &amp;&amp; preview.data) {
|
|
preview = preview.data;
|
|
preview.preview = true;
|
|
preview.subtype = 'url';
|
|
options = {...options, ...preview};
|
|
}
|
|
}
|
|
}
|
|
|
|
let buttonOptions = {};
|
|
if(options.buttons){
|
|
let caption;
|
|
if (options.buttons.type === 'chat') {
|
|
content = options.buttons.body;
|
|
caption = content;
|
|
} else {
|
|
caption = options.caption ? options.caption : ' '; //Caption can't be empty
|
|
}
|
|
buttonOptions = {
|
|
productHeaderImageRejected: false,
|
|
isFromTemplate: false,
|
|
isDynamicReplyButtonsMsg: true,
|
|
title: options.buttons.title ? options.buttons.title : undefined,
|
|
footer: options.buttons.footer ? options.buttons.footer : undefined,
|
|
dynamicReplyButtons: options.buttons.buttons,
|
|
replyButtons: options.buttons.buttons,
|
|
caption: caption
|
|
};
|
|
delete options.buttons;
|
|
}
|
|
|
|
let listOptions = {};
|
|
if (options.list) {
|
|
if (window.Store.Conn.platform === 'smba' || window.Store.Conn.platform === 'smbi') {
|
|
throw '[LT01] Whatsapp business can\'t send this yet';
|
|
}
|
|
listOptions = {
|
|
type: 'list',
|
|
footer: options.list.footer,
|
|
list: {
|
|
...options.list,
|
|
listType: 1
|
|
},
|
|
body: options.list.description
|
|
};
|
|
delete options.list;
|
|
delete listOptions.list.footer;
|
|
}
|
|
|
|
const botOptions = {};
|
|
if (options.invokedBotWid) {
|
|
botOptions.messageSecret = window.crypto.getRandomValues(new Uint8Array(32));
|
|
botOptions.botMessageSecret = await window.Store.BotSecret.genBotMsgSecretFromMsgSecret(botOptions.messageSecret);
|
|
botOptions.invokedBotWid = window.Store.WidFactory.createWid(options.invokedBotWid);
|
|
botOptions.botPersonaId = window.Store.BotProfiles.BotProfileCollection.get(options.invokedBotWid).personaId;
|
|
delete options.invokedBotWid;
|
|
}
|
|
|
|
let meUser = window.Store.User.getMaybeMeUser();
|
|
const newId = await window.Store.MsgKey.newId();
|
|
|
|
if (chat.id.isGroup() &amp;&amp; chat.groupMetadata.isLidAddressingMode) {
|
|
meUser = window.Store.User.getMaybeMeLidUser();
|
|
}
|
|
|
|
const newMsgId = new window.Store.MsgKey({
|
|
from: meUser,
|
|
to: chat.id,
|
|
id: newId,
|
|
participant: chat.id.isGroup() ? meUser : undefined,
|
|
selfDir: 'out',
|
|
});
|
|
|
|
const extraOptions = options.extraOptions || {};
|
|
delete options.extraOptions;
|
|
|
|
const ephemeralFields = window.Store.EphemeralFields.getEphemeralFields(chat);
|
|
|
|
const message = {
|
|
...options,
|
|
id: newMsgId,
|
|
ack: 0,
|
|
body: content,
|
|
from: meUser,
|
|
to: chat.id,
|
|
local: true,
|
|
self: 'out',
|
|
t: parseInt(new Date().getTime() / 1000),
|
|
isNewMsg: true,
|
|
type: 'chat',
|
|
...ephemeralFields,
|
|
...locationOptions,
|
|
..._pollOptions,
|
|
...attOptions,
|
|
...(attOptions.toJSON ? attOptions.toJSON() : {}),
|
|
...quotedMsgOptions,
|
|
...vcardOptions,
|
|
...buttonOptions,
|
|
...listOptions,
|
|
...botOptions,
|
|
...extraOptions
|
|
};
|
|
|
|
// Bot's won't reply if canonicalUrl is set (linking)
|
|
if (botOptions) {
|
|
delete message.canonicalUrl;
|
|
}
|
|
|
|
await window.Store.SendMessage.addAndSendMsgToChat(chat, message);
|
|
return window.Store.Msg.get(newMsgId._serialized);
|
|
};
|
|
|
|
window.WWebJS.editMessage = async (msg, content, options = {}) => {
|
|
|
|
const extraOptions = options.extraOptions || {};
|
|
delete options.extraOptions;
|
|
|
|
if (options.mentionedJidList) {
|
|
options.mentionedJidList = await Promise.all(
|
|
options.mentionedJidList.map(async (id) => {
|
|
const wid = window.Store.WidFactory.createWid(id);
|
|
if (await window.Store.QueryExist(wid)) {
|
|
return wid;
|
|
}
|
|
})
|
|
);
|
|
options.mentionedJidList = options.mentionedJidList.filter(Boolean);
|
|
}
|
|
|
|
if (options.groupMentions) {
|
|
options.groupMentions = options.groupMentions.map((e) => ({
|
|
groupSubject: e.subject,
|
|
groupJid: window.Store.WidFactory.createWid(e.id)
|
|
}));
|
|
}
|
|
|
|
if (options.linkPreview) {
|
|
delete options.linkPreview;
|
|
const link = window.Store.Validators.findLink(content);
|
|
if (link) {
|
|
const preview = await window.Store.LinkPreview.getLinkPreview(link);
|
|
preview.preview = true;
|
|
preview.subtype = 'url';
|
|
options = { ...options, ...preview };
|
|
}
|
|
}
|
|
|
|
|
|
const internalOptions = {
|
|
...options,
|
|
...extraOptions
|
|
};
|
|
|
|
await window.Store.EditMessage.sendMessageEdit(msg, content, internalOptions);
|
|
return window.Store.Msg.get(msg.id._serialized);
|
|
};
|
|
|
|
window.WWebJS.toStickerData = async (mediaInfo) => {
|
|
if (mediaInfo.mimetype == 'image/webp') return mediaInfo;
|
|
|
|
const file = window.WWebJS.mediaInfoToFile(mediaInfo);
|
|
const webpSticker = await window.Store.StickerTools.toWebpSticker(file);
|
|
const webpBuffer = await webpSticker.arrayBuffer();
|
|
const data = window.WWebJS.arrayBufferToBase64(webpBuffer);
|
|
|
|
return {
|
|
mimetype: 'image/webp',
|
|
data
|
|
};
|
|
};
|
|
|
|
window.WWebJS.processStickerData = async (mediaInfo) => {
|
|
if (mediaInfo.mimetype !== 'image/webp') throw new Error('Invalid media type');
|
|
|
|
const file = window.WWebJS.mediaInfoToFile(mediaInfo);
|
|
let filehash = await window.WWebJS.getFileHash(file);
|
|
let mediaKey = await window.WWebJS.generateHash(32);
|
|
|
|
const controller = new AbortController();
|
|
const uploadedInfo = await window.Store.UploadUtils.encryptAndUpload({
|
|
blob: file,
|
|
type: 'sticker',
|
|
signal: controller.signal,
|
|
mediaKey
|
|
});
|
|
|
|
const stickerInfo = {
|
|
...uploadedInfo,
|
|
clientUrl: uploadedInfo.url,
|
|
deprecatedMms3Url: uploadedInfo.url,
|
|
uploadhash: uploadedInfo.encFilehash,
|
|
size: file.size,
|
|
type: 'sticker',
|
|
filehash
|
|
};
|
|
|
|
return stickerInfo;
|
|
};
|
|
|
|
window.WWebJS.processMediaData = async (mediaInfo, { forceVoice, forceDocument, forceGif }) => {
|
|
const file = window.WWebJS.mediaInfoToFile(mediaInfo);
|
|
const mData = await window.Store.OpaqueData.createFromData(file, file.type);
|
|
const mediaPrep = window.Store.MediaPrep.prepRawMedia(mData, { asDocument: forceDocument });
|
|
const mediaData = await mediaPrep.waitForPrep();
|
|
const mediaObject = window.Store.MediaObject.getOrCreateMediaObject(mediaData.filehash);
|
|
|
|
const mediaType = window.Store.MediaTypes.msgToMediaType({
|
|
type: mediaData.type,
|
|
isGif: mediaData.isGif
|
|
});
|
|
|
|
if (forceVoice &amp;&amp; mediaData.type === 'audio') {
|
|
mediaData.type = 'ptt';
|
|
const waveform = mediaObject.contentInfo.waveform;
|
|
mediaData.waveform =
|
|
waveform ?? await window.WWebJS.generateWaveform(file);
|
|
}
|
|
|
|
if (forceGif &amp;&amp; mediaData.type === 'video') {
|
|
mediaData.isGif = true;
|
|
}
|
|
|
|
if (forceDocument) {
|
|
mediaData.type = 'document';
|
|
}
|
|
|
|
if (!(mediaData.mediaBlob instanceof window.Store.OpaqueData)) {
|
|
mediaData.mediaBlob = await window.Store.OpaqueData.createFromData(mediaData.mediaBlob, mediaData.mediaBlob.type);
|
|
}
|
|
|
|
mediaData.renderableUrl = mediaData.mediaBlob.url();
|
|
mediaObject.consolidate(mediaData.toJSON());
|
|
mediaData.mediaBlob.autorelease();
|
|
|
|
const uploadedMedia = await window.Store.MediaUpload.uploadMedia({
|
|
mimetype: mediaData.mimetype,
|
|
mediaObject,
|
|
mediaType
|
|
});
|
|
|
|
const mediaEntry = uploadedMedia.mediaEntry;
|
|
if (!mediaEntry) {
|
|
throw new Error('upload failed: media entry was not created');
|
|
}
|
|
|
|
mediaData.set({
|
|
clientUrl: mediaEntry.mmsUrl,
|
|
deprecatedMms3Url: mediaEntry.deprecatedMms3Url,
|
|
directPath: mediaEntry.directPath,
|
|
mediaKey: mediaEntry.mediaKey,
|
|
mediaKeyTimestamp: mediaEntry.mediaKeyTimestamp,
|
|
filehash: mediaObject.filehash,
|
|
encFilehash: mediaEntry.encFilehash,
|
|
uploadhash: mediaEntry.uploadHash,
|
|
size: mediaObject.size,
|
|
streamingSidecar: mediaEntry.sidecar,
|
|
firstFrameSidecar: mediaEntry.firstFrameSidecar
|
|
});
|
|
|
|
return mediaData;
|
|
};
|
|
|
|
window.WWebJS.getMessageModel = message => {
|
|
const msg = message.serialize();
|
|
|
|
msg.isEphemeral = message.isEphemeral;
|
|
msg.isStatusV3 = message.isStatusV3;
|
|
msg.links = (window.Store.Validators.findLinks(message.mediaObject ? message.caption : message.body)).map((link) => ({
|
|
link: link.href,
|
|
isSuspicious: Boolean(link.suspiciousCharacters &amp;&amp; link.suspiciousCharacters.size)
|
|
}));
|
|
|
|
if (msg.buttons) {
|
|
msg.buttons = msg.buttons.serialize();
|
|
}
|
|
if (msg.dynamicReplyButtons) {
|
|
msg.dynamicReplyButtons = JSON.parse(JSON.stringify(msg.dynamicReplyButtons));
|
|
}
|
|
if (msg.replyButtons) {
|
|
msg.replyButtons = JSON.parse(JSON.stringify(msg.replyButtons));
|
|
}
|
|
|
|
if (typeof msg.id.remote === 'object') {
|
|
msg.id = Object.assign({}, msg.id, { remote: msg.id.remote._serialized });
|
|
}
|
|
|
|
delete msg.pendingAckUpdate;
|
|
|
|
return msg;
|
|
};
|
|
|
|
window.WWebJS.getPollVoteModel = async (vote) => {
|
|
const _vote = vote.serialize();
|
|
if (!vote.parentMsgKey) return null;
|
|
const msg =
|
|
window.Store.Msg.get(vote.parentMsgKey) || (await window.Store.Msg.getMessagesById([vote.parentMsgKey]))?.messages?.[0];
|
|
msg &amp;&amp; (_vote.parentMessage = window.WWebJS.getMessageModel(msg));
|
|
return _vote;
|
|
};
|
|
|
|
window.WWebJS.getChatModel = async chat => {
|
|
|
|
let res = chat.serialize();
|
|
res.isGroup = false;
|
|
res.formattedTitle = chat.formattedTitle;
|
|
res.isMuted = chat.mute?.expiration !== 0;
|
|
|
|
if (chat.groupMetadata) {
|
|
res.isGroup = true;
|
|
const chatWid = window.Store.WidFactory.createWid((chat.id._serialized));
|
|
await window.Store.GroupMetadata.update(chatWid);
|
|
res.groupMetadata = chat.groupMetadata.serialize();
|
|
res.isReadOnly = chat.groupMetadata.announce;
|
|
}
|
|
|
|
res.lastMessage = null;
|
|
if (res.msgs &amp;&amp; res.msgs.length) {
|
|
const lastMessage = chat.lastReceivedKey
|
|
? window.Store.Msg.get(chat.lastReceivedKey._serialized) || (await window.Store.Msg.getMessagesById([chat.lastReceivedKey._serialized]))?.messages?.[0]
|
|
: null;
|
|
if (lastMessage) {
|
|
res.lastMessage = window.WWebJS.getMessageModel(lastMessage);
|
|
}
|
|
}
|
|
|
|
delete res.msgs;
|
|
delete res.msgUnsyncedButtonReplyMsgs;
|
|
delete res.unsyncedButtonReplies;
|
|
|
|
return res;
|
|
};
|
|
|
|
window.WWebJS.getChat = async chatId => {
|
|
const chatWid = window.Store.WidFactory.createWid(chatId);
|
|
const chat = await window.Store.Chat.find(chatWid);
|
|
return await window.WWebJS.getChatModel(chat);
|
|
};
|
|
|
|
window.WWebJS.getChats = async () => {
|
|
const chats = window.Store.Chat.getModelsArray();
|
|
|
|
const chatPromises = chats.map(chat => window.WWebJS.getChatModel(chat));
|
|
return await Promise.all(chatPromises);
|
|
};
|
|
|
|
window.WWebJS.getContactModel = contact => {
|
|
let res = contact.serialize();
|
|
res.isBusiness = contact.isBusiness === undefined ? false : contact.isBusiness;
|
|
|
|
if (contact.businessProfile) {
|
|
res.businessProfile = contact.businessProfile.serialize();
|
|
}
|
|
|
|
// TODO: remove useOldImplementation and its checks once all clients are updated to >= v2.2327.4
|
|
const useOldImplementation
|
|
= window.compareWwebVersions(window.Debug.VERSION, '&lt;', '2.2327.4');
|
|
|
|
res.isMe = useOldImplementation
|
|
? contact.isMe
|
|
: window.Store.ContactMethods.getIsMe(contact);
|
|
res.isUser = useOldImplementation
|
|
? contact.isUser
|
|
: window.Store.ContactMethods.getIsUser(contact);
|
|
res.isGroup = useOldImplementation
|
|
? contact.isGroup
|
|
: window.Store.ContactMethods.getIsGroup(contact);
|
|
res.isWAContact = useOldImplementation
|
|
? contact.isWAContact
|
|
: window.Store.ContactMethods.getIsWAContact(contact);
|
|
res.isMyContact = useOldImplementation
|
|
? contact.isMyContact
|
|
: window.Store.ContactMethods.getIsMyContact(contact);
|
|
res.isBlocked = contact.isContactBlocked;
|
|
res.userid = useOldImplementation
|
|
? contact.userid
|
|
: window.Store.ContactMethods.getUserid(contact);
|
|
res.isEnterprise = useOldImplementation
|
|
? contact.isEnterprise
|
|
: window.Store.ContactMethods.getIsEnterprise(contact);
|
|
res.verifiedName = useOldImplementation
|
|
? contact.verifiedName
|
|
: window.Store.ContactMethods.getVerifiedName(contact);
|
|
res.verifiedLevel = useOldImplementation
|
|
? contact.verifiedLevel
|
|
: window.Store.ContactMethods.getVerifiedLevel(contact);
|
|
res.statusMute = useOldImplementation
|
|
? contact.statusMute
|
|
: window.Store.ContactMethods.getStatusMute(contact);
|
|
res.name = useOldImplementation
|
|
? contact.name
|
|
: window.Store.ContactMethods.getName(contact);
|
|
res.shortName = useOldImplementation
|
|
? contact.shortName
|
|
: window.Store.ContactMethods.getShortName(contact);
|
|
res.pushname = useOldImplementation
|
|
? contact.pushname
|
|
: window.Store.ContactMethods.getPushname(contact);
|
|
|
|
return res;
|
|
};
|
|
|
|
window.WWebJS.getContact = async contactId => {
|
|
const wid = window.Store.WidFactory.createWid(contactId);
|
|
const contact = await window.Store.Contact.find(wid);
|
|
const bizProfile = await window.Store.BusinessProfile.fetchBizProfile(wid);
|
|
bizProfile.profileOptions &amp;&amp; (contact.businessProfile = bizProfile);
|
|
return window.WWebJS.getContactModel(contact);
|
|
};
|
|
|
|
window.WWebJS.getContacts = () => {
|
|
const contacts = window.Store.Contact.getModelsArray();
|
|
return contacts.map(contact => window.WWebJS.getContactModel(contact));
|
|
};
|
|
|
|
window.WWebJS.mediaInfoToFile = ({ data, mimetype, filename }) => {
|
|
const binaryData = window.atob(data);
|
|
|
|
const buffer = new ArrayBuffer(binaryData.length);
|
|
const view = new Uint8Array(buffer);
|
|
for (let i = 0; i &lt; binaryData.length; i++) {
|
|
view[i] = binaryData.charCodeAt(i);
|
|
}
|
|
|
|
const blob = new Blob([buffer], { type: mimetype });
|
|
return new File([blob], filename, {
|
|
type: mimetype,
|
|
lastModified: Date.now()
|
|
});
|
|
};
|
|
|
|
window.WWebJS.arrayBufferToBase64 = (arrayBuffer) => {
|
|
let binary = '';
|
|
const bytes = new Uint8Array(arrayBuffer);
|
|
const len = bytes.byteLength;
|
|
for (let i = 0; i &lt; len; i++) {
|
|
binary += String.fromCharCode(bytes[i]);
|
|
}
|
|
return window.btoa(binary);
|
|
};
|
|
|
|
window.WWebJS.arrayBufferToBase64Async = (arrayBuffer) =>
|
|
new Promise((resolve, reject) => {
|
|
const blob = new Blob([arrayBuffer], {
|
|
type: 'application/octet-stream',
|
|
});
|
|
const fileReader = new FileReader();
|
|
fileReader.onload = () => {
|
|
const [, data] = fileReader.result.split(',');
|
|
resolve(data);
|
|
};
|
|
fileReader.onerror = (e) => reject(e);
|
|
fileReader.readAsDataURL(blob);
|
|
});
|
|
|
|
window.WWebJS.getFileHash = async (data) => {
|
|
let buffer = await data.arrayBuffer();
|
|
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
|
|
return btoa(String.fromCharCode(...new Uint8Array(hashBuffer)));
|
|
};
|
|
|
|
window.WWebJS.generateHash = async (length) => {
|
|
var result = '';
|
|
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
var charactersLength = characters.length;
|
|
for (var i = 0; i &lt; length; i++) {
|
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
}
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Referenced from and modified:
|
|
* @see https://github.com/wppconnect-team/wa-js/commit/290ebfefe6021b3d17f7fdfdda5545bb0473b26f
|
|
*/
|
|
window.WWebJS.generateWaveform = async (audioFile) => {
|
|
try {
|
|
const audioData = await audioFile.arrayBuffer();
|
|
const audioContext = new AudioContext();
|
|
const audioBuffer = await audioContext.decodeAudioData(audioData);
|
|
|
|
const rawData = audioBuffer.getChannelData(0);
|
|
const samples = 64;
|
|
const blockSize = Math.floor(rawData.length / samples);
|
|
const filteredData = [];
|
|
for (let i = 0; i &lt; samples; i++) {
|
|
const blockStart = blockSize * i;
|
|
let sum = 0;
|
|
for (let j = 0; j &lt; blockSize; j++) {
|
|
sum = sum + Math.abs(rawData[blockStart + j]);
|
|
}
|
|
filteredData.push(sum / blockSize);
|
|
}
|
|
|
|
const multiplier = Math.pow(Math.max(...filteredData), -1);
|
|
const normalizedData = filteredData.map((n) => n * multiplier);
|
|
|
|
const waveform = new Uint8Array(
|
|
normalizedData.map((n) => Math.floor(100 * n))
|
|
);
|
|
|
|
return waveform;
|
|
} catch (e) {
|
|
return undefined;
|
|
}
|
|
};
|
|
|
|
window.WWebJS.sendClearChat = async (chatId) => {
|
|
let chat = window.Store.Chat.get(chatId);
|
|
if (chat !== undefined) {
|
|
await window.Store.SendClear.sendClear(chat, false);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
window.WWebJS.sendDeleteChat = async (chatId) => {
|
|
let chat = window.Store.Chat.get(chatId);
|
|
if (chat !== undefined) {
|
|
await window.Store.SendDelete.sendDelete(chat);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
window.WWebJS.sendChatstate = async (state, chatId) => {
|
|
chatId = window.Store.WidFactory.createWid(chatId);
|
|
|
|
switch (state) {
|
|
case 'typing':
|
|
await window.Store.ChatState.sendChatStateComposing(chatId);
|
|
break;
|
|
case 'recording':
|
|
await window.Store.ChatState.sendChatStateRecording(chatId);
|
|
break;
|
|
case 'stop':
|
|
await window.Store.ChatState.sendChatStatePaused(chatId);
|
|
break;
|
|
default:
|
|
throw 'Invalid chatstate';
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
window.WWebJS.getLabelModel = label => {
|
|
let res = label.serialize();
|
|
res.hexColor = label.hexColor;
|
|
|
|
return res;
|
|
};
|
|
|
|
window.WWebJS.getLabels = () => {
|
|
const labels = window.Store.Label.getModelsArray();
|
|
return labels.map(label => window.WWebJS.getLabelModel(label));
|
|
};
|
|
|
|
window.WWebJS.getLabel = (labelId) => {
|
|
const label = window.Store.Label.get(labelId);
|
|
return window.WWebJS.getLabelModel(label);
|
|
};
|
|
|
|
window.WWebJS.getChatLabels = async (chatId) => {
|
|
const chat = await window.WWebJS.getChat(chatId);
|
|
return (chat.labels || []).map(id => window.WWebJS.getLabel(id));
|
|
};
|
|
|
|
window.WWebJS.getOrderDetail = async (orderId, token, chatId) => {
|
|
const chatWid = window.Store.WidFactory.createWid(chatId);
|
|
return window.Store.QueryOrder.queryOrder(chatWid, orderId, 80, 80, token);
|
|
};
|
|
|
|
window.WWebJS.getProductMetadata = async (productId) => {
|
|
let sellerId = window.Store.Conn.wid;
|
|
let product = await window.Store.QueryProduct.queryProduct(sellerId, productId);
|
|
if (product &amp;&amp; product.data) {
|
|
return product.data;
|
|
}
|
|
|
|
return undefined;
|
|
};
|
|
|
|
window.WWebJS.rejectCall = async (peerJid, id) => {
|
|
peerJid = peerJid.split('@')[0] + '@s.whatsapp.net';
|
|
let userId = window.Store.User.getMaybeMeUser().user + '@s.whatsapp.net';
|
|
const stanza = window.Store.SocketWap.wap('call', {
|
|
id: window.Store.SocketWap.generateId(),
|
|
from: window.Store.SocketWap.USER_JID(userId),
|
|
to: window.Store.SocketWap.USER_JID(peerJid),
|
|
}, [
|
|
window.Store.SocketWap.wap('reject', {
|
|
'call-id': id,
|
|
'call-creator': window.Store.SocketWap.USER_JID(peerJid),
|
|
count: '0',
|
|
})
|
|
]);
|
|
await window.Store.Socket.deprecatedCastStanza(stanza);
|
|
};
|
|
|
|
window.WWebJS.cropAndResizeImage = async (media, options = {}) => {
|
|
if (!media.mimetype.includes('image'))
|
|
throw new Error('Media is not an image');
|
|
|
|
if (options.mimetype &amp;&amp; !options.mimetype.includes('image'))
|
|
delete options.mimetype;
|
|
|
|
options = Object.assign({ size: 640, mimetype: media.mimetype, quality: .75, asDataUrl: false }, options);
|
|
|
|
const img = await new Promise ((resolve, reject) => {
|
|
const img = new Image();
|
|
img.onload = () => resolve(img);
|
|
img.onerror = reject;
|
|
img.src = `data:${media.mimetype};base64,${media.data}`;
|
|
});
|
|
|
|
const sl = Math.min(img.width, img.height);
|
|
const sx = Math.floor((img.width - sl) / 2);
|
|
const sy = Math.floor((img.height - sl) / 2);
|
|
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = options.size;
|
|
canvas.height = options.size;
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
ctx.drawImage(img, sx, sy, sl, sl, 0, 0, options.size, options.size);
|
|
|
|
const dataUrl = canvas.toDataURL(options.mimetype, options.quality);
|
|
|
|
if (options.asDataUrl)
|
|
return dataUrl;
|
|
|
|
return Object.assign(media, {
|
|
mimetype: options.mimeType,
|
|
data: dataUrl.replace(`data:${options.mimeType};base64,`, '')
|
|
});
|
|
};
|
|
|
|
window.WWebJS.setPicture = async (chatid, media) => {
|
|
const thumbnail = await window.WWebJS.cropAndResizeImage(media, { asDataUrl: true, mimetype: 'image/jpeg', size: 96 });
|
|
const profilePic = await window.WWebJS.cropAndResizeImage(media, { asDataUrl: true, mimetype: 'image/jpeg', size: 640 });
|
|
|
|
const chatWid = window.Store.WidFactory.createWid(chatid);
|
|
try {
|
|
const collection = window.Store.ProfilePicThumb.get(chatid);
|
|
if (!collection.canSet()) return;
|
|
|
|
const res = await window.Store.GroupUtils.sendSetPicture(chatWid, thumbnail, profilePic);
|
|
return res ? res.status === 200 : false;
|
|
} catch (err) {
|
|
if(err.name === 'ServerStatusCodeError') return false;
|
|
throw err;
|
|
}
|
|
};
|
|
|
|
window.WWebJS.deletePicture = async (chatid) => {
|
|
const chatWid = window.Store.WidFactory.createWid(chatid);
|
|
try {
|
|
const collection = window.Store.ProfilePicThumb.get(chatid);
|
|
if (!collection.canDelete()) return;
|
|
|
|
const res = await window.Store.GroupUtils.requestDeletePicture(chatWid);
|
|
return res ? res.status === 200 : false;
|
|
} catch (err) {
|
|
if(err.name === 'ServerStatusCodeError') return false;
|
|
throw err;
|
|
}
|
|
};
|
|
|
|
window.WWebJS.getProfilePicThumbToBase64 = async (chatWid) => {
|
|
const profilePicCollection = await window.Store.ProfilePicThumb.find(chatWid);
|
|
|
|
const _readImageAsBase64 = (imageBlob) => {
|
|
return new Promise((resolve) => {
|
|
const reader = new FileReader();
|
|
reader.onloadend = function () {
|
|
const base64Image = reader.result;
|
|
if (base64Image == null) {
|
|
resolve(undefined);
|
|
} else {
|
|
const base64Data = base64Image.toString().split(',')[1];
|
|
resolve(base64Data);
|
|
}
|
|
};
|
|
reader.readAsDataURL(imageBlob);
|
|
});
|
|
};
|
|
|
|
if (profilePicCollection?.img) {
|
|
try {
|
|
const response = await fetch(profilePicCollection.img);
|
|
if (response.ok) {
|
|
const imageBlob = await response.blob();
|
|
if (imageBlob) {
|
|
const base64Image = await _readImageAsBase64(imageBlob);
|
|
return base64Image;
|
|
}
|
|
}
|
|
} catch (error) { /* empty */ }
|
|
}
|
|
return undefined;
|
|
};
|
|
|
|
window.WWebJS.getAddParticipantsRpcResult = async (groupMetadata, groupWid, participantWid) => {
|
|
const participantLidArgs = groupMetadata?.isLidAddressingMode
|
|
? {
|
|
phoneNumber: participantWid,
|
|
lid: window.Store.LidUtils.getCurrentLid(participantWid)
|
|
}
|
|
: { phoneNumber: participantWid };
|
|
|
|
const iqTo = window.Store.WidToJid.widToGroupJid(groupWid);
|
|
|
|
const participantArgs =
|
|
participantLidArgs.lid
|
|
? [{
|
|
participantJid: window.Store.WidToJid.widToUserJid(participantLidArgs.lid),
|
|
phoneNumberMixinArgs: {
|
|
anyPhoneNumber: window.Store.WidToJid.widToUserJid(participantLidArgs.phoneNumber)
|
|
}
|
|
}]
|
|
: [{
|
|
participantJid: window.Store.WidToJid.widToUserJid(participantLidArgs.phoneNumber)
|
|
}];
|
|
|
|
let rpcResult, resultArgs;
|
|
const isOldImpl = window.compareWwebVersions(window.Debug.VERSION, '&lt;=', '2.2335.9');
|
|
const data = {
|
|
name: undefined,
|
|
code: undefined,
|
|
inviteV4Code: undefined,
|
|
inviteV4CodeExp: undefined
|
|
};
|
|
|
|
try {
|
|
rpcResult = await window.Store.GroupParticipants.sendAddParticipantsRPC({ participantArgs, iqTo });
|
|
resultArgs = isOldImpl
|
|
? rpcResult.value.addParticipant[0].addParticipantsParticipantMixins
|
|
: rpcResult.value.addParticipant[0]
|
|
.addParticipantsParticipantAddedOrNonRegisteredWaUserParticipantErrorLidResponseMixinGroup
|
|
.value
|
|
.addParticipantsParticipantMixins;
|
|
} catch (err) {
|
|
data.code = 400;
|
|
return data;
|
|
}
|
|
|
|
if (rpcResult.name === 'AddParticipantsResponseSuccess') {
|
|
const code = resultArgs?.value.error ?? '200';
|
|
data.name = resultArgs?.name;
|
|
data.code = +code;
|
|
data.inviteV4Code = resultArgs?.value.addRequestCode;
|
|
data.inviteV4CodeExp = resultArgs?.value.addRequestExpiration?.toString();
|
|
}
|
|
|
|
else if (rpcResult.name === 'AddParticipantsResponseClientError') {
|
|
const { code: code } = rpcResult.value.errorAddParticipantsClientErrors.value;
|
|
data.code = +code;
|
|
}
|
|
|
|
else if (rpcResult.name === 'AddParticipantsResponseServerError') {
|
|
const { code: code } = rpcResult.value.errorServerErrors.value;
|
|
data.code = +code;
|
|
}
|
|
|
|
return data;
|
|
};
|
|
|
|
window.WWebJS.membershipRequestAction = async (groupId, action, requesterIds, sleep) => {
|
|
const groupWid = window.Store.WidFactory.createWid(groupId);
|
|
const group = await window.Store.Chat.find(groupWid);
|
|
const toApprove = action === 'Approve';
|
|
let membershipRequests;
|
|
let response;
|
|
let result = [];
|
|
|
|
await window.Store.GroupQueryAndUpdate({ id: groupId });
|
|
|
|
if (!requesterIds?.length) {
|
|
membershipRequests = group.groupMetadata.membershipApprovalRequests._models.map(({ id }) => id);
|
|
} else {
|
|
!Array.isArray(requesterIds) &amp;&amp; (requesterIds = [requesterIds]);
|
|
membershipRequests = requesterIds.map(r => window.Store.WidFactory.createWid(r));
|
|
}
|
|
|
|
if (!membershipRequests.length) return [];
|
|
|
|
const participantArgs = membershipRequests.map(m => ({
|
|
participantArgs: [
|
|
{
|
|
participantJid: window.Store.WidToJid.widToUserJid(m)
|
|
}
|
|
]
|
|
}));
|
|
|
|
const groupJid = window.Store.WidToJid.widToGroupJid(groupWid);
|
|
|
|
const _getSleepTime = (sleep) => {
|
|
if (!Array.isArray(sleep) || (sleep.length === 2 &amp;&amp; sleep[0] === sleep[1])) {
|
|
return sleep;
|
|
}
|
|
if (sleep.length === 1) {
|
|
return sleep[0];
|
|
}
|
|
sleep[1] - sleep[0] &lt; 100 &amp;&amp; (sleep[0] = sleep[1]) &amp;&amp; (sleep[1] += 100);
|
|
return Math.floor(Math.random() * (sleep[1] - sleep[0] + 1)) + sleep[0];
|
|
};
|
|
|
|
const membReqResCodes = {
|
|
default: `An unknown error occupied while ${toApprove ? 'approving' : 'rejecting'} the participant membership request`,
|
|
400: 'ParticipantNotFoundError',
|
|
401: 'ParticipantNotAuthorizedError',
|
|
403: 'ParticipantForbiddenError',
|
|
404: 'ParticipantRequestNotFoundError',
|
|
408: 'ParticipantTemporarilyBlockedError',
|
|
409: 'ParticipantConflictError',
|
|
412: 'ParticipantParentLinkedGroupsResourceConstraintError',
|
|
500: 'ParticipantResourceConstraintError'
|
|
};
|
|
|
|
try {
|
|
for (const participant of participantArgs) {
|
|
response = await window.Store.MembershipRequestUtils.sendMembershipRequestsActionRPC({
|
|
iqTo: groupJid,
|
|
[toApprove ? 'approveArgs' : 'rejectArgs']: participant
|
|
});
|
|
|
|
if (response.name === 'MembershipRequestsActionResponseSuccess') {
|
|
const value = toApprove
|
|
? response.value.membershipRequestsActionApprove
|
|
: response.value.membershipRequestsActionReject;
|
|
if (value?.participant) {
|
|
const [_] = value.participant.map(p => {
|
|
const error = toApprove
|
|
? value.participant[0].membershipRequestsActionAcceptParticipantMixins?.value.error
|
|
: value.participant[0].membershipRequestsActionRejectParticipantMixins?.value.error;
|
|
return {
|
|
requesterId: window.Store.WidFactory.createWid(p.jid)._serialized,
|
|
...(error
|
|
? { error: +error, message: membReqResCodes[error] || membReqResCodes.default }
|
|
: { message: `${toApprove ? 'Approved' : 'Rejected'} successfully` })
|
|
};
|
|
});
|
|
_ &amp;&amp; result.push(_);
|
|
}
|
|
} else {
|
|
result.push({
|
|
requesterId: window.Store.JidToWid.userJidToUserWid(participant.participantArgs[0].participantJid)._serialized,
|
|
message: 'ServerStatusCodeError'
|
|
});
|
|
}
|
|
|
|
sleep &amp;&amp;
|
|
participantArgs.length > 1 &amp;&amp;
|
|
participantArgs.indexOf(participant) !== participantArgs.length - 1 &amp;&amp;
|
|
(await new Promise((resolve) => setTimeout(resolve, _getSleepTime(sleep))));
|
|
}
|
|
return result;
|
|
} catch (err) {
|
|
return [];
|
|
}
|
|
};
|
|
|
|
window.WWebJS.pinUnpinMsgAction = async (msgId, action, duration) => {
|
|
const message = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
|
if (!message) return false;
|
|
const response = await window.Store.pinUnpinMsg(message, action, duration);
|
|
return response.messageSendResult === 'OK';
|
|
};
|
|
|
|
window.WWebJS.getStatusModel = status => {
|
|
const res = status.serialize();
|
|
delete res._msgs;
|
|
return res;
|
|
};
|
|
|
|
window.WWebJS.getAllStatuses = () => {
|
|
const statuses = window.Store.Status.getModelsArray();
|
|
return statuses.map(status => window.WWebJS.getStatusModel(status));
|
|
};
|
|
};
|
|
</code></pre>
|
|
</article>
|
|
</div>
|
|
</div>
|
|
<nav id="jsdoc-toc-nav" role="navigation"></nav>
|
|
</div>
|
|
</div>
|
|
<footer id="jsdoc-footer" class="jsdoc-footer">
|
|
<div id="jsdoc-footer-container">
|
|
<p>
|
|
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.11 on May 30, 2025.
|
|
</p>
|
|
</div>
|
|
</footer>
|
|
<script src="scripts/jquery.min.js"></script>
|
|
<script src="scripts/tree.jquery.js"></script>
|
|
<script src="scripts/prettify.js"></script>
|
|
<script src="scripts/jsdoc-toc.js"></script>
|
|
<script src="scripts/linenumber.js"></script>
|
|
<script src="scripts/scrollanchor.js"></script>
|
|
</body>
|
|
|
|
</html> |