cuki-bailx 1.1.2 → 1.2.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.
Files changed (116) hide show
  1. package/WAProto/index.js +79296 -118676
  2. package/engine-requirements.js +1 -1
  3. package/lib/Defaults/baileys-version.json +1 -1
  4. package/lib/Defaults/index.d.ts +6 -4
  5. package/lib/Defaults/index.js +102 -78
  6. package/lib/Defaults/phonenumber-mcc.json +223 -0
  7. package/lib/Socket/Client/{types.d.ts → abstract-socket-client.d.ts} +2 -1
  8. package/lib/Socket/Client/index.d.ts +3 -2
  9. package/lib/Socket/Client/index.js +3 -2
  10. package/lib/Socket/Client/mobile-socket-client.d.ts +13 -0
  11. package/lib/Socket/Client/mobile-socket-client.js +65 -0
  12. package/lib/Socket/Client/{websocket.d.ts → web-socket-client.d.ts} +1 -2
  13. package/lib/Socket/Client/{websocket.js → web-socket-client.js} +2 -12
  14. package/lib/Socket/business.d.ts +58 -59
  15. package/lib/Socket/chats.d.ts +27 -29
  16. package/lib/Socket/chats.js +90 -97
  17. package/lib/Socket/dugong.d.ts +219 -0
  18. package/lib/Socket/dugong.js +441 -0
  19. package/lib/Socket/groups.d.ts +32 -41
  20. package/lib/Socket/groups.js +5 -20
  21. package/lib/Socket/index.d.ts +64 -63
  22. package/lib/Socket/index.js +2 -2
  23. package/lib/Socket/messages-recv.js +65 -9
  24. package/lib/Socket/messages-send.d.ts +47 -49
  25. package/lib/Socket/messages-send.js +312 -379
  26. package/lib/Socket/newsletter.d.ts +37 -39
  27. package/lib/Socket/newsletter.js +40 -54
  28. package/lib/Socket/registration.d.ts +267 -0
  29. package/lib/Socket/registration.js +166 -0
  30. package/lib/Socket/socket.d.ts +10 -10
  31. package/lib/Socket/socket.js +32 -39
  32. package/lib/Socket/socket.js.bak +630 -0
  33. package/lib/Socket/usync.d.ts +3 -3
  34. package/lib/Store/index.d.ts +2 -1
  35. package/lib/Store/index.js +3 -1
  36. package/lib/Store/make-cache-manager-store.d.ts +13 -0
  37. package/lib/Store/make-cache-manager-store.js +83 -0
  38. package/lib/Store/make-in-memory-store.d.ts +24 -24
  39. package/lib/Store/make-in-memory-store.js +11 -13
  40. package/lib/Store/make-ordered-dictionary.d.ts +1 -1
  41. package/lib/Store/make-ordered-dictionary.js +2 -2
  42. package/lib/Types/Auth.d.ts +7 -0
  43. package/lib/Types/Call.d.ts +1 -1
  44. package/lib/Types/Chat.d.ts +7 -14
  45. package/lib/Types/Contact.d.ts +1 -5
  46. package/lib/Types/Events.d.ts +2 -44
  47. package/lib/Types/GroupMetadata.d.ts +2 -11
  48. package/lib/Types/Label.js +1 -1
  49. package/lib/Types/LabelAssociation.js +1 -1
  50. package/lib/Types/Message.d.ts +21 -148
  51. package/lib/Types/Message.js +2 -0
  52. package/lib/Types/Newsletter.d.ts +13 -0
  53. package/lib/Types/Newsletter.js +17 -3
  54. package/lib/Types/Socket.d.ts +9 -17
  55. package/lib/Types/index.d.ts +1 -8
  56. package/lib/Types/index.js +2 -2
  57. package/lib/Utils/auth-utils.d.ts +3 -3
  58. package/lib/Utils/auth-utils.js +13 -6
  59. package/lib/Utils/business.js +2 -2
  60. package/lib/Utils/chat-utils.d.ts +16 -15
  61. package/lib/Utils/chat-utils.js +35 -36
  62. package/lib/Utils/crypto.d.ts +16 -15
  63. package/lib/Utils/crypto.js +29 -71
  64. package/lib/Utils/decode-wa-message.d.ts +6 -22
  65. package/lib/Utils/decode-wa-message.js +56 -65
  66. package/lib/Utils/event-buffer.d.ts +2 -2
  67. package/lib/Utils/event-buffer.js +7 -11
  68. package/lib/Utils/generics.d.ts +20 -17
  69. package/lib/Utils/generics.js +23 -73
  70. package/lib/Utils/history.d.ts +0 -4
  71. package/lib/Utils/history.js +6 -4
  72. package/lib/Utils/link-preview.d.ts +2 -2
  73. package/lib/Utils/link-preview.js +1 -34
  74. package/lib/Utils/logger.d.ts +3 -10
  75. package/lib/Utils/lt-hash.d.ts +2 -2
  76. package/lib/Utils/lt-hash.js +6 -6
  77. package/lib/Utils/make-mutex.d.ts +2 -2
  78. package/lib/Utils/messages-media.d.ts +24 -28
  79. package/lib/Utils/messages-media.js +115 -263
  80. package/lib/Utils/messages.d.ts +10 -8
  81. package/lib/Utils/messages.js +72 -298
  82. package/lib/Utils/noise-handler.d.ts +12 -10
  83. package/lib/Utils/noise-handler.js +23 -18
  84. package/lib/Utils/process-message.d.ts +4 -5
  85. package/lib/Utils/process-message.js +23 -74
  86. package/lib/Utils/signal.d.ts +1 -2
  87. package/lib/Utils/signal.js +35 -37
  88. package/lib/Utils/use-multi-file-auth-state.d.ts +1 -0
  89. package/lib/Utils/use-multi-file-auth-state.js +6 -51
  90. package/lib/Utils/validate-connection.d.ts +4 -3
  91. package/lib/Utils/validate-connection.js +52 -20
  92. package/lib/WABinary/constants.d.ts +4 -4
  93. package/lib/WABinary/constants.js +13 -1276
  94. package/lib/WABinary/decode.d.ts +4 -3
  95. package/lib/WABinary/decode.js +13 -26
  96. package/lib/WABinary/encode.d.ts +2 -1
  97. package/lib/WABinary/encode.js +17 -39
  98. package/lib/WABinary/generic-utils.d.ts +3 -1
  99. package/lib/WABinary/generic-utils.js +85 -2
  100. package/lib/WABinary/jid-utils.d.ts +5 -10
  101. package/lib/WABinary/jid-utils.js +5 -26
  102. package/lib/WAM/BinaryInfo.d.ts +11 -2
  103. package/lib/WAM/encode.d.ts +2 -1
  104. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +1 -1
  105. package/lib/index.d.ts +2 -6
  106. package/lib/index.js +7 -22
  107. package/lib/index.js.bak +37 -0
  108. package/package.json +103 -111
  109. package/LICENSE +0 -21
  110. package/WAProto/GenerateStatics.sh +0 -4
  111. package/WAProto/WAProto.proto +0 -4775
  112. package/WAProto/index.d.ts +0 -55057
  113. package/WAProto/index.ts.ts +0 -53473
  114. package/WAProto/p.html +0 -1
  115. package/lib/WABinary/jid-utils.js.bak +0 -83
  116. /package/lib/Socket/Client/{types.js → abstract-socket-client.js} +0 -0
