riftcore 1.4.5 → 1.4.7

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 (115) hide show
  1. package/README.md +422 -0
  2. package/WAProto/index.js +79296 -118676
  3. package/example.js +13 -0
  4. package/lib/Defaults/baileys-version.json +2 -2
  5. package/lib/Defaults/index.d.ts +7 -16
  6. package/lib/Defaults/index.js +103 -90
  7. package/lib/Defaults/phonenumber-mcc.json +223 -0
  8. package/lib/Socket/Client/{types.d.ts → abstract-socket-client.d.ts} +2 -1
  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 -2
  14. package/lib/Socket/Client/{websocket.js → web-socket-client.js} +5 -54
  15. package/lib/Socket/business.d.ts +58 -59
  16. package/lib/Socket/chats.d.ts +27 -29
  17. package/lib/Socket/chats.js +90 -97
  18. package/lib/Socket/erlanggaofficial.d.ts +219 -0
  19. package/lib/Socket/erlanggaofficial.js +439 -0
  20. package/lib/Socket/groups.d.ts +32 -41
  21. package/lib/Socket/groups.js +5 -20
  22. package/lib/Socket/index.d.ts +64 -63
  23. package/lib/Socket/index.js +2 -2
  24. package/lib/Socket/messages-recv.js +65 -9
  25. package/lib/Socket/messages-send.d.ts +47 -49
  26. package/lib/Socket/messages-send.js +377 -541
  27. package/lib/Socket/newsletter.d.ts +37 -39
  28. package/lib/Socket/newsletter.js +41 -73
  29. package/lib/Socket/registration.d.ts +267 -0
  30. package/lib/Socket/registration.js +166 -0
  31. package/lib/Socket/socket.d.ts +43 -270
  32. package/lib/Socket/socket.js +38 -62
  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 +15 -27
  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 +157 -406
  80. package/lib/Utils/messages.d.ts +10 -13
  81. package/lib/Utils/messages.js +48 -345
  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 +25 -108
  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 +66 -90
  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 +10 -2
  100. package/lib/WABinary/jid-utils.d.ts +5 -11
  101. package/lib/WABinary/jid-utils.js +5 -28
  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 +15 -31
  107. package/package.json +51 -39
  108. package/WAProto/GenerateStatics.sh +0 -4
  109. package/WAProto/WAProto.proto +0 -4775
  110. package/WAProto/index.d.ts +0 -55057
  111. package/WAProto/index.ts.ts +0 -53473
  112. package/lib/Socket/setup.js +0 -481
  113. package/lib/Socket/setup.ts +0 -623
  114. package/lib/WABinary/jid-utils.js.bak +0 -83
  115. /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,138 +188,68 @@ const mediaMessageSHA256B64 = (message) => {
349
188
  };
350
189
  exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
