whatsapp-web-sj.js 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/.env.example +3 -0
  2. package/CODE_OF_CONDUCT.md +133 -0
  3. package/LICENSE +201 -0
  4. package/README.md +185 -0
  5. package/example.js +634 -0
  6. package/index.d.ts +1842 -0
  7. package/index.js +32 -0
  8. package/package.json +55 -0
  9. package/shell.js +36 -0
  10. package/src/Client.js +1747 -0
  11. package/src/authStrategies/BaseAuthStrategy.js +27 -0
  12. package/src/authStrategies/LocalAuth.js +56 -0
  13. package/src/authStrategies/NoAuth.js +12 -0
  14. package/src/authStrategies/RemoteAuth.js +204 -0
  15. package/src/factories/ChatFactory.js +16 -0
  16. package/src/factories/ContactFactory.js +16 -0
  17. package/src/structures/Base.js +22 -0
  18. package/src/structures/BusinessContact.js +21 -0
  19. package/src/structures/Buttons.js +82 -0
  20. package/src/structures/Call.js +76 -0
  21. package/src/structures/Chat.js +275 -0
  22. package/src/structures/ClientInfo.js +71 -0
  23. package/src/structures/Contact.js +208 -0
  24. package/src/structures/GroupChat.js +475 -0
  25. package/src/structures/GroupNotification.js +104 -0
  26. package/src/structures/Label.js +50 -0
  27. package/src/structures/List.js +79 -0
  28. package/src/structures/Location.js +61 -0
  29. package/src/structures/Message.js +711 -0
  30. package/src/structures/MessageMedia.js +111 -0
  31. package/src/structures/Order.js +52 -0
  32. package/src/structures/Payment.js +79 -0
  33. package/src/structures/Poll.js +44 -0
  34. package/src/structures/PollVote.js +61 -0
  35. package/src/structures/PrivateChat.js +13 -0
  36. package/src/structures/PrivateContact.js +13 -0
  37. package/src/structures/Product.js +68 -0
  38. package/src/structures/ProductMetadata.js +25 -0
  39. package/src/structures/Reaction.js +69 -0
  40. package/src/structures/index.js +24 -0
  41. package/src/util/Constants.js +176 -0
  42. package/src/util/Injected/AuthStore/AuthStore.js +17 -0
  43. package/src/util/Injected/AuthStore/LegacyAuthStore.js +22 -0
  44. package/src/util/Injected/LegacyStore.js +146 -0
  45. package/src/util/Injected/Store.js +167 -0
  46. package/src/util/Injected/Utils.js +1017 -0
  47. package/src/util/InterfaceController.js +127 -0
  48. package/src/util/Util.js +186 -0
  49. package/src/webCache/LocalWebCache.js +40 -0
  50. package/src/webCache/RemoteWebCache.js +40 -0
  51. package/src/webCache/WebCache.js +14 -0
  52. package/src/webCache/WebCacheFactory.js +20 -0
