alipclutch-baileys 8.3.0 → 8.4.1

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 (120) hide show
  1. package/LICENSE +3 -1
  2. package/README.md +10 -9
  3. package/WAProto/GenerateStatics.sh +4 -0
  4. package/WAProto/WAProto.proto +4775 -0
  5. package/WAProto/index.d.ts +55057 -0
  6. package/WAProto/index.js +56887 -17535
  7. package/WAProto/index.ts.ts +53473 -0
  8. package/lib/Defaults/baileys-version.json +2 -2
  9. package/lib/Defaults/index.d.ts +16 -7
  10. package/lib/Defaults/index.js +90 -119
  11. package/lib/Socket/Client/index.d.ts +2 -3
  12. package/lib/Socket/Client/index.js +2 -3
  13. package/lib/Socket/Client/types.d.ts +0 -1
  14. package/lib/Socket/Client/types.js +0 -1
  15. package/lib/Socket/Client/websocket.d.ts +0 -1
  16. package/lib/Socket/Client/websocket.js +0 -1
  17. package/lib/Socket/business.d.ts +59 -58
  18. package/lib/Socket/chats.d.ts +45 -230
  19. package/lib/Socket/chats.js +139 -238
  20. package/lib/Socket/groups.d.ts +41 -32
  21. package/lib/Socket/groups.js +38 -23
  22. package/lib/Socket/index.d.ts +63 -64
  23. package/lib/Socket/index.js +2 -3
  24. package/lib/Socket/messages-recv.js +9 -65
  25. package/lib/Socket/messages-send.d.ts +49 -47
  26. package/lib/Socket/messages-send.js +584 -395
  27. package/lib/Socket/newsletter.d.ts +39 -37
  28. package/lib/Socket/newsletter.js +88 -123
  29. package/lib/Socket/setup.js +433 -0
  30. package/lib/Socket/{dugong.d.ts → setup.ts} +17 -52
  31. package/lib/Socket/socket.d.ts +10 -10
  32. package/lib/Socket/socket.js +62 -38
  33. package/lib/Socket/usync.d.ts +3 -4
  34. package/lib/Socket/usync.js +0 -1
  35. package/lib/Store/index.d.ts +1 -2
  36. package/lib/Store/index.js +1 -3
  37. package/lib/Store/make-in-memory-store.d.ts +24 -24
  38. package/lib/Store/make-in-memory-store.js +26 -14
  39. package/lib/Store/make-ordered-dictionary.d.ts +1 -1
  40. package/lib/Store/make-ordered-dictionary.js +2 -2
  41. package/lib/Types/Auth.d.ts +0 -7
  42. package/lib/Types/Call.d.ts +1 -1
  43. package/lib/Types/Chat.d.ts +14 -7
  44. package/lib/Types/Contact.d.ts +5 -1
  45. package/lib/Types/Events.d.ts +44 -2
  46. package/lib/Types/GroupMetadata.d.ts +11 -2
  47. package/lib/Types/Label.js +1 -1
  48. package/lib/Types/LabelAssociation.js +1 -1
  49. package/lib/Types/Message.d.ts +148 -21
  50. package/lib/Types/Message.js +0 -2
  51. package/lib/Types/Newsletter.d.ts +73 -97
  52. package/lib/Types/Newsletter.js +18 -38
  53. package/lib/Types/Socket.d.ts +17 -9
  54. package/lib/Types/index.d.ts +8 -1
  55. package/lib/Types/index.js +2 -2
  56. package/lib/Utils/auth-utils.d.ts +3 -3
  57. package/lib/Utils/auth-utils.js +6 -13
  58. package/lib/Utils/business.js +2 -2
  59. package/lib/Utils/chat-utils.d.ts +15 -16
  60. package/lib/Utils/chat-utils.js +36 -35
  61. package/lib/Utils/crypto.d.ts +15 -16
  62. package/lib/Utils/crypto.js +71 -29
  63. package/lib/Utils/decode-wa-message.d.ts +22 -6
  64. package/lib/Utils/decode-wa-message.js +65 -56
  65. package/lib/Utils/event-buffer.d.ts +2 -2
  66. package/lib/Utils/event-buffer.js +11 -7
  67. package/lib/Utils/generics.d.ts +17 -20
  68. package/lib/Utils/generics.js +95 -75
  69. package/lib/Utils/history.d.ts +4 -0
  70. package/lib/Utils/history.js +4 -6
  71. package/lib/Utils/link-preview.d.ts +2 -2
  72. package/lib/Utils/link-preview.js +34 -1
  73. package/lib/Utils/logger.d.ts +10 -3
  74. package/lib/Utils/lt-hash.d.ts +2 -2
  75. package/lib/Utils/lt-hash.js +6 -6
  76. package/lib/Utils/make-mutex.d.ts +2 -2
  77. package/lib/Utils/messages-media.d.ts +28 -24
  78. package/lib/Utils/messages-media.js +272 -111
  79. package/lib/Utils/messages.d.ts +13 -10
  80. package/lib/Utils/messages.js +323 -50
  81. package/lib/Utils/noise-handler.d.ts +10 -12
  82. package/lib/Utils/noise-handler.js +18 -23
  83. package/lib/Utils/process-message.d.ts +5 -4
  84. package/lib/Utils/process-message.js +108 -25
  85. package/lib/Utils/signal.d.ts +2 -1
  86. package/lib/Utils/signal.js +26 -26
  87. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -1
  88. package/lib/Utils/use-multi-file-auth-state.js +51 -6
  89. package/lib/Utils/validate-connection.d.ts +3 -4
  90. package/lib/Utils/validate-connection.js +90 -66
  91. package/lib/WABinary/constants.d.ts +24 -27
  92. package/lib/WABinary/constants.js +1276 -13
  93. package/lib/WABinary/decode.d.ts +3 -4
  94. package/lib/WABinary/decode.js +26 -13
  95. package/lib/WABinary/encode.d.ts +1 -2
  96. package/lib/WABinary/encode.js +137 -152
  97. package/lib/WABinary/generic-utils.d.ts +1 -4
  98. package/lib/WABinary/generic-utils.js +37 -125
  99. package/lib/WABinary/jid-utils.d.ts +11 -5
  100. package/lib/WABinary/jid-utils.js +28 -5
  101. package/lib/WABinary/jid-utils.js.bak +83 -0
  102. package/lib/WAM/BinaryInfo.d.ts +2 -11
  103. package/lib/WAM/encode.d.ts +1 -2
  104. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +1 -1
  105. package/lib/index.d.ts +0 -1
  106. package/lib/index.js +27 -15
  107. package/package.json +18 -31
  108. package/engine-requirements.js +0 -10
  109. package/lib/Defaults/phonenumber-mcc.json +0 -223
  110. package/lib/Socket/Client/abstract-socket-client.d.ts +0 -17
  111. package/lib/Socket/Client/abstract-socket-client.js +0 -13
  112. package/lib/Socket/Client/mobile-socket-client.d.ts +0 -13
  113. package/lib/Socket/Client/mobile-socket-client.js +0 -65
  114. package/lib/Socket/Client/web-socket-client.d.ts +0 -12
  115. package/lib/Socket/Client/web-socket-client.js +0 -62
  116. package/lib/Socket/dugong.js +0 -483
  117. package/lib/Socket/registration.d.ts +0 -267
  118. package/lib/Socket/registration.js +0 -166
  119. package/lib/Store/make-cache-manager-store.d.ts +0 -13
  120. package/lib/Store/make-cache-manager-store.js +0 -83
