@genuxofficial/baileys 3.0.0 → 4.0.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 (88) hide show
  1. package/WAProto/WAProto.proto +24 -206
  2. package/WAProto/index.d.ts +219 -2233
  3. package/WAProto/index.js +525 -6773
  4. package/WAProto/shizo.x +1 -0
  5. package/lib/Defaults/baileys-version.json +1 -1
  6. package/lib/Defaults/index.d.ts +231 -0
  7. package/lib/Defaults/index.js +17 -1
  8. package/lib/Defaults/phonenumber-mcc.json +223 -0
  9. package/lib/Socket/Client/index.d.ts +3 -2
  10. package/lib/Socket/Client/index.js +3 -2
  11. package/lib/Socket/Client/mobile-socket-client.d.ts +13 -0
  12. package/lib/Socket/Client/mobile-socket-client.js +65 -0
  13. package/lib/Socket/Client/{websocket.d.ts → web-socket-client.d.ts} +1 -1
  14. package/lib/Socket/Client/{websocket.js → web-socket-client.js} +2 -2
  15. package/lib/Socket/business.d.ts +7 -9
  16. package/lib/Socket/chats.d.ts +5 -8
  17. package/lib/Socket/chats.js +8 -38
  18. package/lib/Socket/groups.d.ts +5 -7
  19. package/lib/Socket/groups.js +2 -14
  20. package/lib/Socket/index.d.ts +9 -9
  21. package/lib/Socket/index.js +2 -2
  22. package/lib/Socket/messages-recv.d.ts +8 -10
  23. package/lib/Socket/messages-recv.js +11 -18
  24. package/lib/Socket/messages-send.d.ts +7 -14
  25. package/lib/Socket/messages-send.js +13 -36
  26. package/lib/Socket/newsletter.d.ts +7 -9
  27. package/lib/Socket/newsletter.js +3 -11
  28. package/lib/Socket/registration.d.ts +271 -0
  29. package/lib/Socket/registration.js +166 -0
  30. package/lib/Socket/socket.d.ts +4 -5
  31. package/lib/Socket/socket.js +18 -15
  32. package/lib/Socket/usync.d.ts +4 -4
  33. package/lib/Store/index.d.ts +2 -1
  34. package/lib/Store/index.js +3 -1
  35. package/lib/Store/make-cache-manager-store.d.ts +14 -0
  36. package/lib/Store/make-cache-manager-store.js +83 -0
  37. package/lib/Store/make-in-memory-store.js +10 -8
  38. package/lib/Store/make-ordered-dictionary.js +2 -2
  39. package/lib/Types/Auth.d.ts +6 -0
  40. package/lib/Types/Chat.d.ts +0 -4
  41. package/lib/Types/Contact.d.ts +1 -1
  42. package/lib/Types/GroupMetadata.d.ts +0 -6
  43. package/lib/Types/Message.d.ts +5 -29
  44. package/lib/Types/Message.js +2 -0
  45. package/lib/Types/Socket.d.ts +4 -7
  46. package/lib/Utils/auth-utils.d.ts +1 -1
  47. package/lib/Utils/auth-utils.js +9 -2
  48. package/lib/Utils/business.js +3 -15
  49. package/lib/Utils/chat-utils.d.ts +4 -4
  50. package/lib/Utils/chat-utils.js +2 -1
  51. package/lib/Utils/decode-wa-message.d.ts +2 -4
  52. package/lib/Utils/decode-wa-message.js +24 -145
  53. package/lib/Utils/event-buffer.js +6 -4
  54. package/lib/Utils/generics.d.ts +4 -7
  55. package/lib/Utils/generics.js +17 -9
  56. package/lib/Utils/lt-hash.d.ts +3 -3
  57. package/lib/Utils/lt-hash.js +45 -11
  58. package/lib/Utils/messages-media.d.ts +4 -4
  59. package/lib/Utils/messages-media.js +57 -69
  60. package/lib/Utils/messages.js +39 -33
  61. package/lib/Utils/noise-handler.d.ts +2 -1
  62. package/lib/Utils/noise-handler.js +10 -5
  63. package/lib/Utils/use-multi-file-auth-state.js +11 -48
  64. package/lib/Utils/validate-connection.d.ts +1 -0
  65. package/lib/Utils/validate-connection.js +44 -10
  66. package/lib/WABinary/constants.js +5 -5
  67. package/lib/WABinary/encode.js +10 -23
  68. package/lib/WABinary/generic-utils.d.ts +5 -3
  69. package/lib/WABinary/generic-utils.js +19 -34
  70. package/lib/WABinary/jid-utils.d.ts +2 -11
  71. package/lib/WABinary/jid-utils.js +2 -27
  72. package/lib/WAM/BinaryInfo.d.ts +2 -2
  73. package/lib/WAM/constants.d.ts +2 -3
  74. package/lib/WAM/encode.js +2 -2
  75. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +12 -21
  76. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +3 -3
  77. package/lib/WAUSync/USyncQuery.d.ts +0 -2
  78. package/lib/WAUSync/USyncQuery.js +0 -10
  79. package/lib/WAUSync/USyncUser.d.ts +0 -2
  80. package/lib/WAUSync/USyncUser.js +0 -4
  81. package/package.json +5 -6
  82. package/LICENSE +0 -21
  83. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +0 -25
  84. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +0 -53
  85. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -8
  86. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +0 -24
  87. /package/lib/Socket/Client/{types.d.ts → abstract-socket-client.d.ts} +0 -0
  88. /package/lib/Socket/Client/{types.js → abstract-socket-client.js} +0 -0
