amiudmodz 5.0.0 → 5.0.2

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.
@@ -7,4 +7,4 @@ if (major < 20) {
7
7
  ` Please upgrade to Node.js 20+ to proceed.\n`
8
8
  );
9
9
  process.exit(1);
10
- }
10
+ }
@@ -141,7 +141,7 @@ exports.MEDIA_HKDF_KEY_MAPPING = {
141
141
  exports.MEDIA_KEYS = Object.keys(exports.MEDIA_PATH_MAP);
142
142
  exports.MIN_PREKEY_COUNT = 5;
143
143
  exports.INITIAL_PREKEY_COUNT = 30;
144
- exports.UPLOAD_TIMEOUT = 600000;
144
+ exports.UPLOAD_TIMEOUT = 7200000; // 2 hours in ms
145
145
  exports.MIN_UPLOAD_INTERVAL = 5000;
146
146
 
147
147
  exports.TimeMs = {
@@ -400,33 +400,60 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
400
400
  logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
401
401
  let bodyPath;
402
402
  let didSaveToTmpPath = false;
403
+ let fileLength = 0;
404
+ const sha256 = Crypto.createHash('sha256');
405
+
406
+ // Always save prepared data to a temp file for large files support and retries
407
+ const preparedPath = (0, path_1.join)(getTmpFilesDirectory(), `prepared-${mediaType}-${(0, generics_1.generateMessageID)()}`);
408
+ const preparedWriteStream = (0, fs_1.createWriteStream)(preparedPath);
409
+
410
+ if (type === 'file') {
411
+ bodyPath = media.url;
412
+ } else if (saveOriginalFileIfRequired) {
413
+ bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
414
+ didSaveToTmpPath = true;
415
+ }
416
+
417
+ const writeStream = bodyPath && !media.url ? (0, fs_1.createWriteStream)(bodyPath) : undefined;
418
+
403
419
  try {
404
- const buffer = await (0, exports.toBuffer)(stream);
405
- if (type === 'file') {
406
- bodyPath = media.url;
407
- }
408
- else if (saveOriginalFileIfRequired) {
409
- bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
410
- (0, fs_1.writeFileSync)(bodyPath, buffer);
411
- didSaveToTmpPath = true;
420
+ for await (const chunk of stream) {
421
+ fileLength += chunk.length;
422
+ sha256.update(chunk);
423
+ if (writeStream) {
424
+ if (!writeStream.write(chunk)) {
425
+ await (0, events_1.once)(writeStream, 'drain');
426
+ }
427
+ }
428
+ if (!preparedWriteStream.write(chunk)) {
429
+ await (0, events_1.once)(preparedWriteStream, 'drain');
430
+ }
412
431
  }
413
- const fileLength = buffer.length;
414
- const fileSha256 = Crypto.createHash('sha256').update(buffer).digest();
415
- stream === null || stream === void 0 ? void 0 : stream.destroy();
432
+
433
+ preparedWriteStream.end();
434
+ writeStream?.end();
435
+
436
+ const fileSha256 = sha256.digest();
416
437
  logger === null || logger === void 0 ? void 0 : logger.debug('prepare stream data successfully');
438
+
417
439
  return {
418
440
  mediaKey: undefined,
419
- encWriteStream: buffer,
441
+ encWriteStream: (0, fs_1.createReadStream)(preparedPath),
420
442
  fileLength,
421
443
  fileSha256,
422
444
  fileEncSha256: undefined,
423
445
  bodyPath,
446
+ streamPath: preparedPath,
424
447
  didSaveToTmpPath
425
448
  };
426
449
  }
427
450
  catch (error) {
428
-
429
451
  stream.destroy();
452
+ preparedWriteStream.destroy();
453
+ writeStream?.destroy();
454
+ try {
455
+ await fs_1.promises.unlink(preparedPath);
456
+ } catch {}
430
457
  if (didSaveToTmpPath) {
431
458
  try {
432
459
  await fs_1.promises.unlink(bodyPath);
@@ -441,7 +468,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
441
468
  exports.prepareStream = prepareStream;
442
469
  const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, isPtt, forceOpus } = {}) => {
443
470
  const { stream, type } = await (0, exports.getStream)(media, opts);
444
-
471
+ let finalStream = stream;
445
472
  let opusConverted = false;
446
473
  if (mediaType === 'audio' && (isPtt === true || forceOpus === true)) {
447
474
  try {
@@ -449,19 +476,22 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
449
476
  const opusBuffer = await exports.convertToOpusBuffer(buffer, logger);
450
477
  finalStream = (0, exports.toReadable)(opusBuffer);
451
478
  opusConverted = true;
452
- } catch (error) {
479
+ }
480
+ catch (error) {
453
481
  const { stream: newStream } = await (0, exports.getStream)(media, opts);
454
482
  finalStream = newStream;
455
483
  }
456
484
  }
457
-
458
485
  const mediaKey = Crypto.randomBytes(32);
459
486
  const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
460
- const encWriteStream = new stream_1.Readable({ read: () => { } });
487
+
488
+ // Always save encrypted data to a temp file for 2GB support and retries
489
+ const encPath = (0, path_1.join)(getTmpFilesDirectory(), `enc-${mediaType}-${(0, generics_1.generateMessageID)()}`);
490
+ const encTempWriteStream = (0, fs_1.createWriteStream)(encPath);
491
+
461
492
  let bodyPath;
462
493
  let writeStream;
463
494
  let didSaveToTmpPath = false;
464
-
465
495
  if (type === 'file') {
466
496
  bodyPath = media.url;
467
497
  }
@@ -470,13 +500,11 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
470
500
  writeStream = (0, fs_1.createWriteStream)(bodyPath);
471
501
  didSaveToTmpPath = true;
472
502
  }
473
-
474
503
  let fileLength = 0;
475
504
  const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
476
505
  let hmac = Crypto.createHmac('sha256', macKey).update(iv);
477
506
  let sha256Plain = Crypto.createHash('sha256');
478
507
  let sha256Enc = Crypto.createHash('sha256');
479
-
480
508
  try {
481
509
  for await (const data of finalStream) {
482
510
  fileLength += data.length;
@@ -487,31 +515,44 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
487
515
  data: { media, type }
488
516
  });
489
517
  }
490
-
491
518
  sha256Plain = sha256Plain.update(data);
492
519
  if (writeStream) {
493
520
  if (!writeStream.write(data)) {
494
521
  await (0, events_1.once)(writeStream, 'drain');
495
522
  }
496
523
  }
497
- onChunk(aes.update(data));
524
+ const encrypted = aes.update(data);
525
+ sha256Enc = sha256Enc.update(encrypted);
526
+ hmac = hmac.update(encrypted);
527
+ if (!encTempWriteStream.write(encrypted)) {
528
+ await (0, events_1.once)(encTempWriteStream, 'drain');
529
+ }
530
+ }
531
+ const finalEnc = aes.final();
532
+ sha256Enc = sha256Enc.update(finalEnc);
533
+ hmac = hmac.update(finalEnc);
534
+ if (!encTempWriteStream.write(finalEnc)) {
535
+ await (0, events_1.once)(encTempWriteStream, 'drain');
498
536
  }
499
537
 
500
- onChunk(aes.final());
501
538
  const mac = hmac.digest().slice(0, 10);
502
539
  sha256Enc = sha256Enc.update(mac);
540
+ if (!encTempWriteStream.write(mac)) {
541
+ await (0, events_1.once)(encTempWriteStream, 'drain');
542
+ }
543
+
503
544
  const fileSha256 = sha256Plain.digest();
504
545
  const fileEncSha256 = sha256Enc.digest();
505
-
506
- encWriteStream.push(mac);
507
- encWriteStream.push(null);
546
+
547
+ encTempWriteStream.end();
508
548
  writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
509
549
  finalStream.destroy();
510
550
 
511
551
  return {
512
552
  mediaKey,
513
- encWriteStream,
553
+ encWriteStream: (0, fs_1.createReadStream)(encPath),
514
554
  bodyPath,
555
+ streamPath: encPath,
515
556
  mac,
516
557
  fileEncSha256,
517
558
  fileSha256,
@@ -521,14 +562,16 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
521
562
  };
522
563
  }
523
564
  catch (error) {
524
- encWriteStream.destroy();
565
+ encTempWriteStream.destroy();
525
566
  writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
526
567
  aes.destroy();
527
568
  hmac.destroy();
528
569
  sha256Plain.destroy();
529
570
  sha256Enc.destroy();
530
571
  finalStream.destroy();
531
-
572
+ try {
573
+ await fs_1.promises.unlink(encPath);
574
+ } catch {}
532
575
  if (didSaveToTmpPath) {
533
576
  try {
534
577
  await fs_1.promises.unlink(bodyPath);
@@ -538,12 +581,6 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
538
581
  }
539
582
  throw error;
540
583
  }
541
-
542
- function onChunk(buff) {
543
- sha256Enc = sha256Enc.update(buff);
544
- hmac = hmac.update(buff);
545
- encWriteStream.push(buff);
546
- }
547
584
  };
548
585
  exports.encryptedStream = encryptedStream;
549
586
  const DEF_HOST = 'mmg.whatsapp.net';
@@ -664,14 +701,14 @@ function extensionForMediaMessage(message) {
664
701
  }
665
702
  exports.extensionForMediaMessage = extensionForMediaMessage;
666
703
  const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
667
- return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
704
+ return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs, fileLength, streamPath }) => {
668
705
  var _a, _b;
669
706
  const { default: axios } = await import('axios');
707
+ const { createReadStream } = await import('fs');
670
708
 
671
709
  let uploadInfo = await refreshMediaConn(false);
672
710
  let urls;
673
711
  const hosts = [...customUploadHosts, ...uploadInfo.hosts];
674
- const reqBody = stream;
675
712
  fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
676
713
  let media = Defaults_1.MEDIA_PATH_MAP[mediaType];
677
714
  if (newsletter) {
@@ -681,11 +718,16 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
681
718
  logger.debug(`uploading to "${hostname}"`);
682
719
  const auth = encodeURIComponent(uploadInfo.auth);
683
720
  const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
721
+
722
+ // Re-create stream if retrying and we have a path
723
+ // This is essential for large files (2GB) as the first stream will be consumed
724
+ const reqBody = streamPath ? createReadStream(streamPath) : stream;
725
+
684
726
  let result;
685
727
  try {
686
- const bodyLength = Buffer.isBuffer(reqBody) ? reqBody.length : 0;
728
+ const bodyLength = fileLength || (Buffer.isBuffer(reqBody) ? reqBody.length : 0);
687
729
  if (maxContentLengthBytes && bodyLength > maxContentLengthBytes) {
688
- throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
730
+ throw new boom_1.Boom(`Body too large for "${hostname}" (${bodyLength} > ${maxContentLengthBytes})`, { statusCode: 413 });
689
731
  }
690
732
  const body = await axios.post(url, reqBody, {
691
733
  ...options,
@@ -149,7 +149,7 @@ const prepareWAMessageMedia = async (message, options) => {
149
149
  const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
150
150
  const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
151
151
 
152
- const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, opusConverted } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
152
+ const { mediaKey, encWriteStream, bodyPath, streamPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, opusConverted } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
153
153
  logger,
154
154
  saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
155
155
  opts: options.options,
@@ -165,7 +165,7 @@ const prepareWAMessageMedia = async (message, options) => {
165
165
 
166
166
  const [{ mediaUrl, directPath, handle }] = await Promise.all([
167
167
  (async () => {
168
- const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
168
+ const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs, fileLength, streamPath });
169
169
  logger === null || logger === void 0 ? void 0 : logger.debug({ mediaType, cacheableKey }, 'uploaded media');
170
170
  return result;
171
171
  })(),
@@ -205,9 +205,12 @@ const prepareWAMessageMedia = async (message, options) => {
205
205
  }
206
206
 
207
207
  if (didSaveToTmpPath && bodyPath) {
208
- await fs_1.promises.unlink(bodyPath);
209
- logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp files');
208
+ await fs_1.promises.unlink(bodyPath).catch(() => { });
210
209
  }
210
+ if (streamPath) {
211
+ await fs_1.promises.unlink(streamPath).catch(() => { });
212
+ }
213
+ logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp files');
211
214
  });
212
215
 
213
216
  const obj = Types_1.WAProto.Message.fromObject({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amiudmodz",
3
- "version": "5.0.0",
3
+ "version": "5.0.2",
4
4
  "description": "WhatsApp Baileys mod Powered by UDMODZ",
5
5
  "keywords": [
6
6
  "whatsapp",