@@ -15,47 +15,23 @@ 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 () {
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 };
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;
37
24
  };
38
25
  Object.defineProperty(exports, "__esModule", { value: true });
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;
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;
47
27
  const boom_1 = require("@hapi/boom");
48
- const axios_1 = __importDefault(require("axios"));
49
- const form_data_1 = __importDefault(require("form-data"));
50
- const cheerio = __importStar(require("cheerio"));
28
+ const child_process_1 = require("child_process");
51
29
  const Crypto = __importStar(require("crypto"));
52
30
  const events_1 = require("events");
53
31
  const fs_1 = require("fs");
54
32
  const os_1 = require("os");
55
33
  const path_1 = require("path");
56
- const jimp_1 = __importDefault(require("jimp"));
57
34
  const stream_1 = require("stream");
58
- const child_process_1 = require("child_process");
59
35
  const WAProto_1 = require("../../WAProto");
60
36
  const Defaults_1 = require("../Defaults");
61
37
  const WABinary_1 = require("../WABinary");
@@ -65,11 +41,13 @@ const getTmpFilesDirectory = () => (0, os_1.tmpdir)();
65
41
  const getImageProcessingLibrary = async () => {
66
42
  const [_jimp, sharp] = await Promise.all([
67
43
  (async () => {
68
- const jimp = await (Promise.resolve().then(() => __importStar(require('jimp'))).catch(() => { }));
44
+ const jimp = await (import('jimp')
45
+ .catch(() => { }));
69
46
  return jimp;
70
47
  })(),
71
48
  (async () => {
72
- const sharp = await (Promise.resolve().then(() => __importStar(require('sharp'))).catch(() => { }));
49
+ const sharp = await (import('sharp')
50
+ .catch(() => { }));
73
51
  return sharp;
74
52
  })()
75
53
  ]);
@@ -88,7 +66,7 @@ const hkdfInfoKey = (type) => {
88
66
  };
89
67
  exports.hkdfInfoKey = hkdfInfoKey;
90
68
  /** generates all the keys required to encrypt/decrypt & sign a media message */
91
- async function getMediaKeys(buffer, mediaType) {
69
+ function getMediaKeys(buffer, mediaType) {
92
70
  if (!buffer) {
93
71
  throw new boom_1.Boom('Cannot derive from empty media key');
94
72
  }
@@ -96,183 +74,26 @@ async function getMediaKeys(buffer, mediaType) {
96
74
  buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64');
97
75
  }
98
76
  // expand using HKDF to 112 bytes, also pass in the relevant app info
99
- const expandedMediaKey = await (0, crypto_1.hkdf)(buffer, 112, { info: (0, exports.hkdfInfoKey)(mediaType) });
77
+ const expandedMediaKey = (0, crypto_1.hkdf)(buffer, 112, { info: (0, exports.hkdfInfoKey)(mediaType) });
100
78
  return {
101
79
  iv: expandedMediaKey.slice(0, 16),
102
80
  cipherKey: expandedMediaKey.slice(16, 48),
103
81
  macKey: expandedMediaKey.slice(48, 80),
104
82
  };
105
83
  }
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
- }
193
- }
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;
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);
230
91
  }
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
- }
92
+ else {
93
+ resolve();
239
94
  }
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
- });
273
95
  });
