whatsapp-web.js
whatsapp-web.js copied to clipboard
Users are unable to receive Lists once they update whatsapp
Is there an existing issue for this?
- [X] I have searched the existing issues
Describe the bug
I have updated my whatsapp today and now i am unable to receive lists like before.
Expected behavior
User should see Lists
Steps to Reproduce the Bug or Issue
Update whatsapp then chat your bot
Relevant Code
No response
Browser Type
Chromium
WhatsApp Account Type
Standard
Does your WhatsApp account have multidevice enabled?
Yes, I am using Multi Device
Environment
ubuntu 20
Additional context
No response
True, I just updated and I can no longer receive lists. No errors either
Edit: I still see on my alternate account (which hasn't been updated) that the list has been sent, I just don't receive it on my main account (which has been updated).
I am experiencing the same issue too. Any help on this @pedroslopez?
same here
Have the same situation
How can i have this done in android studio friend
same here
Same here after update any soultion please
Same here
same here
same here
fixed (#1636)
same, after update android version, now cannot see list button.
Actually the solution is here https://github.com/pedroslopez/whatsapp-web.js/pull/1636 but I had a problem with the syntax, especially with validations like object?.item
.
So change this and replace the code in the /whatsapp-web.js/src/util/Injected.js
file to this
thaks @PurpShell
'use strict';
// Exposes the internal Store to the WhatsApp Web client
exports.ExposeStore = (moduleRaidStr) => {
eval('var moduleRaid = ' + moduleRaidStr);
// eslint-disable-next-line no-undef
window.mR = moduleRaid();
window.Store = Object.assign({}, window.mR.findModule(m => m.default && m.default.Chat)[0].default);
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.CryptoLib = window.mR.findModule('decryptE2EMedia')[0];
window.Store.DownloadManager = window.mR.findModule('downloadManager')[0].downloadManager;
window.Store.MDBackend = window.mR.findModule('isMDBackend')[0].isMDBackend();
window.Store.Features = window.mR.findModule('FEATURE_CHANGE_EVENT')[0].LegacyPhoneFeatures;
window.Store.GroupMetadata = window.mR.findModule((module) => module.default && module.default.handlePendingInvite)[0].default;
window.Store.Invite = window.mR.findModule('sendJoinGroupViaInvite')[0];
window.Store.InviteInfo = window.mR.findModule('sendQueryGroupInvite')[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.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.QueryExist = window.mR.findModule('queryExists')[0].queryExists;
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')[0].default;
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.ChatState = window.mR.findModule('sendChatStateComposing')[0];
window.Store.GroupParticipants = window.mR.findModule('sendPromoteParticipants')[0];
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.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]
};
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
});
};
}
// Function to modify functions.
window.injectToFunction = (selector, callback) => {
const oldFunct = window.mR.findModule(selector.name)[selector.index][selector.property];
window.mR.findModule(selector.name)[selector.index][selector.property] = (...args) => callback(oldFunct, args);
};
window.findProxyModel = (name) => {
const baseName = name.replace(/Model$/, '');
const names = [baseName];
// ChatModel => "chat"
names.push(baseName.replace(/^(\w)/, (l) => l.toLowerCase()));
// CartItemModel => "cart-item"
// ProductListModel => "product_list"
const parts = baseName.split(/(?=[A-Z])/);
names.push(parts.join('-').toLowerCase());
names.push(parts.join('_').toLowerCase());
return window.mR.findModule(
(m) => {
let vA = m ? m.default ? m.default.prototype ? m.default.prototype.proxyName ? m.default.prototype.proxyName : undefined : undefined : undefined : undefined
let vB = m ? m[name] ? m[name].prototype ? m[name].prototype.proxyName ? m[name].prototype.proxyName : undefined : undefined : undefined : undefined
let vC = m ? m[baseName] ? m[baseName].prototype ? m[baseName].prototype.proxyName : undefined: undefined :undefined
return names.includes(
vA || vB || vC
)
}
);
};
window.injectToFunction({index: 0, name: 'createMsgProtobuf', property: 'createMsgProtobuf'}, (func, args) => {
const proto = func(...args);
if (proto.listMessage) {
proto.viewOnceMessage = {
message: {
listMessage: proto.listMessage
}
};
delete proto.listMessage;
}
if (proto.buttonsMessage) {
proto.viewOnceMessage = {
message: {
buttonsMessage: proto.buttonsMessage,
},
};
delete proto.buttonsMessage;
}
return proto;
});
window.injectToFunction({index: 0, name: 'typeAttributeFromProtobuf', property: 'typeAttributeFromProtobuf'}, (func, args) => {
const [proto] = args;
let vA = proto.buttonsMessage ? proto.buttonsMessage.headerType ? proto.buttonsMessage.headerType === 1 : false : false
let vB = proto.buttonsMessage ? proto.buttonsMessage.headerType ? proto.buttonsMessage.headerType === 2 : false : false
if (
vA || vB
) {
return 'text';
}
if (proto.listMessage) {
return 'text';
}
return func(...args);
});
};
exports.LoadUtils = () => {
window.WWebJS = {};
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
});
content = options.sendMediaAsSticker ? undefined : attOptions.preview;
delete options.attachment;
delete options.sendMediaAsSticker;
}
let quotedMsgOptions = {};
if (options.quotedMessageId) {
let quotedMessage = window.Store.Msg.get(options.quotedMessageId);
if (quotedMessage.canReply()) {
quotedMsgOptions = quotedMessage.msgContextInfo(chat);
}
delete options.quotedMessageId;
}
if (options.mentionedJidList) {
options.mentionedJidList = options.mentionedJidList.map(cId => window.Store.Contact.get(cId).id);
}
let locationOptions = {};
if (options.location) {
locationOptions = {
type: 'location',
loc: options.location.description,
lat: options.location.latitude,
lng: options.location.longitude
};
delete options.location;
}
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 && typeof (content) === 'string' && 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;
// Not supported yet by WhatsApp Web on MD
if(!window.Store.MDBackend) {
const link = window.Store.Validators.findLink(content);
if (link) {
const preview = await window.Store.Wap.queryLinkPreview(link.url);
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
}
// UI needs to stop glitching
const ButtonsCollection = window.mR.findModule('ButtonCollection')[0].ButtonCollection;
const ReplyButtonModel = window.findProxyModel('ReplyButtonModel')[0].default;
const collection = new ButtonsCollection(ReplyButtonModel);
const quickButtons = options.buttons.buttons.map(a => {
return new ReplyButtonModel({id: a.buttonId, displayText: a.buttonText.displayText});
});
collection.add(quickButtons);
buttonOptions = {
isDynamicReplyButtonsMsg: true,
title: options.buttons.title ? options.buttons.title : undefined,
footer: options.buttons.footer ? options.buttons.footer : undefined,
dynamicReplyButtons: options.buttons.buttons,
replyButtons: collection,
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 meUser = window.Store.User.getMaybeMeUser();
const isMD = window.Store.MDBackend;
const newMsgId = new window.Store.MsgKey({
from: meUser,
to: chat.id,
id: window.Store.MsgKey.newId(),
participant: isMD && chat.id.isGroup() ? meUser : undefined,
selfDir: 'out',
});
const extraOptions = options.extraOptions || {};
delete options.extraOptions;
const ephemeralSettings = {
ephemeralDuration: chat.isEphemeralSettingOn() ? chat.getEphemeralSetting() : undefined,
ephemeralSettingTimestamp: chat.getEphemeralSettingTimestamp() || undefined,
disappearingModeInitiator: chat.getDisappearingModeInitiator() || undefined,
};
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',
...ephemeralSettings,
...locationOptions,
...attOptions,
...quotedMsgOptions,
...vcardOptions,
...buttonOptions,
...listOptions,
...extraOptions
};
await window.Store.SendMessage.addAndSendMsgToChat(chat, message);
return window.Store.Msg.get(newMsgId._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 && mediaData.type === 'audio') {
mediaData.type = 'ptt';
}
if (forceGif && 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 = (message.getLinks()).map(link => ({
link: link.href,
isSuspicious: Boolean(link.suspiciousCharacters && 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.getChatModel = async chat => {
let res = chat.serialize();
res.isGroup = chat.isGroup;
res.formattedTitle = chat.formattedTitle;
res.isMuted = chat.mute && chat.mute.isMuted;
if (chat.groupMetadata) {
const chatWid = window.Store.WidFactory.createWid((chat.id._serialized));
await window.Store.GroupMetadata.update(chatWid);
res.groupMetadata = chat.groupMetadata.serialize();
}
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;
if (contact.businessProfile) {
res.businessProfile = contact.businessProfile.serialize();
}
res.isMe = contact.isMe;
res.isUser = contact.isUser;
res.isGroup = contact.isGroup;
res.isWAContact = contact.isWAContact;
res.isMyContact = contact.isMyContact;
res.isBlocked = contact.isContactBlocked;
res.userid = contact.userid;
return res;
};
window.WWebJS.getContact = async contactId => {
const wid = window.Store.WidFactory.createWid(contactId);
const contact = await window.Store.Contact.find(wid);
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 < 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 < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
};
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 < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
};
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) => {
if (window.Store.MDBackend) {
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 && product.data) {
return product.data;
}
return undefined;
};
};
Actually the solution is here https://github.com/pedroslopez/whatsapp-web.js/pull/1636 but I had a problem with the syntax, especially with validations like
object?.item
.So change this and replace the code in the
/whatsapp-web.js/src/util/Injected.js
file to thisthaks @PurpShell
'use strict'; // Exposes the internal Store to the WhatsApp Web client exports.ExposeStore = (moduleRaidStr) => { eval('var moduleRaid = ' + moduleRaidStr); // eslint-disable-next-line no-undef window.mR = moduleRaid(); window.Store = Object.assign({}, window.mR.findModule(m => m.default && m.default.Chat)[0].default); 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.CryptoLib = window.mR.findModule('decryptE2EMedia')[0]; window.Store.DownloadManager = window.mR.findModule('downloadManager')[0].downloadManager; window.Store.MDBackend = window.mR.findModule('isMDBackend')[0].isMDBackend(); window.Store.Features = window.mR.findModule('FEATURE_CHANGE_EVENT')[0].LegacyPhoneFeatures; window.Store.GroupMetadata = window.mR.findModule((module) => module.default && module.default.handlePendingInvite)[0].default; window.Store.Invite = window.mR.findModule('sendJoinGroupViaInvite')[0]; window.Store.InviteInfo = window.mR.findModule('sendQueryGroupInvite')[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.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.QueryExist = window.mR.findModule('queryExists')[0].queryExists; 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')[0].default; 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.ChatState = window.mR.findModule('sendChatStateComposing')[0]; window.Store.GroupParticipants = window.mR.findModule('sendPromoteParticipants')[0]; 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.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] }; 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 }); }; } // Function to modify functions. window.injectToFunction = (selector, callback) => { const oldFunct = window.mR.findModule(selector.name)[selector.index][selector.property]; window.mR.findModule(selector.name)[selector.index][selector.property] = (...args) => callback(oldFunct, args); }; window.findProxyModel = (name) => { const baseName = name.replace(/Model$/, ''); const names = [baseName]; // ChatModel => "chat" names.push(baseName.replace(/^(\w)/, (l) => l.toLowerCase())); // CartItemModel => "cart-item" // ProductListModel => "product_list" const parts = baseName.split(/(?=[A-Z])/); names.push(parts.join('-').toLowerCase()); names.push(parts.join('_').toLowerCase()); return window.mR.findModule( (m) => { let vA = m ? m.default ? m.default.prototype ? m.default.prototype.proxyName ? m.default.prototype.proxyName : undefined : undefined : undefined : undefined let vB = m ? m[name] ? m[name].prototype ? m[name].prototype.proxyName ? m[name].prototype.proxyName : undefined : undefined : undefined : undefined let vC = m ? m[baseName] ? m[baseName].prototype ? m[baseName].prototype.proxyName : undefined: undefined :undefined return names.includes( vA || vB || vC ) } ); }; window.injectToFunction({index: 0, name: 'createMsgProtobuf', property: 'createMsgProtobuf'}, (func, args) => { const proto = func(...args); if (proto.listMessage) { proto.viewOnceMessage = { message: { listMessage: proto.listMessage } }; delete proto.listMessage; } if (proto.buttonsMessage) { proto.viewOnceMessage = { message: { buttonsMessage: proto.buttonsMessage, }, }; delete proto.buttonsMessage; } return proto; }); window.injectToFunction({index: 0, name: 'typeAttributeFromProtobuf', property: 'typeAttributeFromProtobuf'}, (func, args) => { const [proto] = args; let vA = proto.buttonsMessage ? proto.buttonsMessage.headerType ? proto.buttonsMessage.headerType === 1 : false : false let vB = proto.buttonsMessage ? proto.buttonsMessage.headerType ? proto.buttonsMessage.headerType === 2 : false : false if ( vA || vB ) { return 'text'; } if (proto.listMessage) { return 'text'; } return func(...args); }); }; exports.LoadUtils = () => { window.WWebJS = {}; 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 }); content = options.sendMediaAsSticker ? undefined : attOptions.preview; delete options.attachment; delete options.sendMediaAsSticker; } let quotedMsgOptions = {}; if (options.quotedMessageId) { let quotedMessage = window.Store.Msg.get(options.quotedMessageId); if (quotedMessage.canReply()) { quotedMsgOptions = quotedMessage.msgContextInfo(chat); } delete options.quotedMessageId; } if (options.mentionedJidList) { options.mentionedJidList = options.mentionedJidList.map(cId => window.Store.Contact.get(cId).id); } let locationOptions = {}; if (options.location) { locationOptions = { type: 'location', loc: options.location.description, lat: options.location.latitude, lng: options.location.longitude }; delete options.location; } 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 && typeof (content) === 'string' && 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; // Not supported yet by WhatsApp Web on MD if(!window.Store.MDBackend) { const link = window.Store.Validators.findLink(content); if (link) { const preview = await window.Store.Wap.queryLinkPreview(link.url); 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 } // UI needs to stop glitching const ButtonsCollection = window.mR.findModule('ButtonCollection')[0].ButtonCollection; const ReplyButtonModel = window.findProxyModel('ReplyButtonModel')[0].default; const collection = new ButtonsCollection(ReplyButtonModel); const quickButtons = options.buttons.buttons.map(a => { return new ReplyButtonModel({id: a.buttonId, displayText: a.buttonText.displayText}); }); collection.add(quickButtons); buttonOptions = { isDynamicReplyButtonsMsg: true, title: options.buttons.title ? options.buttons.title : undefined, footer: options.buttons.footer ? options.buttons.footer : undefined, dynamicReplyButtons: options.buttons.buttons, replyButtons: collection, 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 meUser = window.Store.User.getMaybeMeUser(); const isMD = window.Store.MDBackend; const newMsgId = new window.Store.MsgKey({ from: meUser, to: chat.id, id: window.Store.MsgKey.newId(), participant: isMD && chat.id.isGroup() ? meUser : undefined, selfDir: 'out', }); const extraOptions = options.extraOptions || {}; delete options.extraOptions; const ephemeralSettings = { ephemeralDuration: chat.isEphemeralSettingOn() ? chat.getEphemeralSetting() : undefined, ephemeralSettingTimestamp: chat.getEphemeralSettingTimestamp() || undefined, disappearingModeInitiator: chat.getDisappearingModeInitiator() || undefined, }; 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', ...ephemeralSettings, ...locationOptions, ...attOptions, ...quotedMsgOptions, ...vcardOptions, ...buttonOptions, ...listOptions, ...extraOptions }; await window.Store.SendMessage.addAndSendMsgToChat(chat, message); return window.Store.Msg.get(newMsgId._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 && mediaData.type === 'audio') { mediaData.type = 'ptt'; } if (forceGif && 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 = (message.getLinks()).map(link => ({ link: link.href, isSuspicious: Boolean(link.suspiciousCharacters && 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.getChatModel = async chat => { let res = chat.serialize(); res.isGroup = chat.isGroup; res.formattedTitle = chat.formattedTitle; res.isMuted = chat.mute && chat.mute.isMuted; if (chat.groupMetadata) { const chatWid = window.Store.WidFactory.createWid((chat.id._serialized)); await window.Store.GroupMetadata.update(chatWid); res.groupMetadata = chat.groupMetadata.serialize(); } 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; if (contact.businessProfile) { res.businessProfile = contact.businessProfile.serialize(); } res.isMe = contact.isMe; res.isUser = contact.isUser; res.isGroup = contact.isGroup; res.isWAContact = contact.isWAContact; res.isMyContact = contact.isMyContact; res.isBlocked = contact.isContactBlocked; res.userid = contact.userid; return res; }; window.WWebJS.getContact = async contactId => { const wid = window.Store.WidFactory.createWid(contactId); const contact = await window.Store.Contact.find(wid); 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 < 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 < len; i++) { binary += String.fromCharCode(bytes[i]); } return window.btoa(binary); }; 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 < length; i++) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; }; 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) => { if (window.Store.MDBackend) { 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 && product.data) { return product.data; } return undefined; }; };
This worked for me on local test, but I am experiencing one problem. I am using WhatsBot so whatsapp-web.js installed as dependency so I don't know how to update this... any help @g4w4
Hello, I was having the "chat.isEphemeralSettingOn is not a function" problem with several clients, I deleted all the files that the browser creates and told the clients to connect WhatsApp again (scan the QR Code), it worked perfectly again
Hello, I was having the "chat.isEphemeralSettingOn is not a function" problem with several clients, I deleted all the files that the browser creates and told the clients to connect WhatsApp again (scan the QR Code), it worked perfectly again
I also have the same problem, but even by logging out and deleting the folder then the problem recurs. I think it's a new thing because until 2 days ago there were no problems
i have the same problem, it was working a couple of hours before and now gave me that error, and I did this configure a pair months before
same here
Refer to the help channel in their discord. A workaround is posted https://discord.gg/H7DqQs4
@superneat255 I changed it directly on my server in the path of my project, the file is in
node_modules/whatsapp-web.js/src/util/Injected.js
So far I have not had any problems after that update, the problem is that it is not scalable because every time I install I have to make that modification, hopefully the release will be ready soon
i can run button/list using this step:
- delete folder node_modules
- run this "npm i github:pedroslopez/whatsapp-web.js#fix-buttons-list"
Buttons and lists currently not supported