@@ -282,7 +282,7 @@ async function generateThumbnail(file, mediaType, options) {
282
282
  }
283
283
  }
284
284
  else if (mediaType === 'video') {
285
- const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.jpg');
285
+ const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
286
286
  try {
287
287
  await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
288
288
  const buff = await fs_1.promises.readFile(imgFilename);
@@ -307,34 +307,25 @@ exports.getHttpStream = getHttpStream;
307
307
  const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
308
308
  const { stream, type } = await (0, exports.getStream)(media, opts);
309
309
  logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
310
- const encFilePath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)() + '-enc');
311
- const encFileWriteStream = (0, fs_1.createWriteStream)(encFilePath);
312
- let originalFilePath;
313
- let didSaveToTmpPath = false;
314
310
  let bodyPath;
311
+ let didSaveToTmpPath = false;
315
312
  try {
316
313
  const buffer = await (0, exports.toBuffer)(stream);
317
- // Write encrypted data
318
- encFileWriteStream.write(buffer);
319
- encFileWriteStream.end();
320
- // Save original file if required
321
- if (saveOriginalFileIfRequired) {
322
- originalFilePath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)() + '-original');
323
- (0, fs_1.writeFileSync)(originalFilePath, buffer);
324
- bodyPath = originalFilePath;
325
- didSaveToTmpPath = true;
326
- }
327
- else if (type === 'file' && typeof media.url === 'string') {
314
+ if (type === 'file') {
328
315
  bodyPath = media.url;
329
316
  }
317
+ else if (saveOriginalFileIfRequired) {
318
+ bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
319
+ (0, fs_1.writeFileSync)(bodyPath, buffer);
320
+ didSaveToTmpPath = true;
321
+ }
330
322
  const fileLength = buffer.length;
331
323
  const fileSha256 = Crypto.createHash('sha256').update(buffer).digest();
332
324
  stream === null || stream === void 0 ? void 0 : stream.destroy();
333
- logger === null || logger === void 0 ? void 0 : logger.debug('prepared stream data successfully');
325
+ logger === null || logger === void 0 ? void 0 : logger.debug('prepare stream data successfully');
334
326
  return {
335
327
  mediaKey: undefined,
336
- encFilePath,
337
- originalFilePath,
328
+ encWriteStream: buffer,
338
329
  fileLength,
339
330
  fileSha256,
340
331
  fileEncSha256: undefined,
@@ -343,17 +334,14 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
343
334
  };
344
335
  }
345
336
  catch (error) {
337
+ // destroy all streams with error
346
338
  stream.destroy();
347
- try {
348
- await fs_1.promises.unlink(encFilePath);
349
- }
350
- catch (_) { }
351
- if (didSaveToTmpPath && bodyPath) {
339
+ if (didSaveToTmpPath) {
352
340
  try {
353
341
  await fs_1.promises.unlink(bodyPath);
354
342
  }
355
343
  catch (err) {
356
- logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to delete tmp bodyPath');
344
+ logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
357
345
  }
358
346
  }
359
347
  throw error;
@@ -361,29 +349,27 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
361
349
  };
362
350
  exports.prepareStream = prepareStream;
363
351
  const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
364
- var _a, _b;
365
352
  const { stream, type } = await (0, exports.getStream)(media, opts);
366
353
  logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
367
354
  const mediaKey = Crypto.randomBytes(32);
368
355
  const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
369
- const encFilePath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)() + '-enc');
370
- const encFileWriteStream = (0, fs_1.createWriteStream)(encFilePath);
371
- let originalFileStream;
372
- let originalFilePath;
373
- if (saveOriginalFileIfRequired) {
374
- originalFilePath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)() + '-original');
375
- originalFileStream = (0, fs_1.createWriteStream)(originalFilePath);
356
+ const encWriteStream = new stream_1.Readable({ read: () => { } });
357
+ let bodyPath;
358
+ let writeStream;
359
+ let didSaveToTmpPath = false;
360
+ if (type === 'file') {
361
+ bodyPath = media.url;
362
+ }
363
+ else if (saveOriginalFileIfRequired) {
364
+ bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
365
+ writeStream = (0, fs_1.createWriteStream)(bodyPath);
366
+ didSaveToTmpPath = true;
376
367
  }
377
368
  let fileLength = 0;
378
369
  const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
379
370
  let hmac = Crypto.createHmac('sha256', macKey).update(iv);
380
371
  let sha256Plain = Crypto.createHash('sha256');