351
190
  async function getAudioDuration(buffer) {
352
- try {
353
- const { PassThrough } = require('stream');
354
- const ff = require('fluent-ffmpeg');
355
-
356
- return await new Promise((resolve, reject) => {
357
- const inputStream = new PassThrough();
358
- inputStream.end(buffer);
359
-
360
- ff(inputStream)
361
- .ffprobe((err, data) => {
362
- if (err) reject(err);
363
- else resolve(data.format.duration);
364
- });
365
- });
366
- } catch (error) {
367
- const musicMetadata = await import('music-metadata');
368
- let metadata;
369
- if (Buffer.isBuffer(buffer)) {
370
- metadata = await musicMetadata.parseBuffer(buffer, undefined, {
371
- duration: true
372
- });
373
- } else if (typeof buffer === 'string') {
374
- const rStream = (0, fs_1.createReadStream)(buffer);
375
- try {
376
- metadata = await musicMetadata.parseStream(rStream, undefined, {
377
- duration: true
378
- });
379
- } finally {
380
- rStream.destroy();
381
- }
382
- } else {
383
- metadata = await musicMetadata.parseStream(buffer, undefined, {
384
- duration: true
385
- });
191
+ const musicMetadata = await import('music-metadata');
192
+ let metadata;
193
+ if (Buffer.isBuffer(buffer)) {
194
+ metadata = await musicMetadata.parseBuffer(buffer, undefined, { duration: true });
195
+ }
196
+ else if (typeof buffer === 'string') {
197
+ const rStream = (0, fs_1.createReadStream)(buffer);
198
+ try {
199
+ metadata = await musicMetadata.parseStream(rStream, undefined, { duration: true });
386
200
  }
387
- return metadata.format.duration;
201
+ finally {
202
+ rStream.destroy();
203
+ }
204
+ }
205
+ else {
206
+ metadata = await musicMetadata.parseStream(buffer, undefined, { duration: true });
388
207
  }
208
+ return metadata.format.duration;
389
209
  }
390
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
+ */
391
214
  async function getAudioWaveform(buffer, logger) {
392
215
  try {
393
- const { PassThrough } = require('stream');
394
- const ff = require('fluent-ffmpeg');
395
-
216
+ const audioDecode = (buffer) => import('audio-decode').then(({ default: audioDecode }) => audioDecode(buffer));
396
217
  let audioData;
397
218
  if (Buffer.isBuffer(buffer)) {
398
219
  audioData = buffer;
399
- } else if (typeof buffer === 'string') {
400
- const rStream = require('fs').createReadStream(buffer);
401
- audioData = await exports.toBuffer(rStream);
402
- } else {
403
- audioData = await exports.toBuffer(buffer);
404
220
  }
405
-
406
- return await new Promise((resolve, reject) => {
407
- const inputStream = new PassThrough();
408
- inputStream.end(audioData);
409
- const chunks = [];
410
- const bars = 64;
411
-
412
- ff(inputStream)
413
- .audioChannels(1)
414
- .audioFrequency(16000)
415
- .format('s16le')
416
- .on('error', reject)
417
- .on('end', () => {
418
- const rawData = Buffer.concat(chunks);
419
- const samples = rawData.length / 2;
420
- const amplitudes = [];
421
-
422
- for (let i = 0; i < samples; i++) {
423
- amplitudes.push(Math.abs(rawData.readInt16LE(i * 2)) / 32768);
424
- }
425
-
426
- const blockSize = Math.floor(amplitudes.length / bars);
427
- const avg = [];
428
- for (let i = 0; i < bars; i++) {
429
- const block = amplitudes.slice(i * blockSize, (i + 1) * blockSize);
430
- avg.push(block.reduce((a, b) => a + b, 0) / block.length);
431
- }
432
-
433
- const max = Math.max(...avg);
434
- const normalized = avg.map(v => Math.floor((v / max) * 100));
435
- resolve(new Uint8Array(normalized));
436
- })
437
- .pipe()
438
- .on('data', chunk => chunks.push(chunk));
439
- });
440
- } catch (e) {
441
- logger?.debug(e);
221
+ else if (typeof buffer === 'string') {
222
+ const rStream = (0, fs_1.createReadStream)(buffer);
223
+ audioData = await (0, exports.toBuffer)(rStream);
224
+ }
225
+ else {
226
+ audioData = await (0, exports.toBuffer)(buffer);
227
+ }
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
232
+ const filteredData = [];
233
+ for (let i = 0; i < samples; i++) {
234
+ const blockStart = blockSize * i; // the location of the first sample in the block
235
+ let sum = 0;
236
+ for (let j = 0; j < blockSize; j++) {
237
+ sum = sum + Math.abs(rawData[blockStart + j]); // find the sum of all the samples in the block
238
+ }
239
+ filteredData.push(sum / blockSize); // divide the sum by the block size to get the average
240
+ }
241
+ // This guarantees that the largest data point will be set to 1, and the rest of the data will scale proportionally.
242
+ const multiplier = Math.pow(Math.max(...filteredData), -1);
243
+ const normalizedData = filteredData.map((n) => n * multiplier);
244
+ // Generate waveform like WhatsApp
245
+ const waveform = new Uint8Array(normalizedData.map((n) => Math.floor(100 * n)));
246
+ return waveform;
442
247
  }
443
- }
444
- exports.getAudioWaveform = getAudioWaveform;
445
- async function convertToOpusBuffer(buffer, logger) {
446
- try {
447
- const { PassThrough } = require('stream');
448
- const ff = require('fluent-ffmpeg');
449
-
450
- return await new Promise((resolve, reject) => {
451
- const inStream = new PassThrough();
452
- const outStream = new PassThrough();
453
- const chunks = [];
454
- inStream.end(buffer);
455
-
456
- ff(inStream)
457
- .noVideo()
458
- .audioCodec('libopus')
459
- .format('ogg')
460
- .audioBitrate('48k')
461
- .audioChannels(1)
462
- .audioFrequency(48000)
463
- .outputOptions([
464
- '-vn',
465
- '-b:a 64k',
466
- '-ac 2',
467
- '-ar 48000',
468
- '-map_metadata', '-1',
469
- '-application', 'voip'
470
- ])
471
- .on('error', reject)
472
- .on('end', () => resolve(Buffer.concat(chunks)))
473
- .pipe(outStream, {
474
- end: true
475
- });
476
- outStream.on('data', c => chunks.push(c));
477
- });
478
- } catch (e) {
479
- logger?.debug(e);
480
- throw e;
248
+ catch (e) {
249
+ logger === null || logger === void 0 ? void 0 : logger.debug('Failed to generate waveform: ' + e);
481
250
  }
482
251
  }
483
- exports.convertToOpusBuffer = convertToOpusBuffer;
252
+ exports.getAudioWaveform = getAudioWaveform;
484
253
  const toReadable = (buffer) => {
485
254
  const readable = new stream_1.Readable({ read: () => { } });
486
255
  readable.push(buffer);
@@ -526,28 +295,12 @@ async function generateThumbnail(file, mediaType, options) {
526
295
  }
527
296
  }
528
297
  else if (mediaType === 'video') {
298
+ const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
529
299
  try {
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
- }
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');
547
303
  await fs_1.promises.unlink(imgFilename);
548
- if (videoPath !== file) {
549
- await fs_1.promises.unlink(videoPath);
550
- }
551
304
  }
552
305
  catch (err) {
553
306
  (_a = options.logger) === null || _a === void 0 ? void 0 : _a.debug('could not generate video thumb: ' + err);
@@ -558,8 +311,10 @@ async function generateThumbnail(file, mediaType, options) {
558
311
  originalImageDimensions
559
312
  };
560
313
  }
314
+ exports.generateThumbnail = generateThumbnail;
561
315
  const getHttpStream = async (url, options = {}) => {
562
- 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' });
563
318
  return fetched.data;
564
319
  };
565
320
  exports.getHttpStream = getHttpStream;
@@ -574,7 +329,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
574
329
  bodyPath = media.url;
575
330
  }
576
331
  else if (saveOriginalFileIfRequired) {
577
- bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)());
332
+ bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
578
333
  (0, fs_1.writeFileSync)(bodyPath, buffer);
579
334
  didSaveToTmpPath = true;
580
335
  }