274
- };
275
- exports.extractVideoThumb = extractVideoThumb;
96
+ });
276
97
  const extractImageThumb = async (bufferOrFilePath, width = 32) => {
277
98
  var _a, _b;
278
99
  if (bufferOrFilePath instanceof stream_1.Readable) {
@@ -321,8 +142,8 @@ const encodeBase64EncodedStringForUpload = (b64) => (encodeURIComponent(b64
321
142
  .replace(/\=+$/, '')));
322
143
  exports.encodeBase64EncodedStringForUpload = encodeBase64EncodedStringForUpload;
323
144
  const generateProfilePicture = async (mediaUpload) => {
145
+ var _a, _b;
324
146
  let bufferOrFilePath;
325
- let img;
326
147
  if (Buffer.isBuffer(mediaUpload)) {
327
148
  bufferOrFilePath = mediaUpload;
328
149
  }
@@ -332,11 +153,29 @@ const generateProfilePicture = async (mediaUpload) => {
332
153
  else {
333
154
  bufferOrFilePath = await (0, exports.toBuffer)(mediaUpload.stream);
334
155
  }
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);
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
+ }
340
179
  return {
341
180
  img: await img,
342
181
  };
@@ -349,25 +188,32 @@ const mediaMessageSHA256B64 = (message) => {
349
188
  };
350
189
  exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
351
190
  async function getAudioDuration(buffer) {
352
- const musicMetadata = await Promise.resolve().then(() => __importStar(require('music-metadata')));
191
+ const musicMetadata = await import('music-metadata');
353
192
  let metadata;
354
- const options = {
355
- duration: true
356
- };
357
193
  if (Buffer.isBuffer(buffer)) {
358
- metadata = await musicMetadata.parseBuffer(buffer, undefined, options);
194
+ metadata = await musicMetadata.parseBuffer(buffer, undefined, { duration: true });
359
195
  }
360
196
  else if (typeof buffer === 'string') {
361
- metadata = await musicMetadata.parseFile(buffer, options);
197
+ const rStream = (0, fs_1.createReadStream)(buffer);
198
+ try {
199
+ metadata = await musicMetadata.parseStream(rStream, undefined, { duration: true });
200
+ }
201
+ finally {
202
+ rStream.destroy();
203
+ }
362
204
  }
363
205
  else {
364
- metadata = await musicMetadata.parseStream(buffer, undefined, options);
206
+ metadata = await musicMetadata.parseStream(buffer, undefined, { duration: true });
365
207
  }
366
208
  return metadata.format.duration;
367
209
  }
210
+ exports.getAudioDuration = getAudioDuration;
211
+ /**
212
+ referenced from and modifying https://github.com/wppconnect-team/wa-js/blob/main/src/chat/functions/prepareAudioWaveform.ts
213
+ */
368
214
  async function getAudioWaveform(buffer, logger) {
369
215
  try {
370
- const { default: decoder } = await eval('import(\'audio-decode\')');
216
+ const audioDecode = (buffer) => import('audio-decode').then(({ default: audioDecode }) => audioDecode(buffer));
371
217
  let audioData;
372
218
  if (Buffer.isBuffer(buffer)) {
373
219
  audioData = buffer;
@@ -379,21 +225,23 @@ async function getAudioWaveform(buffer, logger) {
379
225
  else {
380
226
  audioData = await (0, exports.toBuffer)(buffer);
381
227
  }
382
- const audioBuffer = await decoder(audioData);
383
- const rawData = audioBuffer.getChannelData(0);
384
- const samples = 64;
385
- const blockSize = Math.floor(rawData.length / samples);
228
+ const audioBuffer = await audioDecode(audioData);
229
+ const rawData = audioBuffer.getChannelData(0); // We only need to work with one channel of data
230
+ const samples = 64; // Number of samples we want to have in our final data set
231
+ const blockSize = Math.floor(rawData.length / samples); // the number of samples in each subdivision
386
232
  const filteredData = [];
387
233
  for (let i = 0; i < samples; i++) {
388
- const blockStart = blockSize * i;
234
+ const blockStart = blockSize * i; // the location of the first sample in the block
389
235
  let sum = 0;
390
236
  for (let j = 0; j < blockSize; j++) {
391
- sum = sum + Math.abs(rawData[blockStart + j]);
237
+ sum = sum + Math.abs(rawData[blockStart + j]); // find the sum of all the samples in the block
392
238
  }
393
- filteredData.push(sum / blockSize);
239
+ filteredData.push(sum / blockSize); // divide the sum by the block size to get the average
394
240
  }
241
+ // This guarantees that the largest data point will be set to 1, and the rest of the data will scale proportionally.
395
242
  const multiplier = Math.pow(Math.max(...filteredData), -1);
396
243
  const normalizedData = filteredData.map((n) => n * multiplier);
244
+ // Generate waveform like WhatsApp
397
245
  const waveform = new Uint8Array(normalizedData.map((n) => Math.floor(100 * n)));
398
246
  return waveform;
399
247
  }
@@ -401,6 +249,7 @@ async function getAudioWaveform(buffer, logger) {
401
249
  logger === null || logger === void 0 ? void 0 : logger.debug('Failed to generate waveform: ' + e);
402
250
  }
403
251
  }
252
+ exports.getAudioWaveform = getAudioWaveform;
404
253
  const toReadable = (buffer) => {
405
254
  const readable = new stream_1.Readable({ read: () => { } });
406
255
  readable.push(buffer);
@@ -446,28 +295,12 @@ async function generateThumbnail(file, mediaType, options) {
446
295
  }
447
296
  }
448
297
  else if (mediaType === 'video') {
298
+ const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
449
299
  try {
450
- let videoPath = file;
451
- if (Buffer.isBuffer(file) || file instanceof stream_1.Readable) {
452
- videoPath = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.mp4');
453
- const buffer = Buffer.isBuffer(file) ? file : await (0, exports.toBuffer)(file);
454
- await fs_1.promises.writeFile(videoPath, buffer);
455
- }
456
- const thumbnailBuffer = await (0, exports.extractVideoThumb)(videoPath);
457
- const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.jpg');
458
- await fs_1.promises.writeFile(imgFilename, thumbnailBuffer);
459
- const { buffer: processedThumbnailBuffer, original } = await (0, exports.extractImageThumb)(imgFilename);
460
- thumbnail = processedThumbnailBuffer.toString('base64');
461
- if (original.width && original.height) {
462
- originalImageDimensions = {
463
- width: original.width,
464
- height: original.height,
465
- };
466
- }
300
+ await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
301
+ const buff = await fs_1.promises.readFile(imgFilename);
302
+ thumbnail = buff.toString('base64');
467
303
  await fs_1.promises.unlink(imgFilename);
468
- if (videoPath !== file) {
469
- await fs_1.promises.unlink(videoPath);
470
- }
471
304
  }
472
305
  catch (err) {
473
306
  (_a = options.logger) === null || _a === void 0 ? void 0 : _a.debug('could not generate video thumb: ' + err);
@@ -478,8 +311,10 @@ async function generateThumbnail(file, mediaType, options) {
478
311
  originalImageDimensions
479
312
  };
480
313
  }
314
+ exports.generateThumbnail = generateThumbnail;
481
315
  const getHttpStream = async (url, options = {}) => {
482
- const fetched = await axios_1.default.get(url.toString(), { ...options, responseType: 'stream' });
316
+ const { default: axios } = await import('axios');
317
+ const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
483
318
  return fetched.data;
484
319
  };
485
320
  exports.getHttpStream = getHttpStream;
@@ -494,7 +329,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
494
329
  bodyPath = media.url;
495
330
  }
496
331
  else if (saveOriginalFileIfRequired) {
497
- bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)());
332
+ bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
498
333
  (0, fs_1.writeFileSync)(bodyPath, buffer);
499
334
  didSaveToTmpPath = true;
500
335
  }
@@ -513,6 +348,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
513
348
  };
514
349
  }