381
372
  let sha256Enc = Crypto.createHash('sha256');
382
- const onChunk = (buff) => {
383
- sha256Enc.update(buff);
384
- hmac.update(buff);
385
- encFileWriteStream.write(buff);
386
- };
387
373
  try {
388
374
  for await (const data of stream) {
389
375
  fileLength += data.length;
@@ -394,12 +380,12 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
394
380
  data: { media, type }
395
381
  });
396
382
  }
397
- if (originalFileStream) {
398
- if (!originalFileStream.write(data)) {
399
- await (0, events_1.once)(originalFileStream, 'drain');
383
+ sha256Plain = sha256Plain.update(data);
384
+ if (writeStream) {
385
+ if (!writeStream.write(data)) {
386
+ await (0, events_1.once)(writeStream, 'drain');
400
387
  }
401
388
  }
402
- sha256Plain.update(data);
403
389
  onChunk(aes.update(data));
404
390
  }
405
391
  onChunk(aes.final());
@@ -407,43 +393,46 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
407
393
  sha256Enc = sha256Enc.update(mac);
408
394
  const fileSha256 = sha256Plain.digest();
409
395
  const fileEncSha256 = sha256Enc.digest();
410
- //encWriteStream.push(mac)
411
- //encWriteStream.push(null)
412
- encFileWriteStream.write(mac);
413
- encFileWriteStream.end();
414
- (_a = originalFileStream === null || originalFileStream === void 0 ? void 0 : originalFileStream.end) === null || _a === void 0 ? void 0 : _a.call(originalFileStream);
396
+ encWriteStream.push(mac);
397
+ encWriteStream.push(null);
398
+ writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
415
399
  stream.destroy();
416
400
  logger === null || logger === void 0 ? void 0 : logger.debug('encrypted data successfully');
417
401
  return {
418
402
  mediaKey,
419
- originalFilePath,
420
- encFilePath,
403
+ encWriteStream,
404
+ bodyPath,
421
405
  mac,
422
406
  fileEncSha256,
423
407
  fileSha256,
424
- fileLength
408
+ fileLength,
409
+ didSaveToTmpPath
425
410
  };
426
411
  }