@@ -15,23 +15,47 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
37
  };
25
38
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.getStatusCodeForMediaRetry = exports.decryptMediaRetryData = exports.decodeMediaRetryNode = exports.encryptMediaRetryRequest = exports.getWAUploadToServer = exports.extensionForMediaMessage = exports.downloadEncryptedContent = exports.downloadContentFromMessage = exports.getUrlFromDirectPath = exports.encryptedStream = exports.prepareStream = exports.getHttpStream = exports.generateThumbnail = exports.getStream = exports.toBuffer = exports.toReadable = exports.getAudioWaveform = exports.getAudioDuration = exports.mediaMessageSHA256B64 = exports.generateProfilePicture = exports.encodeBase64EncodedStringForUpload = exports.extractImageThumb = exports.getMediaKeys = exports.hkdfInfoKey = void 0;
39
+ exports.getStatusCodeForMediaRetry = exports.decryptMediaRetryData = exports.decodeMediaRetryNode = exports.encryptMediaRetryRequest = exports.getWAUploadToServer = exports.downloadEncryptedContent = exports.downloadContentFromMessage = exports.getUrlFromDirectPath = exports.encryptedStream = exports.prepareStream = exports.getHttpStream = exports.getStream = exports.toBuffer = exports.toReadable = exports.mediaMessageSHA256B64 = exports.generateProfilePicture = exports.encodeBase64EncodedStringForUpload = exports.extractImageThumb = exports.extractVideoThumb = exports.hkdfInfoKey = void 0;
40
+ exports.getMediaKeys = getMediaKeys;
41
+ exports.uploadFile = uploadFile;
42
+ exports.vid2jpg = vid2jpg;
43
+ exports.getAudioDuration = getAudioDuration;
44
+ exports.getAudioWaveform = getAudioWaveform;
45
+ exports.generateThumbnail = generateThumbnail;
46
+ exports.extensionForMediaMessage = extensionForMediaMessage;
27
47
  const boom_1 = require("@hapi/boom");