@@ -593,6 +348,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
593
348
  };
594
349
  }
595
350
  catch (error) {
351
+ // destroy all streams with error
596
352
  stream.destroy();
597
353
  if (didSaveToTmpPath) {
598
354
  try {
@@ -606,51 +362,34 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
606
362
  }
607
363
  };
608
364
  exports.prepareStream = prepareStream;
609
- const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, isPtt, forceOpus } = {}) => {
365
+ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
610
366
  const { stream, type } = await (0, exports.getStream)(media, opts);
611
- logger?.debug('fetched media stream');
612
-
613
- let finalStream = stream;
614
-
615
- // Tambahan untuk konversi audio jadi Opus (PTT)
616
- if (mediaType === 'audio' && (isPtt === true || forceOpus === true)) {
617
- try {
618
- const buffer = await (0, exports.toBuffer)(stream);
619
- const opusBuffer = await exports.convertToOpusBuffer(buffer, logger);
620
- finalStream = (0, exports.toReadable)(opusBuffer);
621
- logger?.debug('converted audio to Opus');
622
- } catch (error) {
623
- logger?.error('failed to convert audio to Opus, fallback to original stream');
624
- const { stream: newStream } = await (0, exports.getStream)(media, opts);
625
- finalStream = newStream;
626
- }
627
- }
628
-
367
+ logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
629
368
  const mediaKey = Crypto.randomBytes(32);
630
- const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
369
+ const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
631
370
  const encWriteStream = new stream_1.Readable({ read: () => { } });
632
371
  let bodyPath;
633
372
  let writeStream;
634
373
  let didSaveToTmpPath = false;
635
-
636
374
  if (type === 'file') {
637
375
  bodyPath = media.url;
638
- } else if (saveOriginalFileIfRequired) {
639
- bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)());
376
+ }
377
+ else if (saveOriginalFileIfRequired) {
378
+ bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
640
379
  writeStream = (0, fs_1.createWriteStream)(bodyPath);
641
380
  didSaveToTmpPath = true;
642
381
  }