427
412
  catch (error) {
428
413
  // destroy all streams with error
429
- encFileWriteStream.destroy();
430
- (_b = originalFileStream === null || originalFileStream === void 0 ? void 0 : originalFileStream.destroy) === null || _b === void 0 ? void 0 : _b.call(originalFileStream);
414
+ encWriteStream.destroy();
415
+ writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
431
416
  aes.destroy();
432
417
  hmac.destroy();
433
418
  sha256Plain.destroy();
434
419
  sha256Enc.destroy();
435
420
  stream.destroy();
436
- try {
437
- await fs_1.promises.unlink(encFilePath);
438
- if (originalFilePath) {
439
- await fs_1.promises.unlink(originalFilePath);
421
+ if (didSaveToTmpPath) {
422
+ try {
423
+ await fs_1.promises.unlink(bodyPath);
424
+ }
425
+ catch (err) {
426
+ logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
440
427
  }
441
- }
442
- catch (err) {
443
- logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed deleting tmp files');
444
428
  }
445
429
  throw error;
446
430
  }
431
+ function onChunk(buff) {
432
+ sha256Enc = sha256Enc.update(buff);
433
+ hmac = hmac.update(buff);
434
+ encWriteStream.push(buff);
435
+ }
447
436
  };
448
437
  exports.encryptedStream = encryptedStream;
449
438
  const DEF_HOST = 'mmg.whatsapp.net';
@@ -564,19 +553,19 @@ function extensionForMediaMessage(message) {
564
553
  }
565
554
  exports.extensionForMediaMessage = extensionForMediaMessage;
566
555
  const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
567
- return async (filePath, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
556
+ return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
568
557
  var _a, _b;
569
558
  // send a query JSON to obtain the url & auth token to upload our media
570
559
  let uploadInfo = await refreshMediaConn(false);
571
560
  let urls;
572
561
  const hosts = [...customUploadHosts, ...uploadInfo.hosts];
573
- /*const chunks: Buffer[] | Buffer = []
562
+ const chunks = [];
574
563
  if (!Buffer.isBuffer(stream)) {
575
564
  for await (const chunk of stream) {
576
- chunks.push(chunk)
565
+ chunks.push(chunk);
577
566
  }
578
- }*/
579
- //const reqBody = Buffer.isBuffer(stream) ? stream : Buffer.concat(chunks)
567
+ }
568
+ const reqBody = Buffer.isBuffer(stream) ? stream : Buffer.concat(chunks);
580
569
  fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
581
570
  let media = Defaults_1.MEDIA_PATH_MAP[mediaType];
582
571
  if (newsletter) {
@@ -588,12 +577,11 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
588
577
  const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
589
578
  let result;
590
579
  try {
591
- //if(maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
592
- // throw new Boom(`Body too large for "${hostname}"`, { statusCode: 413 })
593
- //}
594
- const body = await axios_1.default.post(url, (0, fs_1.createReadStream)(filePath), {
580
+ if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
581
+ throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
582
+ }
583
+ const body = await axios_1.default.post(url, reqBody, {
595
584
  ...options,
596
- maxRedirects: 0,
597
585
  headers: {
598
586
  ...options.headers || {},
599
587
  'Content-Type': 'application/octet-stream',
@@ -81,17 +81,20 @@ const prepareWAMessageMedia = async (message, options) => {
81
81
  media: message[mediaType]
82
82
  };
83
83
  delete uploadData[mediaType];
84
+ // check if cacheable + generate cache key
84
85
  const cacheableKey = typeof uploadData.media === 'object' &&
85
- 'url' in uploadData.media &&
86
+ ('url' in uploadData.media) &&
86
87
  !!uploadData.media.url &&
87
- !!options.mediaCache &&
88
- (mediaType + ':' + uploadData.media.url.toString());
88
+ !!options.mediaCache && (
89
+ // generate the key
90
+ mediaType + ':' + uploadData.media.url.toString());
89
91
  if (mediaType === 'document' && !uploadData.fileName) {
90
92
  uploadData.fileName = 'file';
91
93
  }
92
94
  if (!uploadData.mimetype) {
93
95
  uploadData.mimetype = MIMETYPE_MAP[mediaType];
94
96
  }
97
+ // check for cache hit
95
98
  if (cacheableKey) {
96
99
  const mediaBuff = options.mediaCache.get(cacheableKey);
97
100
  if (mediaBuff) {
@@ -103,26 +106,28 @@ const prepareWAMessageMedia = async (message, options) => {
103
106
  }
104
107
  }
105
108
  const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
106
- const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined';
109
+ const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
110
+ (typeof uploadData['jpegThumbnail'] === 'undefined');
107
111
  const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
108
112
  const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
109
113
  const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
110
- const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
114
+ const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
111
115
  logger,
112
116
  saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
113
117
  opts: options.options
114
118
  });
119
+ // url safe Base64 encode the SHA256 hash of the body
115
120
  const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256).toString('base64');
116
121
  const [{ mediaUrl, directPath, handle }] = await Promise.all([
117
122
  (async () => {
118
- const result = await options.upload(encFilePath, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
123
+ const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
119
124
  logger === null || logger === void 0 ? void 0 : logger.debug({ mediaType, cacheableKey }, 'uploaded media');
120
125
  return result;
121
126
  })(),
122
127
  (async () => {
123
128
  try {
124
129
  if (requiresThumbnailComputation) {
125
- const { thumbnail, originalImageDimensions } = await (0, messages_media_1.generateThumbnail)(originalFilePath, mediaType, options);
130
+ const { thumbnail, originalImageDimensions } = await (0, messages_media_1.generateThumbnail)(bodyPath, mediaType, options);
126
131
  uploadData.jpegThumbnail = thumbnail;
127
132
  if (!uploadData.width && originalImageDimensions) {
128
133
  uploadData.width = originalImageDimensions.width;
@@ -132,11 +137,11 @@ const prepareWAMessageMedia = async (message, options) => {
132
137
  logger === null || logger === void 0 ? void 0 : logger.debug('generated thumbnail');
133
138
  }
134
139
  if (requiresDurationComputation) {
135
- uploadData.seconds = await (0, messages_media_1.getAudioDuration)(originalFilePath);
140
+ uploadData.seconds = await (0, messages_media_1.getAudioDuration)(bodyPath);
136
141
  logger === null || logger === void 0 ? void 0 : logger.debug('computed audio duration');
137
142
  }
138
143
  if (requiresWaveformProcessing) {
139
- uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(originalFilePath, logger);
144
+ uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(bodyPath, logger);
140
145
  logger === null || logger === void 0 ? void 0 : logger.debug('processed waveform');
141
146
  }
142
147
  if (requiresAudioBackground) {
@@ -150,15 +155,19 @@ const prepareWAMessageMedia = async (message, options) => {
150
155
  })(),
151
156
  ])
152
157
  .finally(async () => {
153
- try {
154
- await fs_1.promises.unlink(encFilePath);
155
- if (originalFilePath) {
156
- await fs_1.promises.unlink(originalFilePath);
157
- }
158
- logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp files');
158
+ if (!Buffer.isBuffer(encWriteStream)) {
159
+ encWriteStream.destroy();
159
160
  }
160
- catch (error) {
161
- logger === null || logger === void 0 ? void 0 : logger.warn('failed to remove tmp file');
161
+ // remove tmp files
162
+ if (didSaveToTmpPath && bodyPath) {
163
+ try {
164
+ await fs_1.promises.access(bodyPath);
165
+ await fs_1.promises.unlink(bodyPath);
166
+ logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp file');
167
+ }
168
+ catch (error) {
169
+ logger === null || logger === void 0 ? void 0 : logger.warn('failed to remove tmp file');
170
+ }
162
171
  }
163
172
  });
164
173
  const obj = Types_1.WAProto.Message.fromObject({
@@ -265,10 +274,6 @@ const generateWAMessageContent = async (message, options) => {
265
274
  extContent.font = options.font;
266
275
  }
267
276
  m.extendedTextMessage = extContent;
268
- //WhatsApp always sends secretMessage along with the text message
269
- m.messageContextInfo = {
270
- messageSecret: (0, crypto_1.randomBytes)(32)
271
- };
272
277
  }
273
278
  else if ('contacts' in message) {
274
279
  const contactLen = message.contacts.contacts.length;
@@ -728,7 +733,7 @@ const generateWAMessageFromContent = (jid, message, options) => {
728
733
  key: {
729
734
  remoteJid: jid,
730
735
  fromMe: true,
731
- id: (options === null || options === void 0 ? void 0 : options.messageId) || (0, generics_1.generateMessageIDV2)(),
736
+ id: (options === null || options === void 0 ? void 0 : options.messageId) || (0, generics_1.generateMessageID)(),
732
737
  },
733
738
  message: message,
734
739
  messageTimestamp: timestamp,
@@ -792,10 +797,7 @@ const normalizeMessageContent = (content) => {
792
797
  || (message === null || message === void 0 ? void 0 : message.pollCreationMessageV4)
793
798
  || (message === null || message === void 0 ? void 0 : message.pollCreationMessageV5)
794
799
  || (message === null || message === void 0 ? void 0 : message.statusAddYours)
795
- || (message === null || message === void 0 ? void 0 : message.groupStatusMessage)
796
- || (message === null || message === void 0 ? void 0 : message.limitSharingMessage)
797
- || (message === null || message === void 0 ? void 0 : message.botTaskMessage)
798
- || (message === null || message === void 0 ? void 0 : message.questionMessage));
800
+ || (message === null || message === void 0 ? void 0 : message.groupStatusMessage));
799
801
  }
800
802
  };
801
803
  exports.normalizeMessageContent = normalizeMessageContent;
@@ -951,13 +953,17 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
951
953
  const result = await downloadMsg()
952
954
  .catch(async (error) => {
953
955
  var _a;
954
- if (ctx && axios_1.default.isAxiosError(error) && // check if the message requires a reupload
955
- REUPLOAD_REQUIRED_STATUS.includes((_a = error.response) === null || _a === void 0 ? void 0 : _a.status)) {
956
- ctx.logger.info({ key: message.key }, 'sending reupload media request...');
957
- // request reupload
958
- message = await ctx.reuploadRequest(message);
959
- const result = await downloadMsg();
960
- return result;
956
+ if (ctx) {
957
+ if (axios_1.default.isAxiosError(error)) {
958
+ // check if the message requires a reupload
959
+ if (REUPLOAD_REQUIRED_STATUS.includes((_a = error.response) === null || _a === void 0 ? void 0 : _a.status)) {
960
+ ctx.logger.info({ key: message.key }, 'sending reupload media request...');
961
+ // request reupload
962
+ message = await ctx.reuploadRequest(message);
963
+ const result = await downloadMsg();
964
+ return result;
965
+ }
966
+ }
961
967
  }
962
968
  throw error;
963
969
  });
@@ -4,9 +4,10 @@ import { ILogger } from './logger';
4
4
  import { proto } from '../../WAProto';
5
5
  import { KeyPair } from '../Types';
6
6
  import { BinaryNode } from '../WABinary';
7
- export declare const makeNoiseHandler: ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, logger, routingInfo }: {
7
+ export declare const makeNoiseHandler: ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, mobile, logger, routingInfo }: {
8
8
  keyPair: KeyPair;
9
9
  NOISE_HEADER: Uint8Array;
10
+ mobile: boolean;
10
11
  logger: ILogger;
11
12
  routingInfo?: Buffer | undefined;
12
13
  }) => {
@@ -11,7 +11,7 @@ const generateIV = (counter) => {
11
11
  new DataView(iv).setUint32(8, counter);
12
12
  return new Uint8Array(iv);
13
13
  };
14
- const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, logger, routingInfo }) => {
14
+ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, mobile, logger, routingInfo }) => {
15
15
  logger = logger.child({ class: 'ns' });
16
16
  const authenticate = (data) => {
17
17
  if (!isFinished) {
@@ -83,10 +83,15 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
83
83
  const decStaticContent = decrypt(serverHello.static);
84
84
  await mixIntoKey(crypto_1.Curve.sharedKey(privateKey, decStaticContent));
85
85
  const certDecoded = decrypt(serverHello.payload);
86
- const { intermediate: certIntermediate } = WAProto_1.proto.CertChain.decode(certDecoded);
87
- const { issuerSerial } = WAProto_1.proto.CertChain.NoiseCertificate.Details.decode(certIntermediate.details);
88
- if (issuerSerial !== Defaults_1.WA_CERT_DETAILS.SERIAL) {
89
- throw new boom_1.Boom('certification match failed', { statusCode: 400 });
86
+ if (mobile) {
87
+ WAProto_1.proto.CertChain.NoiseCertificate.decode(certDecoded);
88
+ }
89
+ else {
90
+ const { intermediate: certIntermediate } = WAProto_1.proto.CertChain.decode(certDecoded);
91
+ const { issuerSerial } = WAProto_1.proto.CertChain.NoiseCertificate.Details.decode(certIntermediate.details);
92
+ if (issuerSerial !== Defaults_1.WA_CERT_DETAILS.SERIAL) {
93
+ throw new boom_1.Boom('certification match failed', { statusCode: 400 });
94
+ }
90
95
  }
91
96
  const keyEnc = encrypt(noiseKey.public);
92
97
  await mixIntoKey(crypto_1.Curve.sharedKey(noiseKey.private, serverHello.ephemeral));
@@ -1,26 +1,16 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.useMultiFileAuthState = void 0;
4
- const async_mutex_1 = require("async-mutex");
5
7
  const promises_1 = require("fs/promises");
6
8
  const path_1 = require("path");
7
9
  const WAProto_1 = require("../../WAProto");
8
10
  const auth_utils_1 = require("./auth-utils");
9
11
  const generics_1 = require("./generics");
10
- // We need to lock files due to the fact that we are using async functions to read and write files
11
- // https://github.com/WhiskeySockets/Baileys/issues/794
12
- // https://github.com/nodejs/node/issues/26338
13
- // Use a Map to store mutexes for each file path
14
- const fileLocks = new Map();
15
- // Get or create a mutex for a specific file path
16
- const getFileLock = (path) => {
17
- let mutex = fileLocks.get(path);
18
- if (!mutex) {
19
- mutex = new async_mutex_1.Mutex();
20
- fileLocks.set(path, mutex);
21
- }
22
- return mutex;
23
- };
12
+ const async_lock_1 = __importDefault(require("async-lock"));
13
+ const fileLock = new async_lock_1.default({ maxPending: Infinity });
24
14
  /**
25
15
  * stores the full authentication state in a single folder.
26
16
  * Far more efficient than singlefileauthstate
@@ -29,32 +19,15 @@ const getFileLock = (path) => {
29
19
  * Would recommend writing an auth state for use with a proper SQL or No-SQL DB
30
20
  * */
31
21
  const useMultiFileAuthState = async (folder) => {
32
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
- const writeData = async (data, file) => {
22
+ const writeData = (data, file) => {
34
23
  const filePath = (0, path_1.join)(folder, fixFileName(file));
35
- const mutex = getFileLock(filePath);
36
- return mutex.acquire().then(async (release) => {
37
- try {
38
- await (0, promises_1.writeFile)(filePath, JSON.stringify(data, generics_1.BufferJSON.replacer));
39
- }
40
- finally {
41
- release();
42
- }
43
- });
24
+ return fileLock.acquire(filePath, () => (0, promises_1.writeFile)((0, path_1.join)(filePath), JSON.stringify(data, generics_1.BufferJSON.replacer)));
44
25
  };
45
26
  const readData = async (file) => {
46
27
  try {
47
28
  const filePath = (0, path_1.join)(folder, fixFileName(file));
48
- const mutex = getFileLock(filePath);
49
- return await mutex.acquire().then(async (release) => {
50
- try {
51
- const data = await (0, promises_1.readFile)(filePath, { encoding: 'utf-8' });
52
- return JSON.parse(data, generics_1.BufferJSON.reviver);
53
- }
54
- finally {
55
- release();
56
- }
57
- });
29
+ const data = await fileLock.acquire(filePath, () => (0, promises_1.readFile)(filePath, { encoding: 'utf-8' }));
30
+ return JSON.parse(data, generics_1.BufferJSON.reviver);
58
31
  }
59
32
  catch (error) {
60
33
  return null;
@@ -63,17 +36,7 @@ const useMultiFileAuthState = async (folder) => {
63
36
  const removeData = async (file) => {
64
37
  try {
65
38
  const filePath = (0, path_1.join)(folder, fixFileName(file));
66
- const mutex = getFileLock(filePath);
67
- return mutex.acquire().then(async (release) => {
68
- try {
69
- await (0, promises_1.unlink)(filePath);
70
- }
71
- catch (_a) {
72
- }
73
- finally {
74
- release();
75
- }
76
- });
39
+ await fileLock.acquire(filePath, () => (0, promises_1.unlink)(filePath));
77
40
  }
78
41
  catch (_a) {
79
42
  }
@@ -117,7 +80,7 @@ const useMultiFileAuthState = async (folder) => {
117
80
  }
118
81
  }
119
82
  },
120
- saveCreds: async () => {
83
+ saveCreds: () => {
121
84
  return writeData(creds, 'creds.json');
122
85
  }
123
86
  };
@@ -1,6 +1,7 @@
1
1
  import { proto } from '../../WAProto';
2
2
  import type { AuthenticationCreds, SignalCreds, SocketConfig } from '../Types';
3
3
  import { BinaryNode } from '../WABinary';
4
+ export declare const generateMobileNode: (config: SocketConfig) => proto.IClientPayload;
4
5
  export declare const generateLoginNode: (userJid: string, config: SocketConfig) => proto.IClientPayload;
5
6
  export declare const generateRegistrationNode: ({ registrationId, signedPreKey, signedIdentityKey }: SignalCreds, config: SocketConfig) => proto.ClientPayload;
6
7
  export declare const configureSuccessfulPairing: (stanza: BinaryNode, { advSecretKey, signedIdentityKey, signalIdentities }: Pick<AuthenticationCreds, 'advSecretKey' | 'signedIdentityKey' | 'signalIdentities'>) => {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.encodeSignedDeviceIdentity = exports.configureSuccessfulPairing = exports.generateRegistrationNode = exports.generateLoginNode = void 0;
3
+ exports.encodeSignedDeviceIdentity = exports.configureSuccessfulPairing = exports.generateRegistrationNode = exports.generateLoginNode = exports.generateMobileNode = void 0;
4
4
  const boom_1 = require("@hapi/boom");
5
5
  const crypto_1 = require("crypto");
6
6
  const WAProto_1 = require("../../WAProto");
@@ -10,19 +10,30 @@ const crypto_2 = require("./crypto");
10
10
  const generics_1 = require("./generics");
11
11
  const signal_1 = require("./signal");
12
12
  const getUserAgent = (config) => {
13
+ var _a, _b;
14
+ const osVersion = config.mobile ? '15.3.1' : '0.1';
15
+ const version = config.mobile ? [2, 24, 6] : config.version;
16
+ const device = config.mobile ? 'iPhone_7' : 'Desktop';
17
+ const manufacturer = config.mobile ? 'Apple' : '';
18
+ const platform = config.mobile ? WAProto_1.proto.ClientPayload.UserAgent.Platform.IOS : WAProto_1.proto.ClientPayload.UserAgent.Platform.WEB;
19
+ const phoneId = config.mobile ? { phoneId: config.auth.creds.phoneId } : {};
13
20
  return {
14
21
  appVersion: {
15
- primary: config.version[0],
16
- secondary: config.version[1],
17
- tertiary: config.version[2],
22
+ primary: version[0],
23
+ secondary: version[1],
24
+ tertiary: version[2],
18
25
  },
19
- platform: WAProto_1.proto.ClientPayload.UserAgent.Platform.WEB,
26
+ platform,
20
27
  releaseChannel: WAProto_1.proto.ClientPayload.UserAgent.ReleaseChannel.RELEASE,
21
- osVersion: '0.1',
22
- device: 'Desktop',
23
- osBuildNumber: '0.1',
28
+ mcc: ((_a = config.auth.creds.registration) === null || _a === void 0 ? void 0 : _a.phoneNumberMobileCountryCode) || '000',
29
+ mnc: ((_b = config.auth.creds.registration) === null || _b === void 0 ? void 0 : _b.phoneNumberMobileNetworkCode) || '000',
30
+ osVersion: osVersion,
31
+ manufacturer,
32
+ device,
33
+ osBuildNumber: osVersion,
24
34
  localeLanguageIso6391: 'en',
25
- localeCountryIso31661Alpha2: config.countryCode
35
+ localeCountryIso31661Alpha2: config.countryCode,
36
+ ...phoneId
26
37
  };
27
38
  };
28
39
  const PLATFORM_MAP = {
@@ -42,9 +53,32 @@ const getClientPayload = (config) => {
42
53
  connectReason: WAProto_1.proto.ClientPayload.ConnectReason.USER_ACTIVATED,
43
54
  userAgent: getUserAgent(config),
44
55
  };
45
- payload.webInfo = getWebInfo(config);
56
+ if (!config.mobile) {
57
+ payload.webInfo = getWebInfo(config);
58
+ }
46
59
  return payload;
47
60
  };
61
+ const generateMobileNode = (config) => {
62
+ if (!config.auth.creds) {
63
+ throw new boom_1.Boom('No registration data found', { data: config });
64
+ }
65
+ const payload = {
66
+ ...getClientPayload(config),
67
+ sessionId: Math.floor(Math.random() * 999999999 + 1),
68
+ shortConnect: true,
69
+ connectAttemptCount: 0,
70
+ device: 0,
71
+ dnsSource: {
72
+ appCached: false,
73
+ dnsMethod: WAProto_1.proto.ClientPayload.DNSSource.DNSResolutionMethod.SYSTEM,
74
+ },
75
+ passive: false,
76
+ pushName: 'test',
77
+ username: Number(`${config.auth.creds.registration.phoneNumberCountryCode}${config.auth.creds.registration.phoneNumberNationalNumber}`),
78
+ };
79
+ return WAProto_1.proto.ClientPayload.fromObject(payload);
80
+ };
81
+ exports.generateMobileNode = generateMobileNode;
48
82
  const generateLoginNode = (userJid, config) => {
49
83
  const { user, device } = (0, WABinary_1.jidDecode)(userJid);
50
84
  const payload = {
@@ -30,11 +30,11 @@ exports.SINGLE_BYTE_TOKENS = [
30
30
  '', 'xmlstreamstart', 'xmlstreamend', 's.whatsapp.net', 'type', 'participant', 'from', 'receipt', 'id', 'broadcast', 'status', 'message', 'notification', 'notify', 'to', 'jid', 'user', 'class', 'offline', 'g.us', 'result', 'mediatype', 'enc', 'skmsg', 'off_cnt', 'xmlns', 'presence', 'participants', 'ack', 't', 'iq', 'device_hash', 'read', 'value', 'media', 'picture', 'chatstate', 'unavailable', 'text', 'urn:xmpp:whatsapp:push', 'devices', 'verified_name', 'contact', 'composing', 'edge_routing', 'routing_info', 'item', 'image', 'verified_level', 'get', 'fallback_hostname', '2', 'media_conn', '1', 'v', 'handshake', 'fallback_class', 'count', 'config', 'offline_preview', 'download_buckets', 'w:profile:picture', 'set', 'creation', 'location', 'fallback_ip4', 'msg', 'urn:xmpp:ping', 'fallback_ip6', 'call-creator', 'relaylatency', 'success', 'subscribe', 'video', 'business_hours_config', 'platform', 'hostname', 'version', 'unknown', '0', 'ping', 'hash', 'edit', 'subject', 'max_buckets', 'download', 'delivery', 'props', 'sticker', 'name', 'last', 'contacts', 'business', 'primary', 'preview', 'w:p', 'pkmsg', 'call-id', 'retry', 'prop', 'call', 'auth_ttl', 'available', 'relay_id', 'last_id', 'day_of_week', 'w', 'host', 'seen', 'bits', 'list', 'atn', 'upload', 'is_new', 'w:stats', 'key', 'paused', 'specific_hours', 'multicast', 'stream:error', 'mmg.whatsapp.net', 'code', 'deny', 'played', 'profile', 'fna', 'device-list', 'close_time', 'latency', 'gcm', 'pop', 'audio', '26', 'w:web', 'open_time', 'error', 'auth', 'ip4', 'update', 'profile_options', 'config_value', 'category', 'catalog_not_created', '00', 'config_code', 'mode', 'catalog_status', 'ip6', 'blocklist', 'registration', '7', 'web', 'fail', 'w:m', 'cart_enabled', 'ttl', 'gif', '300', 'device_orientation', 'identity', 'query', '401', 'media-gig2-1.cdn.whatsapp.net', 'in', '3', 'te2', 'add', 'fallback', 'categories', 'ptt', 'encrypt', 'notice', 'thumbnail-document', 'item-not-found', '12', 'thumbnail-image', 'stage', 'thumbnail-link', 'usync', 'out', 'thumbnail-video', '8', '01', 'context', 'sidelist', 'thumbnail-gif', 'terminate', 'not-authorized', 'orientation', 'dhash', 'capability', 'side_list', 'md-app-state', 'description', 'serial', 'readreceipts', 'te', 'business_hours', 'md-msg-hist', 'tag', 'attribute_padding', 'document', 'open_24h', 'delete', 'expiration', 'active', 'prev_v_id', 'true', 'passive', 'index', '4', 'conflict', 'remove', 'w:gp2', 'config_expo_key', 'screen_height', 'replaced', '02', 'screen_width', 'uploadfieldstat', '2:47DEQpj8', 'media-bog1-1.cdn.whatsapp.net', 'encopt', 'url', 'catalog_exists', 'keygen', 'rate', 'offer', 'opus', 'media-mia3-1.cdn.whatsapp.net', 'privacy', 'media-mia3-2.cdn.whatsapp.net', 'signature', 'preaccept', 'token_id', 'media-eze1-1.cdn.whatsapp.net'
31
31
  ];
32
32
  exports.TOKEN_MAP = {};
33
- for (const [i, SINGLE_BYTE_TOKEN] of exports.SINGLE_BYTE_TOKENS.entries()) {
34
- exports.TOKEN_MAP[SINGLE_BYTE_TOKEN] = { index: i };
33
+ for (let i = 0; i < exports.SINGLE_BYTE_TOKENS.length; i++) {
34
+ exports.TOKEN_MAP[exports.SINGLE_BYTE_TOKENS[i]] = { index: i };
35
35
  }
36
- for (const [i, DOUBLE_BYTE_TOKEN] of exports.DOUBLE_BYTE_TOKENS.entries()) {
37
- for (const [j, element] of DOUBLE_BYTE_TOKEN.entries()) {
38
- exports.TOKEN_MAP[element] = { dict: i, index: j };
36
+ for (let i = 0; i < exports.DOUBLE_BYTE_TOKENS.length; i++) {
37
+ for (let j = 0; j < exports.DOUBLE_BYTE_TOKENS[i].length; j++) {
38
+ exports.TOKEN_MAP[exports.DOUBLE_BYTE_TOKENS[i][j]] = { dict: i, index: j };
39
39
  }
40
40
  }