28
- const child_process_1 = require("child_process");
48
+ const axios_1 = __importDefault(require("axios"));
49
+ const form_data_1 = __importDefault(require("form-data"));
50
+ const cheerio = __importStar(require("cheerio"));
29
51
  const Crypto = __importStar(require("crypto"));
30
52
  const events_1 = require("events");
31
53
  const fs_1 = require("fs");
32
54
  const os_1 = require("os");
33
55
  const path_1 = require("path");
56
+ const jimp_1 = __importDefault(require("jimp"));
34
57
  const stream_1 = require("stream");
58
+ const child_process_1 = require("child_process");
35
59
  const WAProto_1 = require("../../WAProto");
36
60
  const Defaults_1 = require("../Defaults");
37
61
  const WABinary_1 = require("../WABinary");
@@ -41,13 +65,11 @@ const getTmpFilesDirectory = () => (0, os_1.tmpdir)();
41
65
  const getImageProcessingLibrary = async () => {
42
66
  const [_jimp, sharp] = await Promise.all([
43
67
  (async () => {
44
- const jimp = await (import('jimp')
45
- .catch(() => { }));
68
+ const jimp = await (Promise.resolve().then(() => __importStar(require('jimp'))).catch(() => { }));
46
69
  return jimp;
47
70
  })(),
48
71
  (async () => {
49
- const sharp = await (import('sharp')
50
- .catch(() => { }));
72
+ const sharp = await (Promise.resolve().then(() => __importStar(require('sharp'))).catch(() => { }));
51
73
  return sharp;
52
74
  })()
53
75
  ]);
@@ -66,7 +88,7 @@ const hkdfInfoKey = (type) => {
66
88
  };
67
89
  exports.hkdfInfoKey = hkdfInfoKey;
68
90
  /** generates all the keys required to encrypt/decrypt & sign a media message */
69
- function getMediaKeys(buffer, mediaType) {
91
+ async function getMediaKeys(buffer, mediaType) {
70
92
  if (!buffer) {
71
93
  throw new boom_1.Boom('Cannot derive from empty media key');
72
94
  }
@@ -74,26 +96,183 @@ function getMediaKeys(buffer, mediaType) {
74
96
  buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64');
75
97
  }
76
98
  // expand using HKDF to 112 bytes, also pass in the relevant app info
77
- const expandedMediaKey = (0, crypto_1.hkdf)(buffer, 112, { info: (0, exports.hkdfInfoKey)(mediaType) });
99
+ const expandedMediaKey = await (0, crypto_1.hkdf)(buffer, 112, { info: (0, exports.hkdfInfoKey)(mediaType) });
78
100
  return {
79
101
  iv: expandedMediaKey.slice(0, 16),
80
102
  cipherKey: expandedMediaKey.slice(16, 48),
81
103
  macKey: expandedMediaKey.slice(48, 80),
82
104
  };
83
105
  }
84
- exports.getMediaKeys = getMediaKeys;
85
- /** Extracts video thumb using FFMPEG */
86
- const extractVideoThumb = async (path, destPath, time, size) => new Promise((resolve, reject) => {
87
- const cmd = `ffmpeg -ss ${time} -i ${path} -y -vf scale=${size.width}:-1 -vframes 1 -f image2 ${destPath}`;
88
- (0, child_process_1.exec)(cmd, (err) => {
89
- if (err) {
90
- reject(err);
106
+ async function uploadFile(buffer, logger) {
107
+ const { fromBuffer } = await Promise.resolve().then(() => __importStar(require('file-type')));
108
+ const fileType = await fromBuffer(buffer);
109
+ if (!fileType)
110
+ throw new Error("Failed to detect file type.");
111
+ const { ext, mime } = fileType;
112
+ const services = [
113
+ {
114
+ name: "catbox",
115
+ url: "https://catbox.moe/user/api.php",
116
+ buildForm: () => {
117
+ const form = new form_data_1.default();
118
+ form.append("fileToUpload", buffer, {
119
+ filename: `file.${ext}`,
120
+ contentType: mime || "application/octet-stream"
121
+ });
122
+ form.append("reqtype", "fileupload");
123
+ return form;
124
+ },
125
+ parseResponse: res => res.data
126
+ },
127
+ {
128
+ name: "pdi.moe",
129
+ url: "https://scdn.pdi.moe/upload",
130
+ buildForm: () => {
131
+ const form = new form_data_1.default();
132
+ form.append("file", buffer, {
133
+ filename: `file.${ext}`,
134
+ contentType: mime
135
+ });
136
+ return form;
137
+ },
138
+ parseResponse: res => res.data.result.url
139
+ },
140
+ {
141
+ name: "qu.ax",
142
+ url: "https://qu.ax/upload.php",
143
+ buildForm: () => {
144
+ const form = new form_data_1.default();
145
+ form.append("files[]", buffer, {
146
+ filename: `file.${ext}`,
147
+ contentType: mime || "application/octet-stream"
148
+ });
149
+ return form;
150
+ },
151
+ parseResponse: res => {
152
+ var _a, _b, _c;
153
+ if (!((_c = (_b = (_a = res.data) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.url))
154
+ throw new Error("Failed to get URL from qu.ax");
155
+ return res.data.files[0].url;
156
+ }
157
+ },
158
+ {
159
+ name: "uguu.se",
160
+ url: "https://uguu.se/upload.php",
161
+ buildForm: () => {
162
+ const form = new form_data_1.default();
163
+ form.append("files[]", buffer, {
164
+ filename: `file.${ext}`,
165
+ contentType: mime || "application/octet-stream"
166
+ });
167
+ return form;
168
+ },
169
+ parseResponse: res => {
170
+ var _a, _b, _c;
171
+ if (!((_c = (_b = (_a = res.data) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.url))
172
+ throw new Error("Failed to get URL from uguu.se");
173
+ return res.data.files[0].url;
174
+ }
175
+ },
176
+ {
177
+ name: "tmpfiles",
178
+ url: "https://tmpfiles.org/api/v1/upload",
179
+ buildForm: () => {
180
+ const form = new form_data_1.default();
181
+ form.append("file", buffer, {
182
+ filename: `file.${ext}`,
183
+ contentType: mime
184
+ });
185
+ return form;
186
+ },
187
+ parseResponse: res => {
188
+ const match = res.data.data.url.match(/https:\/\/tmpfiles\.org\/(.*)/);
189
+ if (!match)
190
+ throw new Error("Failed to parse tmpfiles URL.");
191
+ return `https://tmpfiles.org/dl/${match[1]}`;
192
+ }
91
193
  }
92
- else {
93
- resolve();
194
+ ];
195
+ for (const service of services) {
196
+ try {
197
+ const form = service.buildForm();
198
+ const res = await axios_1.default.post(service.url, form, {
199
+ headers: form.getHeaders()
200
+ });
201
+ const url = service.parseResponse(res);
202
+ return url;
203
+ }
204
+ catch (error) {
205
+ logger === null || logger === void 0 ? void 0 : logger.debug(`[${service.name}] eror:`, (error === null || error === void 0 ? void 0 : error.message) || error);
206
+ }
207
+ }
208
+ throw new Error("All upload services failed.");
209
+ }
210
+ async function vid2jpg(videoUrl) {
211
+ try {
212
+ const { data } = await axios_1.default.get(`https://ezgif.com/video-to-jpg?url=${encodeURIComponent(videoUrl)}`);
213
+ const $ = cheerio.load(data);
214
+ const fileToken = $('input[name="file"]').attr("value");
215
+ if (!fileToken) {
216
+ throw new Error("Failed to retrieve file token. The video URL may be invalid or inaccessible.");
217
+ }
218
+ const formData = new URLSearchParams();
219
+ formData.append("file", fileToken);
220
+ formData.append("end", "1");
221
+ formData.append("video-to-jpg", "Convert to JPG!");
222
+ const convert = await axios_1.default.post(`https://ezgif.com/video-to-jpg/${fileToken}`, formData);
223
+ const $2 = cheerio.load(convert.data);
224
+ let imageUrl = $2("#output img").first().attr("src");
225
+ if (!imageUrl) {
226
+ throw new Error("Could not locate the converted image output.");
227
+ }
228
+ if (imageUrl.startsWith("//")) {
229
+ imageUrl = "https:" + imageUrl;
94
230
  }
231
+ else if (imageUrl.startsWith("/")) {
232
+ const cdnMatch = imageUrl.match(/\/(s\d+\..+?)\/.*/);
233
+ if (cdnMatch) {
234
+ imageUrl = "https://" + imageUrl.slice(2);
235
+ }
236
+ else {
237
+ imageUrl = "https://ezgif.com" + imageUrl;
238
+ }
239
+ }
240
+ return imageUrl;
241
+ }
242
+ catch (error) {
243
+ throw new Error("Failed to convert video to JPG: " + error.message);
244
+ }
245
+ }
246
+ /**
247
+ * Extracts video thumbnail using FFmpeg
248
+ */
249
+ const extractVideoThumb = async (videoPath, time = '00:00:00', size = { width: 256 }) => {
250
+ return new Promise((resolve, reject) => {
251
+ const args = [
252
+ '-ss', time,
253
+ '-i', videoPath,
254
+ '-y',
255
+ '-vf', `scale=${size.width}:-1`,
256
+ '-vframes', '1',
257
+ '-f', 'image2',
258
+ '-vcodec', 'mjpeg',
259
+ 'pipe:1'
260
+ ];
261
+ const ffmpeg = (0, child_process_1.spawn)('ffmpeg', args);
262
+ const chunks = [];
263
+ let errorOutput = '';
264
+ ffmpeg.stdout.on('data', chunk => chunks.push(chunk));
265
+ ffmpeg.stderr.on('data', data => {
266
+ errorOutput += data.toString();
267
+ });
268
+ ffmpeg.on('error', reject);
269
+ ffmpeg.on('close', code => {
270
+ if (code === 0) return resolve(Buffer.concat(chunks));
271
+ reject(new Error(`ffmpeg exited with code ${code}\n${errorOutput}`));
272
+ });
95
273
  });
96
- });
274
+ };
275
+ exports.extractVideoThumb = extractVideoThumb;
97
276
  const extractImageThumb = async (bufferOrFilePath, width = 32) => {
98
277
  var _a, _b;
99
278
  if (bufferOrFilePath instanceof stream_1.Readable) {
@@ -142,8 +321,8 @@ const encodeBase64EncodedStringForUpload = (b64) => (encodeURIComponent(b64
142
321
  .replace(/\=+$/, '')));
143
322
  exports.encodeBase64EncodedStringForUpload = encodeBase64EncodedStringForUpload;
144
323
  const generateProfilePicture = async (mediaUpload) => {
145
- var _a, _b;
146
324
  let bufferOrFilePath;
325
+ let img;
147
326
  if (Buffer.isBuffer(mediaUpload)) {
148
327
  bufferOrFilePath = mediaUpload;
149
328
  }
@@ -153,29 +332,11 @@ const generateProfilePicture = async (mediaUpload) => {
153
332
  else {
154
333
  bufferOrFilePath = await (0, exports.toBuffer)(mediaUpload.stream);
155
334
  }
156
- const lib = await getImageProcessingLibrary();
157
- let img;
158
- if ('sharp' in lib && typeof ((_a = lib.sharp) === null || _a === void 0 ? void 0 : _a.default) === 'function') {
159
- img = lib.sharp.default(bufferOrFilePath)
160
- .resize(640, 640)
161
- .jpeg({
162
- quality: 50,
163
- })
164
- .toBuffer();
165
- }
166
- else if ('jimp' in lib && typeof ((_b = lib.jimp) === null || _b === void 0 ? void 0 : _b.read) === 'function') {
167
- const { read, MIME_JPEG, RESIZE_BILINEAR } = lib.jimp;
168
- const jimp = await read(bufferOrFilePath);
169
- const min = Math.min(jimp.getWidth(), jimp.getHeight());
170
- const cropped = jimp.crop(0, 0, min, min);
171
- img = cropped
172
- .quality(50)
173
- .resize(640, 640, RESIZE_BILINEAR)
174
- .getBufferAsync(MIME_JPEG);
175
- }
176
- else {
177
- throw new boom_1.Boom('No image processing library available');
178
- }
335
+ const jimp = await jimp_1.default.read(bufferOrFilePath);
336
+ const cropped = jimp.getWidth() > jimp.getHeight() ? jimp.resize(550, -1) : jimp.resize(-1, 650);
337
+ img = cropped
338
+ .quality(100)
339
+ .getBufferAsync(jimp_1.default.MIME_JPEG);
179
340
  return {
180
341
  img: await img,
181
342
  };
@@ -365,12 +526,28 @@ async function generateThumbnail(file, mediaType, options) {
365
526
  }
366
527
  }
367
528
  else if (mediaType === 'video') {
368
- const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
369
529
  try {
370
- await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
371
- const buff = await fs_1.promises.readFile(imgFilename);
372
- thumbnail = buff.toString('base64');
530
+ let videoPath = file;
531
+ if (Buffer.isBuffer(file) || file instanceof stream_1.Readable) {
532
+ videoPath = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.mp4');
533
+ const buffer = Buffer.isBuffer(file) ? file : await (0, exports.toBuffer)(file);
534
+ await fs_1.promises.writeFile(videoPath, buffer);
535
+ }
536
+ const thumbnailBuffer = await (0, exports.extractVideoThumb)(videoPath);
537
+ const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.jpg');
538
+ await fs_1.promises.writeFile(imgFilename, thumbnailBuffer);
539
+ const { buffer: processedThumbnailBuffer, original } = await (0, exports.extractImageThumb)(imgFilename);
540
+ thumbnail = processedThumbnailBuffer.toString('base64');
541
+ if (original.width && original.height) {
542
+ originalImageDimensions = {
543
+ width: original.width,
544
+ height: original.height,
545
+ };
546
+ }
373
547
  await fs_1.promises.unlink(imgFilename);
548
+ if (videoPath !== file) {
549
+ await fs_1.promises.unlink(videoPath);
550
+ }
374
551
  }
375
552
  catch (err) {
376
553
  (_a = options.logger) === null || _a === void 0 ? void 0 : _a.debug('could not generate video thumb: ' + err);
@@ -381,10 +558,8 @@ async function generateThumbnail(file, mediaType, options) {
381
558
  originalImageDimensions
382
559
  };
383
560
  }
384
- exports.generateThumbnail = generateThumbnail;
385
561
  const getHttpStream = async (url, options = {}) => {
386
- const { default: axios } = await import('axios');
387
- const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
562
+ const fetched = await axios_1.default.get(url.toString(), { ...options, responseType: 'stream' });
388
563
  return fetched.data;
389
564
  };
390
565
  exports.getHttpStream = getHttpStream;
@@ -399,7 +574,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
399
574
  bodyPath = media.url;
400
575
  }
401
576
  else if (saveOriginalFileIfRequired) {
402
- bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
577
+ bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)());
403
578
  (0, fs_1.writeFileSync)(bodyPath, buffer);
404
579
  didSaveToTmpPath = true;
405
580
  }
@@ -418,7 +593,6 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
418
593
  };
419
594
  }
420
595
  catch (error) {
421
- // destroy all streams with error
422
596
  stream.destroy();
423
597
  if (didSaveToTmpPath) {
424
598
  try {
@@ -434,52 +608,53 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
434
608
  exports.prepareStream = prepareStream;
435
609
  const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, isPtt, forceOpus } = {}) => {
436
610
  const { stream, type } = await (0, exports.getStream)(media, opts);
437
-
438
- let finalStream = stream;
611
+ logger?.debug('fetched media stream');
612
+
613
+ let finalStream = stream;
614
+
615
+ // Tambahan untuk konversi audio jadi Opus (PTT)
439
616
  if (mediaType === 'audio' && (isPtt === true || forceOpus === true)) {
440
617
  try {
441
618
  const buffer = await (0, exports.toBuffer)(stream);
442
619
  const opusBuffer = await exports.convertToOpusBuffer(buffer, logger);
443
620
  finalStream = (0, exports.toReadable)(opusBuffer);
621
+ logger?.debug('converted audio to Opus');
444
622
  } catch (error) {
623
+ logger?.error('failed to convert audio to Opus, fallback to original stream');
445
624
  const { stream: newStream } = await (0, exports.getStream)(media, opts);
446
625
  finalStream = newStream;
447
626
  }
448
627
  }
449
628
 
450
629
  const mediaKey = Crypto.randomBytes(32);
451
- const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
630
+ const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
452
631
  const encWriteStream = new stream_1.Readable({ read: () => { } });
453
632
  let bodyPath;
454
633
  let writeStream;
455
634
  let didSaveToTmpPath = false;
456
-
635
+
457
636
  if (type === 'file') {
458
637
  bodyPath = media.url;
459
- }
460
- else if (saveOriginalFileIfRequired) {
461
- bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
638
+ } else if (saveOriginalFileIfRequired) {
639
+ bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)());
462
640
  writeStream = (0, fs_1.createWriteStream)(bodyPath);
463
641
  didSaveToTmpPath = true;
464
642
  }
465
-
643
+
466
644
  let fileLength = 0;
467
645
  const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
468
646
  let hmac = Crypto.createHmac('sha256', macKey).update(iv);
469
647
  let sha256Plain = Crypto.createHash('sha256');
470
648
  let sha256Enc = Crypto.createHash('sha256');
471
-
649
+
472
650
  try {
473
651
  for await (const data of finalStream) {
474
652
  fileLength += data.length;
475
- if (type === 'remote'
476
- && (opts === null || opts === void 0 ? void 0 : opts.maxContentLength)
477
- && fileLength + data.length > opts.maxContentLength) {
653
+ if (type === 'remote' && (opts?.maxContentLength) && fileLength + data.length > opts.maxContentLength) {
478
654
  throw new boom_1.Boom(`content length exceeded when encrypting "${type}"`, {
479
655
  data: { media, type }
480
656
  });
481
657
  }
482
-
483
658
  sha256Plain = sha256Plain.update(data);
484
659
  if (writeStream) {
485
660
  if (!writeStream.write(data)) {
@@ -488,18 +663,20 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
488
663
  }
489
664
  onChunk(aes.update(data));
490
665
  }
491
-
666
+
492
667
  onChunk(aes.final());
493
668
  const mac = hmac.digest().slice(0, 10);
494
669
  sha256Enc = sha256Enc.update(mac);
495
670
  const fileSha256 = sha256Plain.digest();
496
671
  const fileEncSha256 = sha256Enc.digest();
497
-
672
+
498
673
  encWriteStream.push(mac);
499
674
  encWriteStream.push(null);
500
- writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
675
+ writeStream?.end();
501
676
  finalStream.destroy();
502
-
677
+
678
+ logger?.debug('encrypted data successfully');
679
+
503
680
  return {
504
681
  mediaKey,
505
682
  encWriteStream,
@@ -510,26 +687,25 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
510
687
  fileLength,
511
688
  didSaveToTmpPath
512
689
  };
513
- }
514
- catch (error) {
690
+ } catch (error) {
515
691
  encWriteStream.destroy();
516
- writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
692
+ writeStream?.destroy();
517
693
  aes.destroy();
518
694
  hmac.destroy();
519
695
  sha256Plain.destroy();
520
696
  sha256Enc.destroy();
521
697
  finalStream.destroy();
522
-
698
+
523
699
  if (didSaveToTmpPath) {
524
700
  try {
525
701
  await fs_1.promises.unlink(bodyPath);
526
- }
527
- catch (err) {
702
+ } catch (err) {
703
+ logger?.error({ err }, 'failed to save to tmp path');
528
704
  }
529
705
  }
530
706
  throw error;
531
707
  }
532
-
708
+
533
709
  function onChunk(buff) {
534
710
  sha256Enc = sha256Enc.update(buff);
535
711
  hmac = hmac.update(buff);
@@ -544,21 +720,20 @@ const toSmallestChunkSize = (num) => {
544
720
  };
545
721
  const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
546
722
  exports.getUrlFromDirectPath = getUrlFromDirectPath;
547
- const downloadContentFromMessage = ({ mediaKey, directPath, url }, type, opts = {}) => {
548
- const downloadUrl = url || (0, exports.getUrlFromDirectPath)(directPath);
549
- const keys = getMediaKeys(mediaKey, type);
723
+ const downloadContentFromMessage = async ({ mediaKey, directPath, url }, type, opts = {}) => {
724
+ const isValidMediaUrl = url === null || url === void 0 ? void 0 : url.startsWith('https://mmg.whatsapp.net/');
725
+ const downloadUrl = isValidMediaUrl ? url : (0, exports.getUrlFromDirectPath)(directPath);
726
+ if (!downloadUrl) {
727
+ throw new boom_1.Boom('No valid media URL or directPath present in message', { statusCode: 400 });
728
+ }
729
+ const keys = await getMediaKeys(mediaKey, type);
550
730
  return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
551
731
  };
552
732
  exports.downloadContentFromMessage = downloadContentFromMessage;
553
- /**
554
- * Decrypts and downloads an AES256-CBC encrypted file given the keys.
555
- * Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
556
- * */
557
733
  const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
558
734
  let bytesFetched = 0;
559
735
  let startChunk = 0;
560
736
  let firstBlockIsIV = false;
561
- // if a start byte is specified -- then we need to fetch the previous chunk as that will form the IV
562
737
  if (startByte) {
563
738
  const chunk = toSmallestChunkSize(startByte || 0);
564
739
  if (chunk) {
@@ -578,7 +753,6 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
578
753
  headers.Range += endChunk;
579
754
  }
580
755
  }
581
- // download the message
582
756
  const fetched = await (0, exports.getHttpStream)(downloadUrl, {
583
757
  ...options || {},
584
758
  headers,
@@ -611,8 +785,6 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
611
785
  data = data.slice(AES_CHUNK_SIZE);
612
786
  }
613
787
  aes = Crypto.createDecipheriv('aes-256-cbc', cipherKey, ivValue);
614
- // if an end byte that is not EOF is specified
615
- // stop auto padding (PKCS7) -- otherwise throws an error for decryption
616
788
  if (endByte) {
617
789
  aes.setAutoPadding(false);
618
790
  }
@@ -653,12 +825,9 @@ function extensionForMediaMessage(message) {
653
825
  }
654
826
  return extension;
655
827
  }
656
- exports.extensionForMediaMessage = extensionForMediaMessage;
657
828
  const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
658
829
  return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
659
830
  var _a, _b;
660
- const { default: axios } = await import('axios');
661
- // send a query JSON to obtain the url & auth token to upload our media
662
831
  let uploadInfo = await refreshMediaConn(false);
663
832
  let urls;
664
833
  const hosts = [...customUploadHosts, ...uploadInfo.hosts];
@@ -676,14 +845,14 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
676
845
  }
677
846
  for (const { hostname, maxContentLengthBytes } of hosts) {
678
847
  logger.debug(`uploading to "${hostname}"`);
679
- const auth = encodeURIComponent(uploadInfo.auth); // the auth token
848
+ const auth = encodeURIComponent(uploadInfo.auth);
680
849
  const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
681
850
  let result;
682
851
  try {
683
852
  if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
684
853
  throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
685
854
  }
686
- const body = await axios.post(url, reqBody, {
855
+ const body = await axios_1.default.post(url, reqBody, {
687
856
  ...options,
688
857
  headers: {
689
858
  ...options.headers || {},
@@ -711,7 +880,7 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
711
880
  }
712
881
  }
713
882
  catch (error) {
714
- if (axios.isAxiosError(error)) {
883
+ if (axios_1.default.isAxiosError(error)) {
715
884
  result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
716
885
  }
717
886
  const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
@@ -728,14 +897,11 @@ exports.getWAUploadToServer = getWAUploadToServer;
728
897
  const getMediaRetryKey = (mediaKey) => {
729
898
  return (0, crypto_1.hkdf)(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
730
899
  };
731
- /**
732
- * Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
733
- */
734
- const encryptMediaRetryRequest = (key, mediaKey, meId) => {
900
+ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
735
901
  const recp = { stanzaId: key.id };
736
902
  const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
737
903
  const iv = Crypto.randomBytes(12);
738
- const retryKey = getMediaRetryKey(mediaKey);
904
+ const retryKey = await getMediaRetryKey(mediaKey);
739
905
  const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
740
906
  const req = {
741
907
  tag: 'receipt',
@@ -745,9 +911,6 @@ const encryptMediaRetryRequest = (key, mediaKey, meId) => {
745
911
  type: 'server-error'
746
912
  },
747
913
  content: [
748
- // this encrypt node is actually pretty useless
749
- // the media is returned even without this node
750
- // keeping it here to maintain parity with WA Web
751
914
  {
752
915
  tag: 'encrypt',
753
916
  attrs: {},
@@ -761,7 +924,6 @@ const encryptMediaRetryRequest = (key, mediaKey, meId) => {
761
924
  attrs: {
762
925
  jid: key.remoteJid,
763
926
  'from_me': (!!key.fromMe).toString(),
764
- // @ts-ignore
765
927
  participant: key.participant || undefined
766
928
  }
767
929
  }
@@ -799,8 +961,8 @@ const decodeMediaRetryNode = (node) => {
799
961
  return event;
800
962
  };
801
963
  exports.decodeMediaRetryNode = decodeMediaRetryNode;
802
- const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
803
- const retryKey = getMediaRetryKey(mediaKey);
964
+ const decryptMediaRetryData = async ({ ciphertext, iv }, mediaKey, msgId) => {
965
+ const retryKey = await getMediaRetryKey(mediaKey);
804
966
  const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
805
967
  return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
806
968
  };
@@ -813,7 +975,6 @@ const MEDIA_RETRY_STATUS_MAP = {
813
975
  [WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
814
976
  [WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
815
977
  };
816
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
817
978
  function __importStar(arg0) {
818
979
  throw new Error('Function not implemented.');
819
- }
980
+ }