@@ -0,0 +1,1017 @@
1
+ 'use strict';
2
+
3
+ exports.LoadUtils = () => {
4
+ window.WWebJS = {};
5
+
6
+ window.WWebJS.forwardMessage = async (chatId, msgId) => {
7
+ const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
8
+ let chat = window.Store.Chat.get(chatId);
9
+
10
+ if (window.compareWwebVersions(window.Debug.VERSION, '>', '2.3000.0')) {
11
+ return window.Store.ForwardUtils.forwardMessagesToChats([msg], [chat], false);
12
+ } else {
13
+ return chat.forwardMessages([msg]);
14
+ }
15
+ };
16
+
17
+ window.WWebJS.sendSeen = async (chatId) => {
18
+ let chat = window.Store.Chat.get(chatId);
19
+ if (chat !== undefined) {
20
+ await window.Store.SendSeen.sendSeen(chat, false);
21
+ return true;
22
+ }
23
+ return false;
24
+
25
+ };
26
+
27
+ window.WWebJS.sendMessage = async (chat, content, options = {}) => {
28
+ let attOptions = {};
29
+ if (options.attachment) {
30
+ attOptions = options.sendMediaAsSticker
31
+ ? await window.WWebJS.processStickerData(options.attachment)
32
+ : await window.WWebJS.processMediaData(options.attachment, {
33
+ forceVoice: options.sendAudioAsVoice,
34
+ forceDocument: options.sendMediaAsDocument,
35
+ forceGif: options.sendVideoAsGif
36
+ });
37
+
38
+ attOptions.caption = options.caption;
39
+ content = options.sendMediaAsSticker ? undefined : attOptions.preview;
40
+ attOptions.isViewOnce = options.isViewOnce;
41
+
42
+ delete options.attachment;
43
+ delete options.sendMediaAsSticker;
44
+ }
45
+ let quotedMsgOptions = {};
46
+ if (options.quotedMessageId) {
47
+ let quotedMessage = await window.Store.Msg.getMessagesById([options.quotedMessageId]);
48
+
49
+ if (quotedMessage['messages'].length != 1) {
50
+ throw new Error('Could not get the quoted message.');
51
+ }
52
+
53
+ quotedMessage = quotedMessage['messages'][0];
54
+
55
+ // TODO remove .canReply() once all clients are updated to >= v2.2241.6
56
+ const canReply = window.Store.ReplyUtils ?
57
+ window.Store.ReplyUtils.canReplyMsg(quotedMessage.unsafe()) :
58
+ quotedMessage.canReply();
59
+
60
+ if (canReply) {
61
+ quotedMsgOptions = quotedMessage.msgContextInfo(chat);
62
+ }
63
+ delete options.quotedMessageId;
64
+ }
65
+
66
+ if (options.mentionedJidList) {
67
+ options.mentionedJidList = await Promise.all(
68
+ options.mentionedJidList.map(async (id) => {
69
+ const wid = window.Store.WidFactory.createWid(id);
70
+ if (await window.Store.QueryExist(wid)) {
71
+ return wid;
72
+ }
73
+ })
74
+ );
75
+ options.mentionedJidList = options.mentionedJidList.filter(Boolean);
76
+ }
77
+
78
+ if (options.groupMentions) {
79
+ options.groupMentions = options.groupMentions.map((e) => ({
80
+ groupSubject: e.subject,
81
+ groupJid: window.Store.WidFactory.createWid(e.id)
82
+ }));
83
+ }
84
+
85
+ let locationOptions = {};
86
+ if (options.location) {
87
+ let { latitude, longitude, description, url } = options.location;
88
+ url = window.Store.Validators.findLink(url)?.href;
89
+ url && !description && (description = url);
90
+ locationOptions = {
91
+ type: 'location',
92
+ loc: description,
93
+ lat: latitude,
94
+ lng: longitude,
95
+ clientUrl: url
96
+ };
97
+ delete options.location;
98
+ }
99
+
100
+ let _pollOptions = {};
101
+ if (options.poll) {
102
+ const { pollName, pollOptions } = options.poll;
103
+ const { allowMultipleAnswers, messageSecret } = options.poll.options;
104
+ _pollOptions = {
105
+ type: 'poll_creation',
106
+ pollName: pollName,
107
+ pollOptions: pollOptions,
108
+ pollSelectableOptionsCount: allowMultipleAnswers ? 0 : 1,
109
+ messageSecret:
110
+ Array.isArray(messageSecret) && messageSecret.length === 32
111
+ ? new Uint8Array(messageSecret)
112
+ : window.crypto.getRandomValues(new Uint8Array(32))
113
+ };
114
+ delete options.poll;
115
+ }
116
+
117
+ let vcardOptions = {};
118
+ if (options.contactCard) {
119
+ let contact = window.Store.Contact.get(options.contactCard);
120
+ vcardOptions = {
121
+ body: window.Store.VCard.vcardFromContactModel(contact).vcard,
122
+ type: 'vcard',
123
+ vcardFormattedName: contact.formattedName
124
+ };
125
+ delete options.contactCard;
126
+ } else if (options.contactCardList) {
127
+ let contacts = options.contactCardList.map(c => window.Store.Contact.get(c));
128
+ let vcards = contacts.map(c => window.Store.VCard.vcardFromContactModel(c));
129
+ vcardOptions = {
130
+ type: 'multi_vcard',
131
+ vcardList: vcards,
132
+ body: undefined
133
+ };
134
+ delete options.contactCardList;
135
+ } else if (options.parseVCards && typeof (content) === 'string' && content.startsWith('BEGIN:VCARD')) {
136
+ delete options.parseVCards;
137
+ try {
138
+ const parsed = window.Store.VCard.parseVcard(content);
139
+ if (parsed) {
140
+ vcardOptions = {
141
+ type: 'vcard',
142
+ vcardFormattedName: window.Store.VCard.vcardGetNameFromParsed(parsed)
143
+ };
144
+ }
145
+ } catch (_) {
146
+ // not a vcard
147
+ }
148
+ }
149
+
150
+ if (options.linkPreview) {
151
+ delete options.linkPreview;
152
+ const link = window.Store.Validators.findLink(content);
153
+ if (link) {
154
+ let preview = await window.Store.LinkPreview.getLinkPreview(link);
155
+ if (preview && preview.data) {
156
+ preview = preview.data;
157
+ preview.preview = true;
158
+ preview.subtype = 'url';
159
+ options = {...options, ...preview};
160
+ }
161
+ }
162
+ }
163
+
164
+ let buttonOptions = {};
165
+ if(options.buttons){
166
+ let caption;
167
+ if (options.buttons.type === 'chat') {
168
+ content = options.buttons.body;
169
+ caption = content;
170
+ } else {
171
+ caption = options.caption ? options.caption : ' '; //Caption can't be empty
172
+ }
173
+ buttonOptions = {
174
+ productHeaderImageRejected: false,
175
+ isFromTemplate: false,
176
+ isDynamicReplyButtonsMsg: true,
177
+ title: options.buttons.title ? options.buttons.title : undefined,
178
+ footer: options.buttons.footer ? options.buttons.footer : undefined,
179
+ dynamicReplyButtons: options.buttons.buttons,
180
+ replyButtons: options.buttons.buttons,
181
+ caption: caption
182
+ };
183
+ delete options.buttons;
184
+ }
185
+
186
+ let listOptions = {};
187
+ if (options.list) {
188
+ if (window.Store.Conn.platform === 'smba' || window.Store.Conn.platform === 'smbi') {
189
+ throw '[LT01] Whatsapp business can\'t send this yet';
190
+ }
191
+ listOptions = {
192
+ type: 'list',
193
+ footer: options.list.footer,
194
+ list: {
195
+ ...options.list,
196
+ listType: 1
197
+ },
198
+ body: options.list.description
199
+ };
200
+ delete options.list;
201
+ delete listOptions.list.footer;
202
+ }
203
+
204
+ const botOptions = {};
205
+ if (options.invokedBotWid) {
206
+ botOptions.messageSecret = window.crypto.getRandomValues(new Uint8Array(32));
207
+ botOptions.botMessageSecret = await window.Store.BotSecret.genBotMsgSecretFromMsgSecret(botOptions.messageSecret);
208
+ botOptions.invokedBotWid = window.Store.WidFactory.createWid(options.invokedBotWid);
209
+ botOptions.botPersonaId = window.Store.BotProfiles.BotProfileCollection.get(options.invokedBotWid).personaId;
210
+ delete options.invokedBotWid;
211
+ }
212
+
213
+ const meUser = window.Store.User.getMaybeMeUser();
214
+ const newId = await window.Store.MsgKey.newId();
215
+
216
+ const newMsgId = new window.Store.MsgKey({
217
+ from: meUser,
218
+ to: chat.id,
219
+ id: newId,
220
+ participant: chat.id.isGroup() ? meUser : undefined,
221
+ selfDir: 'out',
222
+ });
223
+
224
+ const extraOptions = options.extraOptions || {};
225
+ delete options.extraOptions;
226
+
227
+ const ephemeralFields = window.Store.EphemeralFields.getEphemeralFields(chat);
228
+
229
+ const message = {
230
+ ...options,
231
+ id: newMsgId,
232
+ ack: 0,
233
+ body: content,
234
+ from: meUser,
235
+ to: chat.id,
236
+ local: true,
237
+ self: 'out',
238
+ t: parseInt(new Date().getTime() / 1000),
239
+ isNewMsg: true,
240
+ type: 'chat',
241
+ ...ephemeralFields,
242
+ ...locationOptions,
243
+ ..._pollOptions,
244
+ ...attOptions,
245
+ ...(attOptions.toJSON ? attOptions.toJSON() : {}),
246
+ ...quotedMsgOptions,
247
+ ...vcardOptions,
248
+ ...buttonOptions,
249
+ ...listOptions,
250
+ ...botOptions,
251
+ ...extraOptions
252
+ };
253
+
254
+ // Bot's won't reply if canonicalUrl is set (linking)
255
+ if (botOptions) {
256
+ delete message.canonicalUrl;
257
+ }
258
+
259
+ await window.Store.SendMessage.addAndSendMsgToChat(chat, message);
260
+ return window.Store.Msg.get(newMsgId._serialized);
261
+ };
262
+
263
+ window.WWebJS.editMessage = async (msg, content, options = {}) => {
264
+
265
+ const extraOptions = options.extraOptions || {};
266
+ delete options.extraOptions;
267
+
268
+ if (options.mentionedJidList) {
269
+ options.mentionedJidList = await Promise.all(
270
+ options.mentionedJidList.map(async (id) => {
271
+ const wid = window.Store.WidFactory.createWid(id);
272
+ if (await window.Store.QueryExist(wid)) {
273
+ return wid;
274
+ }
275
+ })
276
+ );
277
+ options.mentionedJidList = options.mentionedJidList.filter(Boolean);
278
+ }
279
+
280
+ if (options.groupMentions) {
281
+ options.groupMentions = options.groupMentions.map((e) => ({
282
+ groupSubject: e.subject,
283
+ groupJid: window.Store.WidFactory.createWid(e.id)
284
+ }));
285
+ }
286
+
287
+ if (options.linkPreview) {
288
+ delete options.linkPreview;
289
+ const link = window.Store.Validators.findLink(content);
290
+ if (link) {
291
+ const preview = await window.Store.LinkPreview.getLinkPreview(link);
292
+ preview.preview = true;
293
+ preview.subtype = 'url';
294
+ options = { ...options, ...preview };
295
+ }
296
+ }
297
+
298
+
299
+ const internalOptions = {
300
+ ...options,
301
+ ...extraOptions
302
+ };
303
+
304
+ await window.Store.EditMessage.sendMessageEdit(msg, content, internalOptions);
305
+ return window.Store.Msg.get(msg.id._serialized);
306
+ };
307
+
308
+ window.WWebJS.toStickerData = async (mediaInfo) => {
309
+ if (mediaInfo.mimetype == 'image/webp') return mediaInfo;
310
+
311
+ const file = window.WWebJS.mediaInfoToFile(mediaInfo);
312
+ const webpSticker = await window.Store.StickerTools.toWebpSticker(file);
313
+ const webpBuffer = await webpSticker.arrayBuffer();
314
+ const data = window.WWebJS.arrayBufferToBase64(webpBuffer);
315
+
316
+ return {
317
+ mimetype: 'image/webp',
318
+ data
319
+ };
320
+ };
321
+
322
+ window.WWebJS.processStickerData = async (mediaInfo) => {
323
+ if (mediaInfo.mimetype !== 'image/webp') throw new Error('Invalid media type');
324
+
325
+ const file = window.WWebJS.mediaInfoToFile(mediaInfo);
326
+ let filehash = await window.WWebJS.getFileHash(file);
327
+ let mediaKey = await window.WWebJS.generateHash(32);
328
+
329
+ const controller = new AbortController();
330
+ const uploadedInfo = await window.Store.UploadUtils.encryptAndUpload({
331
+ blob: file,
332
+ type: 'sticker',
333
+ signal: controller.signal,
334
+ mediaKey
335
+ });
336
+
337
+ const stickerInfo = {
338
+ ...uploadedInfo,
339
+ clientUrl: uploadedInfo.url,
340
+ deprecatedMms3Url: uploadedInfo.url,
341
+ uploadhash: uploadedInfo.encFilehash,
342
+ size: file.size,
343
+ type: 'sticker',
344
+ filehash
345
+ };
346
+
347
+ return stickerInfo;
348
+ };
349
+
350
+ window.WWebJS.processMediaData = async (mediaInfo, { forceVoice, forceDocument, forceGif }) => {
351
+ const file = window.WWebJS.mediaInfoToFile(mediaInfo);
352
+ const mData = await window.Store.OpaqueData.createFromData(file, file.type);
353
+ const mediaPrep = window.Store.MediaPrep.prepRawMedia(mData, { asDocument: forceDocument });
354
+ const mediaData = await mediaPrep.waitForPrep();
355
+ const mediaObject = window.Store.MediaObject.getOrCreateMediaObject(mediaData.filehash);
356
+
357
+ const mediaType = window.Store.MediaTypes.msgToMediaType({
358
+ type: mediaData.type,
359
+ isGif: mediaData.isGif
360
+ });
361
+
362
+ if (forceVoice && mediaData.type === 'audio') {
363
+ mediaData.type = 'ptt';
364
+ const waveform = mediaObject.contentInfo.waveform;
365
+ mediaData.waveform =
366
+ waveform ?? await window.WWebJS.generateWaveform(file);
367
+ }
368
+
369
+ if (forceGif && mediaData.type === 'video') {
370
+ mediaData.isGif = true;
371
+ }
372
+
373
+ if (forceDocument) {
374
+ mediaData.type = 'document';
375
+ }
376
+
377
+ if (!(mediaData.mediaBlob instanceof window.Store.OpaqueData)) {
378
+ mediaData.mediaBlob = await window.Store.OpaqueData.createFromData(mediaData.mediaBlob, mediaData.mediaBlob.type);
379
+ }
380
+
381
+ mediaData.renderableUrl = mediaData.mediaBlob.url();
382
+ mediaObject.consolidate(mediaData.toJSON());
383
+ mediaData.mediaBlob.autorelease();
384
+
385
+ const uploadedMedia = await window.Store.MediaUpload.uploadMedia({
386
+ mimetype: mediaData.mimetype,
387
+ mediaObject,
388
+ mediaType
389
+ });
390
+
391
+ const mediaEntry = uploadedMedia.mediaEntry;
392
+ if (!mediaEntry) {
393
+ throw new Error('upload failed: media entry was not created');
394
+ }
395
+
396
+ mediaData.set({
397
+ clientUrl: mediaEntry.mmsUrl,
398
+ deprecatedMms3Url: mediaEntry.deprecatedMms3Url,
399
+ directPath: mediaEntry.directPath,
400
+ mediaKey: mediaEntry.mediaKey,
401
+ mediaKeyTimestamp: mediaEntry.mediaKeyTimestamp,
402
+ filehash: mediaObject.filehash,
403
+ encFilehash: mediaEntry.encFilehash,
404
+ uploadhash: mediaEntry.uploadHash,
405
+ size: mediaObject.size,
406
+ streamingSidecar: mediaEntry.sidecar,
407
+ firstFrameSidecar: mediaEntry.firstFrameSidecar
408
+ });
409
+
410
+ return mediaData;
411
+ };
412
+
413
+ window.WWebJS.getMessageModel = message => {
414
+ const msg = message.serialize();
415
+
416
+ msg.isEphemeral = message.isEphemeral;
417
+ msg.isStatusV3 = message.isStatusV3;
418
+ msg.links = (window.Store.Validators.findLinks(message.mediaObject ? message.caption : message.body)).map((link) => ({
419
+ link: link.href,
420
+ isSuspicious: Boolean(link.suspiciousCharacters && link.suspiciousCharacters.size)
421
+ }));
422
+
423
+ if (msg.buttons) {
424
+ msg.buttons = msg.buttons.serialize();
425
+ }
426
+ if (msg.dynamicReplyButtons) {
427
+ msg.dynamicReplyButtons = JSON.parse(JSON.stringify(msg.dynamicReplyButtons));
428
+ }
429
+ if (msg.replyButtons) {
430
+ msg.replyButtons = JSON.parse(JSON.stringify(msg.replyButtons));
431
+ }
432
+
433
+ if (typeof msg.id.remote === 'object') {
434
+ msg.id = Object.assign({}, msg.id, { remote: msg.id.remote._serialized });
435
+ }
436
+
437
+ delete msg.pendingAckUpdate;
438
+
439
+ return msg;
440
+ };
441
+
442
+ window.WWebJS.getPollVoteModel = async (vote) => {
443
+ const _vote = vote.serialize();
444
+ if (!vote.parentMsgKey) return null;
445
+ const msg =
446
+ window.Store.Msg.get(vote.parentMsgKey) || (await window.Store.Msg.getMessagesById([vote.parentMsgKey]))?.messages?.[0];
447
+ msg && (_vote.parentMessage = window.WWebJS.getMessageModel(msg));
448
+ return _vote;
449
+ };
450
+
451
+ window.WWebJS.getChatModel = async chat => {
452
+
453
+ let res = chat.serialize();
454
+ res.isGroup = chat.isGroup;
455
+ res.formattedTitle = chat.formattedTitle;
456
+ res.isMuted = chat.mute && chat.mute.isMuted;
457
+
458
+ if (chat.groupMetadata) {
459
+ const chatWid = window.Store.WidFactory.createWid((chat.id._serialized));
460
+ await window.Store.GroupMetadata.update(chatWid);
461
+ res.groupMetadata = chat.groupMetadata.serialize();
462
+ }
463
+
464
+ res.lastMessage = null;
465
+ if (res.msgs && res.msgs.length) {
466
+ const lastMessage = chat.lastReceivedKey
467
+ ? window.Store.Msg.get(chat.lastReceivedKey._serialized) || (await window.Store.Msg.getMessagesById([chat.lastReceivedKey._serialized]))?.messages?.[0]
468
+ : null;
469
+ if (lastMessage) {
470
+ res.lastMessage = window.WWebJS.getMessageModel(lastMessage);
471
+ }
472
+ }
473
+
474
+ delete res.msgs;
475
+ delete res.msgUnsyncedButtonReplyMsgs;
476
+ delete res.unsyncedButtonReplies;
477
+
478
+ return res;
479
+ };
480
+
481
+ window.WWebJS.getChat = async chatId => {
482
+ const chatWid = window.Store.WidFactory.createWid(chatId);
483
+ const chat = await window.Store.Chat.find(chatWid);
484
+ return await window.WWebJS.getChatModel(chat);
485
+ };
486
+
487
+ window.WWebJS.getChats = async () => {
488
+ const chats = window.Store.Chat.getModelsArray();
489
+
490
+ const chatPromises = chats.map(chat => window.WWebJS.getChatModel(chat));
491
+ return await Promise.all(chatPromises);
492
+ };
493
+
494
+ window.WWebJS.getContactModel = contact => {
495
+ let res = contact.serialize();
496
+ res.isBusiness = contact.isBusiness === undefined ? false : contact.isBusiness;
497
+
498
+ if (contact.businessProfile) {
499
+ res.businessProfile = contact.businessProfile.serialize();
500
+ }
501
+
502
+ // TODO: remove useOldImplementation and its checks once all clients are updated to >= v2.2327.4
503
+ const useOldImplementation
504
+ = window.compareWwebVersions(window.Debug.VERSION, '<', '2.2327.4');
505
+
506
+ res.isMe = useOldImplementation
507
+ ? contact.isMe
508
+ : window.Store.ContactMethods.getIsMe(contact);
509
+ res.isUser = useOldImplementation
510
+ ? contact.isUser
511
+ : window.Store.ContactMethods.getIsUser(contact);
512
+ res.isGroup = useOldImplementation
513
+ ? contact.isGroup
514
+ : window.Store.ContactMethods.getIsGroup(contact);
515
+ res.isWAContact = useOldImplementation
516
+ ? contact.isWAContact
517
+ : window.Store.ContactMethods.getIsWAContact(contact);
518
+ res.isMyContact = useOldImplementation
519
+ ? contact.isMyContact
520
+ : window.Store.ContactMethods.getIsMyContact(contact);
521
+ res.isBlocked = contact.isContactBlocked;
522
+ res.userid = useOldImplementation
523
+ ? contact.userid
524
+ : window.Store.ContactMethods.getUserid(contact);
525
+ res.isEnterprise = useOldImplementation
526
+ ? contact.isEnterprise
527
+ : window.Store.ContactMethods.getIsEnterprise(contact);
528
+ res.verifiedName = useOldImplementation
529
+ ? contact.verifiedName
530
+ : window.Store.ContactMethods.getVerifiedName(contact);
531
+ res.verifiedLevel = useOldImplementation
532
+ ? contact.verifiedLevel
533
+ : window.Store.ContactMethods.getVerifiedLevel(contact);
534
+ res.statusMute = useOldImplementation
535
+ ? contact.statusMute
536
+ : window.Store.ContactMethods.getStatusMute(contact);
537
+ res.name = useOldImplementation
538
+ ? contact.name
539
+ : window.Store.ContactMethods.getName(contact);
540
+ res.shortName = useOldImplementation
541
+ ? contact.shortName
542
+ : window.Store.ContactMethods.getShortName(contact);
543
+ res.pushname = useOldImplementation
544
+ ? contact.pushname
545
+ : window.Store.ContactMethods.getPushname(contact);
546
+
547
+ return res;
548
+ };
549
+
550
+ window.WWebJS.getContact = async contactId => {
551
+ const wid = window.Store.WidFactory.createWid(contactId);
552
+ const contact = await window.Store.Contact.find(wid);
553
+ const bizProfile = await window.Store.BusinessProfile.fetchBizProfile(wid);
554
+ bizProfile.profileOptions && (contact.businessProfile = bizProfile);
555
+ return window.WWebJS.getContactModel(contact);
556
+ };
557
+
558
+ window.WWebJS.getContacts = () => {
559
+ const contacts = window.Store.Contact.getModelsArray();
560
+ return contacts.map(contact => window.WWebJS.getContactModel(contact));
561
+ };
562
+
563
+ window.WWebJS.mediaInfoToFile = ({ data, mimetype, filename }) => {
564
+ const binaryData = window.atob(data);
565
+
566
+ const buffer = new ArrayBuffer(binaryData.length);
567
+ const view = new Uint8Array(buffer);
568
+ for (let i = 0; i < binaryData.length; i++) {
569
+ view[i] = binaryData.charCodeAt(i);
570
+ }
571
+
572
+ const blob = new Blob([buffer], { type: mimetype });
573
+ return new File([blob], filename, {
574
+ type: mimetype,
575
+ lastModified: Date.now()
576
+ });
577
+ };
578
+
579
+ window.WWebJS.arrayBufferToBase64 = (arrayBuffer) => {
580
+ let binary = '';
581
+ const bytes = new Uint8Array(arrayBuffer);
582
+ const len = bytes.byteLength;
583
+ for (let i = 0; i < len; i++) {
584
+ binary += String.fromCharCode(bytes[i]);
585
+ }
586
+ return window.btoa(binary);
587
+ };
588
+
589
+ window.WWebJS.arrayBufferToBase64Async = (arrayBuffer) =>
590
+ new Promise((resolve, reject) => {
591
+ const blob = new Blob([arrayBuffer], {
592
+ type: 'application/octet-stream',
593
+ });
594
+ const fileReader = new FileReader();
595
+ fileReader.onload = () => {
596
+ const [, data] = fileReader.result.split(',');
597
+ resolve(data);
598
+ };
599
+ fileReader.onerror = (e) => reject(e);
600
+ fileReader.readAsDataURL(blob);
601
+ });
602
+
603
+ window.WWebJS.getFileHash = async (data) => {
604
+ let buffer = await data.arrayBuffer();
605
+ const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
606
+ return btoa(String.fromCharCode(...new Uint8Array(hashBuffer)));
607
+ };
608
+
609
+ window.WWebJS.generateHash = async (length) => {
610
+ var result = '';
611
+ var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
612
+ var charactersLength = characters.length;
613
+ for (var i = 0; i < length; i++) {
614
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
615
+ }
616
+ return result;
617
+ };
618
+
619
+ /**
620
+ * Referenced from and modified:
621
+ * @see https://github.com/wppconnect-team/wa-js/commit/290ebfefe6021b3d17f7fdfdda5545bb0473b26f
622
+ */
623
+ window.WWebJS.generateWaveform = async (audioFile) => {
624
+ try {
625
+ const audioData = await audioFile.arrayBuffer();
626
+ const audioContext = new AudioContext();
627
+ const audioBuffer = await audioContext.decodeAudioData(audioData);
628
+
629
+ const rawData = audioBuffer.getChannelData(0);
630
+ const samples = 64;
631
+ const blockSize = Math.floor(rawData.length / samples);
632
+ const filteredData = [];
633
+ for (let i = 0; i < samples; i++) {
634
+ const blockStart = blockSize * i;
635
+ let sum = 0;
636
+ for (let j = 0; j < blockSize; j++) {
637
+ sum = sum + Math.abs(rawData[blockStart + j]);
638
+ }
639
+ filteredData.push(sum / blockSize);
640
+ }
641
+
642
+ const multiplier = Math.pow(Math.max(...filteredData), -1);
643
+ const normalizedData = filteredData.map((n) => n * multiplier);
644
+
645
+ const waveform = new Uint8Array(
646
+ normalizedData.map((n) => Math.floor(100 * n))
647
+ );
648
+
649
+ return waveform;
650
+ } catch (e) {
651
+ return undefined;
652
+ }
653
+ };
654
+
655
+ window.WWebJS.sendClearChat = async (chatId) => {
656
+ let chat = window.Store.Chat.get(chatId);
657
+ if (chat !== undefined) {
658
+ await window.Store.SendClear.sendClear(chat, false);
659
+ return true;
660
+ }
661
+ return false;
662
+ };
663
+
664
+ window.WWebJS.sendDeleteChat = async (chatId) => {
665
+ let chat = window.Store.Chat.get(chatId);
666
+ if (chat !== undefined) {
667
+ await window.Store.SendDelete.sendDelete(chat);
668
+ return true;
669
+ }
670
+ return false;
671
+ };
672
+
673
+ window.WWebJS.sendChatstate = async (state, chatId) => {
674
+ chatId = window.Store.WidFactory.createWid(chatId);
675
+
676
+ switch (state) {
677
+ case 'typing':
678
+ await window.Store.ChatState.sendChatStateComposing(chatId);
679
+ break;
680
+ case 'recording':
681
+ await window.Store.ChatState.sendChatStateRecording(chatId);
682
+ break;
683
+ case 'stop':
684
+ await window.Store.ChatState.sendChatStatePaused(chatId);
685
+ break;
686
+ default:
687
+ throw 'Invalid chatstate';
688
+ }
689
+
690
+ return true;
691
+ };
692
+
693
+ window.WWebJS.getLabelModel = label => {
694
+ let res = label.serialize();
695
+ res.hexColor = label.hexColor;
696
+
697
+ return res;
698
+ };
699
+
700
+ window.WWebJS.getLabels = () => {
701
+ const labels = window.Store.Label.getModelsArray();
702
+ return labels.map(label => window.WWebJS.getLabelModel(label));
703
+ };
704
+
705
+ window.WWebJS.getLabel = (labelId) => {
706
+ const label = window.Store.Label.get(labelId);
707
+ return window.WWebJS.getLabelModel(label);
708
+ };
709
+
710
+ window.WWebJS.getChatLabels = async (chatId) => {
711
+ const chat = await window.WWebJS.getChat(chatId);
712
+ return (chat.labels || []).map(id => window.WWebJS.getLabel(id));
713
+ };
714
+
715
+ window.WWebJS.getOrderDetail = async (orderId, token, chatId) => {
716
+ const chatWid = window.Store.WidFactory.createWid(chatId);
717
+ return window.Store.QueryOrder.queryOrder(chatWid, orderId, 80, 80, token);
718
+ };
719
+
720
+ window.WWebJS.getProductMetadata = async (productId) => {
721
+ let sellerId = window.Store.Conn.wid;
722
+ let product = await window.Store.QueryProduct.queryProduct(sellerId, productId);
723
+ if (product && product.data) {
724
+ return product.data;
725
+ }
726
+
727
+ return undefined;
728
+ };
729
+
730
+ window.WWebJS.rejectCall = async (peerJid, id) => {
731
+ peerJid = peerJid.split('@')[0] + '@s.whatsapp.net';
732
+ let userId = window.Store.User.getMaybeMeUser().user + '@s.whatsapp.net';
733
+ const stanza = window.Store.SocketWap.wap('call', {
734
+ id: window.Store.SocketWap.generateId(),
735
+ from: window.Store.SocketWap.USER_JID(userId),
736
+ to: window.Store.SocketWap.USER_JID(peerJid),
737
+ }, [
738
+ window.Store.SocketWap.wap('reject', {
739
+ 'call-id': id,
740
+ 'call-creator': window.Store.SocketWap.USER_JID(peerJid),
741
+ count: '0',
742
+ })
743
+ ]);
744
+ await window.Store.Socket.deprecatedCastStanza(stanza);
745
+ };
746
+
747
+ window.WWebJS.cropAndResizeImage = async (media, options = {}) => {
748
+ if (!media.mimetype.includes('image'))
749
+ throw new Error('Media is not an image');
750
+
751
+ if (options.mimetype && !options.mimetype.includes('image'))
752
+ delete options.mimetype;
753
+
754
+ options = Object.assign({ size: 640, mimetype: media.mimetype, quality: .75, asDataUrl: false }, options);
755
+
756
+ const img = await new Promise ((resolve, reject) => {
757
+ const img = new Image();
758
+ img.onload = () => resolve(img);
759
+ img.onerror = reject;
760
+ img.src = `data:${media.mimetype};base64,${media.data}`;
761
+ });
762
+
763
+ const sl = Math.min(img.width, img.height);
764
+ const sx = Math.floor((img.width - sl) / 2);
765
+ const sy = Math.floor((img.height - sl) / 2);
766
+
767
+ const canvas = document.createElement('canvas');
768
+ canvas.width = options.size;
769
+ canvas.height = options.size;
770
+
771
+ const ctx = canvas.getContext('2d');
772
+ ctx.drawImage(img, sx, sy, sl, sl, 0, 0, options.size, options.size);
773
+
774
+ const dataUrl = canvas.toDataURL(options.mimetype, options.quality);
775
+
776
+ if (options.asDataUrl)
777
+ return dataUrl;
778
+
779
+ return Object.assign(media, {
780
+ mimetype: options.mimeType,
781
+ data: dataUrl.replace(`data:${options.mimeType};base64,`, '')
782
+ });
783
+ };
784
+
785
+ window.WWebJS.setPicture = async (chatid, media) => {
786
+ const thumbnail = await window.WWebJS.cropAndResizeImage(media, { asDataUrl: true, mimetype: 'image/jpeg', size: 96 });
787
+ const profilePic = await window.WWebJS.cropAndResizeImage(media, { asDataUrl: true, mimetype: 'image/jpeg', size: 640 });
788
+
789
+ const chatWid = window.Store.WidFactory.createWid(chatid);
790
+ try {
791
+ const collection = window.Store.ProfilePicThumb.get(chatid);
792
+ if (!collection.canSet()) return;
793
+
794
+ const res = await window.Store.GroupUtils.sendSetPicture(chatWid, thumbnail, profilePic);
795
+ return res ? res.status === 200 : false;
796
+ } catch (err) {
797
+ if(err.name === 'ServerStatusCodeError') return false;
798
+ throw err;
799
+ }
800
+ };
801
+
802
+ window.WWebJS.deletePicture = async (chatid) => {
803
+ const chatWid = window.Store.WidFactory.createWid(chatid);
804
+ try {
805
+ const collection = window.Store.ProfilePicThumb.get(chatid);
806
+ if (!collection.canDelete()) return;
807
+
808
+ const res = await window.Store.GroupUtils.requestDeletePicture(chatWid);
809
+ return res ? res.status === 200 : false;
810
+ } catch (err) {
811
+ if(err.name === 'ServerStatusCodeError') return false;
812
+ throw err;
813
+ }
814
+ };
815
+
816
+ window.WWebJS.getProfilePicThumbToBase64 = async (chatWid) => {
817
+ const profilePicCollection = await window.Store.ProfilePicThumb.find(chatWid);
818
+
819
+ const _readImageAsBase64 = (imageBlob) => {
820
+ return new Promise((resolve) => {
821
+ const reader = new FileReader();
822
+ reader.onloadend = function () {
823
+ const base64Image = reader.result;
824
+ if (base64Image == null) {
825
+ resolve(undefined);
826
+ } else {
827
+ const base64Data = base64Image.toString().split(',')[1];
828
+ resolve(base64Data);
829
+ }
830
+ };
831
+ reader.readAsDataURL(imageBlob);
832
+ });
833
+ };
834
+
835
+ if (profilePicCollection?.img) {
836
+ try {
837
+ const response = await fetch(profilePicCollection.img);
838
+ if (response.ok) {
839
+ const imageBlob = await response.blob();
840
+ if (imageBlob) {
841
+ const base64Image = await _readImageAsBase64(imageBlob);
842
+ return base64Image;
843
+ }
844
+ }
845
+ } catch (error) { /* empty */ }
846
+ }
847
+ return undefined;
848
+ };
849
+
850
+ window.WWebJS.getAddParticipantsRpcResult = async (groupMetadata, groupWid, participantWid) => {
851
+ const participantLidArgs = groupMetadata?.isLidAddressingMode
852
+ ? {
853
+ phoneNumber: participantWid,
854
+ lid: window.Store.LidUtils.getCurrentLid(participantWid)
855
+ }
856
+ : { phoneNumber: participantWid };
857
+
858
+ const iqTo = window.Store.WidToJid.widToGroupJid(groupWid);
859
+
860
+ const participantArgs =
861
+ participantLidArgs.lid
862
+ ? [{
863
+ participantJid: window.Store.WidToJid.widToUserJid(participantLidArgs.lid),
864
+ phoneNumberMixinArgs: {
865
+ anyPhoneNumber: window.Store.WidToJid.widToUserJid(participantLidArgs.phoneNumber)
866
+ }
867
+ }]
868
+ : [{
869
+ participantJid: window.Store.WidToJid.widToUserJid(participantLidArgs.phoneNumber)
870
+ }];
871
+
872
+ let rpcResult, resultArgs;
873
+ const isOldImpl = window.compareWwebVersions(window.Debug.VERSION, '<=', '2.2335.9');
874
+ const data = {
875
+ name: undefined,
876
+ code: undefined,
877
+ inviteV4Code: undefined,
878
+ inviteV4CodeExp: undefined
879
+ };
880
+
881
+ try {
882
+ rpcResult = await window.Store.GroupParticipants.sendAddParticipantsRPC({ participantArgs, iqTo });
883
+ resultArgs = isOldImpl
884
+ ? rpcResult.value.addParticipant[0].addParticipantsParticipantMixins
885
+ : rpcResult.value.addParticipant[0]
886
+ .addParticipantsParticipantAddedOrNonRegisteredWaUserParticipantErrorLidResponseMixinGroup
887
+ .value
888
+ .addParticipantsParticipantMixins;
889
+ } catch (err) {
890
+ data.code = 400;
891
+ return data;
892
+ }
893
+
894
+ if (rpcResult.name === 'AddParticipantsResponseSuccess') {
895
+ const code = resultArgs?.value.error ?? '200';
896
+ data.name = resultArgs?.name;
897
+ data.code = +code;
898
+ data.inviteV4Code = resultArgs?.value.addRequestCode;
899
+ data.inviteV4CodeExp = resultArgs?.value.addRequestExpiration?.toString();
900
+ }
901
+
902
+ else if (rpcResult.name === 'AddParticipantsResponseClientError') {
903
+ const { code: code } = rpcResult.value.errorAddParticipantsClientErrors.value;
904
+ data.code = +code;
905
+ }
906
+
907
+ else if (rpcResult.name === 'AddParticipantsResponseServerError') {
908
+ const { code: code } = rpcResult.value.errorServerErrors.value;
909
+ data.code = +code;
910
+ }
911
+
912
+ return data;
913
+ };
914
+
915
+ window.WWebJS.membershipRequestAction = async (groupId, action, requesterIds, sleep) => {
916
+ const groupWid = window.Store.WidFactory.createWid(groupId);
917
+ const group = await window.Store.Chat.find(groupWid);
918
+ const toApprove = action === 'Approve';
919
+ let membershipRequests;
920
+ let response;
921
+ let result = [];
922
+
923
+ await window.Store.GroupQueryAndUpdate(groupWid);
924
+
925
+ if (!requesterIds?.length) {
926
+ membershipRequests = group.groupMetadata.membershipApprovalRequests._models.map(({ id }) => id);
927
+ } else {
928
+ !Array.isArray(requesterIds) && (requesterIds = [requesterIds]);
929
+ membershipRequests = requesterIds.map(r => window.Store.WidFactory.createWid(r));
930
+ }
931
+
932
+ if (!membershipRequests.length) return [];
933
+
934
+ const participantArgs = membershipRequests.map(m => ({
935
+ participantArgs: [
936
+ {
937
+ participantJid: window.Store.WidToJid.widToUserJid(m)
938
+ }
939
+ ]
940
+ }));
941
+
942
+ const groupJid = window.Store.WidToJid.widToGroupJid(groupWid);
943
+
944
+ const _getSleepTime = (sleep) => {
945
+ if (!Array.isArray(sleep) || (sleep.length === 2 && sleep[0] === sleep[1])) {
946
+ return sleep;
947
+ }
948
+ if (sleep.length === 1) {
949
+ return sleep[0];
950
+ }
951
+ sleep[1] - sleep[0] < 100 && (sleep[0] = sleep[1]) && (sleep[1] += 100);
952
+ return Math.floor(Math.random() * (sleep[1] - sleep[0] + 1)) + sleep[0];
953
+ };
954
+
955
+ const membReqResCodes = {
956
+ default: `An unknown error occupied while ${toApprove ? 'approving' : 'rejecting'} the participant membership request`,
957
+ 400: 'ParticipantNotFoundError',
958
+ 401: 'ParticipantNotAuthorizedError',
959
+ 403: 'ParticipantForbiddenError',
960
+ 404: 'ParticipantRequestNotFoundError',
961
+ 408: 'ParticipantTemporarilyBlockedError',
962
+ 409: 'ParticipantConflictError',
963
+ 412: 'ParticipantParentLinkedGroupsResourceConstraintError',
964
+ 500: 'ParticipantResourceConstraintError'
965
+ };
966
+
967
+ try {
968
+ for (const participant of participantArgs) {
969
+ response = await window.Store.MembershipRequestUtils.sendMembershipRequestsActionRPC({
970
+ iqTo: groupJid,
971
+ [toApprove ? 'approveArgs' : 'rejectArgs']: participant
972
+ });
973
+
974
+ if (response.name === 'MembershipRequestsActionResponseSuccess') {
975
+ const value = toApprove
976
+ ? response.value.membershipRequestsActionApprove
977
+ : response.value.membershipRequestsActionReject;
978
+ if (value?.participant) {
979
+ const [_] = value.participant.map(p => {
980
+ const error = toApprove
981
+ ? value.participant[0].membershipRequestsActionAcceptParticipantMixins?.value.error
982
+ : value.participant[0].membershipRequestsActionRejectParticipantMixins?.value.error;
983
+ return {
984
+ requesterId: window.Store.WidFactory.createWid(p.jid)._serialized,
985
+ ...(error
986
+ ? { error: +error, message: membReqResCodes[error] || membReqResCodes.default }
987
+ : { message: `${toApprove ? 'Approved' : 'Rejected'} successfully` })
988
+ };
989
+ });
990
+ _ && result.push(_);
991
+ }
992
+ } else {
993
+ result.push({
994
+ requesterId: window.Store.JidToWid.userJidToUserWid(participant.participantArgs[0].participantJid)._serialized,
995
+ message: 'ServerStatusCodeError'
996
+ });
997
+ }
998
+
999
+ sleep &&
1000
+ participantArgs.length > 1 &&
1001
+ participantArgs.indexOf(participant) !== participantArgs.length - 1 &&
1002
+ (await new Promise((resolve) => setTimeout(resolve, _getSleepTime(sleep))));
1003
+ }
1004
+ return result;
1005
+ } catch (err) {
1006
+ return [];
1007
+ }
1008
+ };
1009
+
1010
+ window.WWebJS.pinUnpinMsgAction = async (msgId, action, duration) => {
1011
+ const message = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
1012
+ if (!message) return false;
1013
+ const response = await window.Store.pinUnpinMsg(message, action, duration);
1014
+ return response.messageSendResult === 'OK';
1015
+ };
1016
+
1017
+ };