515
350
  catch (error) {
351
+ // destroy all streams with error
516
352
  stream.destroy();
517
353
  if (didSaveToTmpPath) {
518
354
  try {
@@ -530,7 +366,7 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
530
366
  const { stream, type } = await (0, exports.getStream)(media, opts);
531
367
  logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
532
368
  const mediaKey = Crypto.randomBytes(32);
533
- const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
369
+ const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
534
370
  const encWriteStream = new stream_1.Readable({ read: () => { } });
535
371
  let bodyPath;
536
372
  let writeStream;
@@ -539,7 +375,7 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
539
375
  bodyPath = media.url;
540
376
  }
541
377
  else if (saveOriginalFileIfRequired) {
542
- bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)());
378
+ bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
543
379
  writeStream = (0, fs_1.createWriteStream)(bodyPath);
544
380
  didSaveToTmpPath = true;
545
381
  }
@@ -588,6 +424,7 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
588
424
  };
589
425
  }
590
426
  catch (error) {
427
+ // destroy all streams with error
591
428
  encWriteStream.destroy();
592
429
  writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
593
430
  aes.destroy();
@@ -619,20 +456,21 @@ const toSmallestChunkSize = (num) => {
619
456
  };
620
457
  const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
621
458
  exports.getUrlFromDirectPath = getUrlFromDirectPath;
622
- const downloadContentFromMessage = async ({ mediaKey, directPath, url }, type, opts = {}) => {
623
- const isValidMediaUrl = url === null || url === void 0 ? void 0 : url.startsWith('https://mmg.whatsapp.net/');
624
- const downloadUrl = isValidMediaUrl ? url : (0, exports.getUrlFromDirectPath)(directPath);
625
- if (!downloadUrl) {
626
- throw new boom_1.Boom('No valid media URL or directPath present in message', { statusCode: 400 });
627
- }
628
- const keys = await getMediaKeys(mediaKey, type);
459
+ const downloadContentFromMessage = ({ mediaKey, directPath, url }, type, opts = {}) => {
460
+ const downloadUrl = url || (0, exports.getUrlFromDirectPath)(directPath);
461
+ const keys = getMediaKeys(mediaKey, type);
629
462
  return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
630
463
  };
631
464
  exports.downloadContentFromMessage = downloadContentFromMessage;
465
+ /**
466
+ * Decrypts and downloads an AES256-CBC encrypted file given the keys.
467
+ * Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
468
+ * */
632
469
  const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
633
470
  let bytesFetched = 0;
634
471
  let startChunk = 0;
635
472
  let firstBlockIsIV = false;
473
+ // if a start byte is specified -- then we need to fetch the previous chunk as that will form the IV
636
474
  if (startByte) {
637
475
  const chunk = toSmallestChunkSize(startByte || 0);
638
476
  if (chunk) {
@@ -652,6 +490,7 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
652
490
  headers.Range += endChunk;
653
491
  }
654
492
  }
493
+ // download the message
655
494
  const fetched = await (0, exports.getHttpStream)(downloadUrl, {
656
495
  ...options || {},
657
496
  headers,
@@ -684,6 +523,8 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
684
523
  data = data.slice(AES_CHUNK_SIZE);
685
524
  }
686
525
  aes = Crypto.createDecipheriv('aes-256-cbc', cipherKey, ivValue);
526
+ // if an end byte that is not EOF is specified
527
+ // stop auto padding (PKCS7) -- otherwise throws an error for decryption
687
528
  if (endByte) {
688
529
  aes.setAutoPadding(false);
689
530
  }
@@ -724,9 +565,12 @@ function extensionForMediaMessage(message) {
724
565
  }
725
566
  return extension;
726
567
  }
568
+ exports.extensionForMediaMessage = extensionForMediaMessage;
727
569
  const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
728
570
  return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
729
571
  var _a, _b;
572
+ const { default: axios } = await import('axios');
573
+ // send a query JSON to obtain the url & auth token to upload our media
730
574
  let uploadInfo = await refreshMediaConn(false);
731
575
  let urls;
732
576
  const hosts = [...customUploadHosts, ...uploadInfo.hosts];
@@ -744,14 +588,14 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
744
588
  }
745
589
  for (const { hostname, maxContentLengthBytes } of hosts) {
746
590
  logger.debug(`uploading to "${hostname}"`);
747
- const auth = encodeURIComponent(uploadInfo.auth);
591
+ const auth = encodeURIComponent(uploadInfo.auth); // the auth token
748
592
  const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
749
593
  let result;
750
594
  try {
751
595
  if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
752
596
  throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
753
597
  }
754
- const body = await axios_1.default.post(url, reqBody, {
598
+ const body = await axios.post(url, reqBody, {
755
599
  ...options,
756
600
  headers: {
757
601
  ...options.headers || {},
@@ -779,7 +623,7 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
779
623
  }
780
624
  }
781
625
  catch (error) {
782
- if (axios_1.default.isAxiosError(error)) {
626
+ if (axios.isAxiosError(error)) {
783
627
  result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
784
628
  }
785
629
  const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
@@ -796,11 +640,14 @@ exports.getWAUploadToServer = getWAUploadToServer;
796
640
  const getMediaRetryKey = (mediaKey) => {
797
641
  return (0, crypto_1.hkdf)(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
798
642
  };
799
- const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
643
+ /**
644
+ * Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
645
+ */
646
+ const encryptMediaRetryRequest = (key, mediaKey, meId) => {
800
647
  const recp = { stanzaId: key.id };
801
648
  const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
802
649
  const iv = Crypto.randomBytes(12);
803
- const retryKey = await getMediaRetryKey(mediaKey);
650
+ const retryKey = getMediaRetryKey(mediaKey);
804
651
  const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
805
652
  const req = {
806
653
  tag: 'receipt',
@@ -810,6 +657,9 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
810
657
  type: 'server-error'
811
658
  },
812
659
  content: [
660
+ // this encrypt node is actually pretty useless
661
+ // the media is returned even without this node
662
+ // keeping it here to maintain parity with WA Web
813
663
  {
814
664
  tag: 'encrypt',
815
665
  attrs: {},
@@ -823,6 +673,7 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
823
673
  attrs: {
824
674
  jid: key.remoteJid,
825
675
  'from_me': (!!key.fromMe).toString(),
676
+ // @ts-ignore
826
677
  participant: key.participant || undefined
827
678
  }
828
679
  }
@@ -860,8 +711,8 @@ const decodeMediaRetryNode = (node) => {
860
711
  return event;
861
712
  };
862
713
  exports.decodeMediaRetryNode = decodeMediaRetryNode;
863
- const decryptMediaRetryData = async ({ ciphertext, iv }, mediaKey, msgId) => {
864
- const retryKey = await getMediaRetryKey(mediaKey);
714
+ const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
715
+ const retryKey = getMediaRetryKey(mediaKey);
865
716
  const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
866
717
  return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
867
718
  };
@@ -874,6 +725,7 @@ const MEDIA_RETRY_STATUS_MAP = {
874
725
  [WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
875
726
  [WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
876
727
  };
728
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
877
729
  function __importStar(arg0) {
878
730
  throw new Error('Function not implemented.');
879
- }
731
+ }