643
-
644
382
  let fileLength = 0;
645
383
  const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
646
384
  let hmac = Crypto.createHmac('sha256', macKey).update(iv);
647
385
  let sha256Plain = Crypto.createHash('sha256');
648
386
  let sha256Enc = Crypto.createHash('sha256');
649
-
650
387
  try {
651
- for await (const data of finalStream) {
388
+ for await (const data of stream) {
652
389
  fileLength += data.length;
653
- if (type === 'remote' && (opts?.maxContentLength) && fileLength + data.length > opts.maxContentLength) {
390
+ if (type === 'remote'
391
+ && (opts === null || opts === void 0 ? void 0 : opts.maxContentLength)
392
+ && fileLength + data.length > opts.maxContentLength) {
654
393
  throw new boom_1.Boom(`content length exceeded when encrypting "${type}"`, {
655
394
  data: { media, type }
656
395
  });
@@ -663,20 +402,16 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
663
402
  }
664
403
  onChunk(aes.update(data));
665
404
  }
666
-
667
405
  onChunk(aes.final());
668
406
  const mac = hmac.digest().slice(0, 10);
669
407
  sha256Enc = sha256Enc.update(mac);
670
408
  const fileSha256 = sha256Plain.digest();
671
409
  const fileEncSha256 = sha256Enc.digest();
672
-
673
410
  encWriteStream.push(mac);
674
411
  encWriteStream.push(null);
675
- writeStream?.end();
676
- finalStream.destroy();
677
-
678
- logger?.debug('encrypted data successfully');
679
-
412
+ writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
413
+ stream.destroy();
414
+ logger === null || logger === void 0 ? void 0 : logger.debug('encrypted data successfully');
680
415
  return {
681
416
  mediaKey,
682
417
  encWriteStream,
@@ -687,25 +422,26 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
687
422
  fileLength,
688
423
  didSaveToTmpPath
689
424
  };
690
- } catch (error) {
425
+ }
426
+ catch (error) {
427
+ // destroy all streams with error
691
428
  encWriteStream.destroy();
692
- writeStream?.destroy();
429
+ writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
693
430
  aes.destroy();
694
431
  hmac.destroy();
695
432
  sha256Plain.destroy();
696
433
  sha256Enc.destroy();
697
- finalStream.destroy();
698
-
434
+ stream.destroy();
699
435
  if (didSaveToTmpPath) {
700
436
  try {
701
437
  await fs_1.promises.unlink(bodyPath);
702
- } catch (err) {
703
- logger?.error({ err }, 'failed to save to tmp path');
438
+ }
439
+ catch (err) {
440
+ logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
704
441
  }
705
442
  }
706
443
  throw error;
707
444
  }
708
-
709
445
  function onChunk(buff) {
710
446
  sha256Enc = sha256Enc.update(buff);
711
447
  hmac = hmac.update(buff);
@@ -720,20 +456,21 @@ const toSmallestChunkSize = (num) => {
720
456
  };
721
457
  const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
722
458
  exports.getUrlFromDirectPath = getUrlFromDirectPath;
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);
459
+ const downloadContentFromMessage = ({ mediaKey, directPath, url }, type, opts = {}) => {
460
+ const downloadUrl = url || (0, exports.getUrlFromDirectPath)(directPath);
461
+ const keys = getMediaKeys(mediaKey, type);
730
462
  return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
731
463
  };
732
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
+ * */
733
469
  const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
734
470
  let bytesFetched = 0;
735
471
  let startChunk = 0;
736
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
737
474
  if (startByte) {
738
475
  const chunk = toSmallestChunkSize(startByte || 0);
739
476
  if (chunk) {
@@ -753,6 +490,7 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
753
490
  headers.Range += endChunk;
754
491
  }
755
492
  }
493
+ // download the message
756
494
  const fetched = await (0, exports.getHttpStream)(downloadUrl, {
757
495
  ...options || {},
758
496
  headers,
@@ -785,6 +523,8 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
785
523
  data = data.slice(AES_CHUNK_SIZE);
786
524
  }
787
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
788
528
  if (endByte) {
789
529
  aes.setAutoPadding(false);
790
530
  }
@@ -825,9 +565,12 @@ function extensionForMediaMessage(message) {
825
565
  }
826
566
  return extension;
827
567
  }
568
+ exports.extensionForMediaMessage = extensionForMediaMessage;
828
569
  const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
829
570
  return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
830
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
831
574
  let uploadInfo = await refreshMediaConn(false);
832
575
  let urls;
833
576
  const hosts = [...customUploadHosts, ...uploadInfo.hosts];
@@ -845,14 +588,14 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
845
588
  }
846
589
  for (const { hostname, maxContentLengthBytes } of hosts) {
847
590
  logger.debug(`uploading to "${hostname}"`);
848
- const auth = encodeURIComponent(uploadInfo.auth);
591
+ const auth = encodeURIComponent(uploadInfo.auth); // the auth token
849
592
  const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
850
593
  let result;
851
594
  try {
852
595
  if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
853
596
  throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
854
597
  }
855
- const body = await axios_1.default.post(url, reqBody, {
598
+ const body = await axios.post(url, reqBody, {
856
599
  ...options,
857
600
  headers: {
858
601
  ...options.headers || {},
@@ -880,7 +623,7 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
880
623
  }
881
624
  }
882
625
  catch (error) {
883
- if (axios_1.default.isAxiosError(error)) {
626
+ if (axios.isAxiosError(error)) {
884
627
  result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
885
628
  }
886
629
  const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
@@ -897,11 +640,14 @@ exports.getWAUploadToServer = getWAUploadToServer;
897
640
  const getMediaRetryKey = (mediaKey) => {
898
641
  return (0, crypto_1.hkdf)(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
899
642
  };
900
- 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) => {
901
647
  const recp = { stanzaId: key.id };
902
648
  const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
903
649
  const iv = Crypto.randomBytes(12);
904
- const retryKey = await getMediaRetryKey(mediaKey);
650
+ const retryKey = getMediaRetryKey(mediaKey);
905
651
  const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
906
652
  const req = {
907
653
  tag: 'receipt',
@@ -911,6 +657,9 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
911
657
  type: 'server-error'
912
658
  },
913
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
914
663
  {
915
664
  tag: 'encrypt',
916
665
  attrs: {},
@@ -924,6 +673,7 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
924
673
  attrs: {
925
674
  jid: key.remoteJid,
926
675
  'from_me': (!!key.fromMe).toString(),
676
+ // @ts-ignore
927
677
  participant: key.participant || undefined
928
678
  }
929
679
  }
@@ -961,8 +711,8 @@ const decodeMediaRetryNode = (node) => {
961
711
  return event;
962
712
  };
963
713
  exports.decodeMediaRetryNode = decodeMediaRetryNode;
964
- const decryptMediaRetryData = async ({ ciphertext, iv }, mediaKey, msgId) => {
965
- const retryKey = await getMediaRetryKey(mediaKey);
714
+ const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
715
+ const retryKey = getMediaRetryKey(mediaKey);
966
716
  const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
967
717
  return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
968
718
  };
@@ -975,6 +725,7 @@ const MEDIA_RETRY_STATUS_MAP = {
975
725
  [WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
976
726
  [WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
977
727
  };
728
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
978
729
  function __importStar(arg0) {
979
730
  throw new Error('Function not implemented.');
980
- }
731
+ }