@queenanya/baileys 8.2.7 → 8.3.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 (105) hide show
  1. package/WAProto/index.d.ts +1590 -6
  2. package/WAProto/index.js +4635 -3
  3. package/engine-requirements.js +1 -1
  4. package/lib/Defaults/baileys-version.json +1 -1
  5. package/lib/Defaults/index.d.ts +1 -1
  6. package/lib/Defaults/index.js +4 -5
  7. package/lib/Signal/Group/ciphertext-message.d.ts +9 -0
  8. package/lib/Signal/Group/ciphertext-message.js +15 -0
  9. package/lib/Signal/Group/group-session-builder.d.ts +14 -0
  10. package/lib/Signal/Group/group-session-builder.js +64 -0
  11. package/lib/Signal/Group/group_cipher.d.ts +17 -0
  12. package/lib/Signal/Group/group_cipher.js +96 -0
  13. package/lib/Signal/Group/index.d.ts +11 -0
  14. package/lib/Signal/Group/index.js +57 -0
  15. package/lib/Signal/Group/keyhelper.d.ts +10 -0
  16. package/lib/Signal/Group/keyhelper.js +55 -0
  17. package/lib/Signal/Group/queue-job.d.ts +1 -0
  18. package/lib/Signal/Group/queue-job.js +57 -0
  19. package/lib/Signal/Group/sender-chain-key.d.ts +13 -0
  20. package/lib/Signal/Group/sender-chain-key.js +34 -0
  21. package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -0
  22. package/lib/Signal/Group/sender-key-distribution-message.js +66 -0
  23. package/lib/Signal/Group/sender-key-message.d.ts +18 -0
  24. package/lib/Signal/Group/sender-key-message.js +69 -0
  25. package/lib/Signal/Group/sender-key-name.d.ts +17 -0
  26. package/lib/Signal/Group/sender-key-name.js +51 -0
  27. package/lib/Signal/Group/sender-key-record.d.ts +30 -0
  28. package/lib/Signal/Group/sender-key-record.js +53 -0
  29. package/lib/Signal/Group/sender-key-state.d.ts +38 -0
  30. package/lib/Signal/Group/sender-key-state.js +99 -0
  31. package/lib/Signal/Group/sender-message-key.d.ts +11 -0
  32. package/{WASignalGroup/sender_message_key.js → lib/Signal/Group/sender-message-key.js} +6 -16
  33. package/lib/Signal/libsignal.js +33 -20
  34. package/lib/Socket/Client/types.d.ts +1 -0
  35. package/lib/Socket/Client/websocket.d.ts +1 -0
  36. package/lib/Socket/Client/websocket.js +11 -1
  37. package/lib/Socket/business.d.ts +5 -8
  38. package/lib/Socket/chats.d.ts +4 -8
  39. package/lib/Socket/chats.js +7 -87
  40. package/lib/Socket/groups.d.ts +4 -6
  41. package/lib/Socket/groups.js +13 -9
  42. package/lib/Socket/index.d.ts +5 -8
  43. package/lib/Socket/messages-recv.d.ts +5 -8
  44. package/lib/Socket/messages-recv.js +20 -25
  45. package/lib/Socket/messages-send.d.ts +5 -8
  46. package/lib/Socket/messages-send.js +116 -81
  47. package/lib/Socket/newsletter.d.ts +4 -6
  48. package/lib/Socket/newsletter.js +2 -4
  49. package/lib/Socket/socket.js +63 -1
  50. package/lib/Socket/usync.js +15 -10
  51. package/lib/Types/Chat.d.ts +2 -8
  52. package/lib/Types/Contact.d.ts +4 -5
  53. package/lib/Types/GroupMetadata.d.ts +4 -3
  54. package/lib/Types/Label.d.ts +0 -11
  55. package/lib/Types/Message.d.ts +15 -2
  56. package/lib/Types/Socket.d.ts +0 -2
  57. package/lib/Utils/chat-utils.d.ts +8 -8
  58. package/lib/Utils/chat-utils.js +4 -30
  59. package/lib/Utils/crypto.d.ts +1 -1
  60. package/lib/Utils/crypto.js +1 -3
  61. package/lib/Utils/decode-wa-message.d.ts +2 -4
  62. package/lib/Utils/decode-wa-message.js +18 -161
  63. package/lib/Utils/generics.d.ts +18 -8
  64. package/lib/Utils/generics.js +93 -7
  65. package/lib/Utils/history.js +1 -1
  66. package/lib/Utils/index.d.ts +1 -0
  67. package/lib/Utils/index.js +1 -0
  68. package/lib/Utils/messages-media.d.ts +9 -16
  69. package/lib/Utils/messages-media.js +186 -98
  70. package/lib/Utils/messages.d.ts +1 -1
  71. package/lib/Utils/messages.js +27 -17
  72. package/lib/Utils/use-single-file-auth-state.d.ts +5 -0
  73. package/lib/Utils/use-single-file-auth-state.js +66 -0
  74. package/lib/Utils/validate-connection.js +7 -7
  75. package/lib/WABinary/constants.d.ts +4 -4
  76. package/lib/WABinary/constants.js +1271 -8
  77. package/lib/WABinary/encode.js +5 -7
  78. package/lib/WABinary/jid-utils.d.ts +3 -3
  79. package/lib/WABinary/jid-utils.js +18 -18
  80. package/lib/WAM/constants.d.ts +2 -3
  81. package/lib/WAM/encode.js +2 -2
  82. package/lib/WAUSync/Protocols/USyncContactProtocol.js +2 -2
  83. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +2 -2
  84. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +3 -3
  85. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +2 -2
  86. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +1 -1
  87. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +1 -1
  88. package/lib/WAUSync/USyncQuery.js +13 -17
  89. package/package.json +10 -5
  90. package/WASignalGroup/GroupProtocol.js +0 -1697
  91. package/WASignalGroup/ciphertext_message.js +0 -16
  92. package/WASignalGroup/group_cipher.js +0 -120
  93. package/WASignalGroup/group_session_builder.js +0 -46
  94. package/WASignalGroup/index.js +0 -5
  95. package/WASignalGroup/keyhelper.js +0 -21
  96. package/WASignalGroup/protobufs.js +0 -3
  97. package/WASignalGroup/queue_job.js +0 -69
  98. package/WASignalGroup/sender_chain_key.js +0 -50
  99. package/WASignalGroup/sender_key_distribution_message.js +0 -78
  100. package/WASignalGroup/sender_key_message.js +0 -92
  101. package/WASignalGroup/sender_key_name.js +0 -70
  102. package/WASignalGroup/sender_key_record.js +0 -56
  103. package/WASignalGroup/sender_key_state.js +0 -129
  104. package/lib/Store/make-cache-manager-store.d.ts +0 -14
  105. package/lib/Store/make-cache-manager-store.js +0 -83
@@ -9,31 +9,24 @@ import { ILogger } from './logger';
9
9
  export declare const hkdfInfoKey: (type: MediaType) => string;
10
10
  /** generates all the keys required to encrypt/decrypt & sign a media message */
11
11
  export declare function getMediaKeys(buffer: Uint8Array | string | null | undefined, mediaType: MediaType): Promise<MediaDecryptionKeyInfo>;
12
+ export declare function uploadFile(buffer: Buffer, logger?: ILogger): Promise<string>;
13
+ export declare function vid2jpg(videoUrl: string): Promise<string>;
14
+ /**
15
+ * Originally written by Techwiz (https://github.com/techwiz37)
16
+ * Modified for customization and improvements
17
+ */
18
+ export declare const extractVideoThumb: (videoPath: string) => Promise<Buffer<ArrayBufferLike>>;
12
19
  export declare const extractImageThumb: (bufferOrFilePath: Readable | Buffer | string, width?: number) => Promise<{
13
20
  buffer: Buffer<ArrayBufferLike>;
14
21
  original: {
15
- width: number | undefined;
16
- height: number | undefined;
22
+ width: number;
23
+ height: number;
17
24
  };
18
25
  }>;
19
26
  export declare const encodeBase64EncodedStringForUpload: (b64: string) => string;
20
27
  export declare const generateProfilePicture: (mediaUpload: WAMediaUpload) => Promise<{
21
28
  img: Buffer<ArrayBufferLike>;
22
29
  }>;
23
- export declare const generateProfilePictureFull: (img: any) => Promise<{
24
- img: any;
25
- }>;
26
- export declare const generateProfilePictureFP: (buffer: any) => Promise<{
27
- img: any;
28
- preview: any;
29
- }>;
30
- export declare const generatePP: (buffer: any) => Promise<{
31
- img: any;
32
- preview: any;
33
- }>;
34
- export declare const changeprofileFull: (img: any) => Promise<{
35
- img: any;
36
- }>;
37
30
  /** gets the SHA256 of the given media message */
38
31
  export declare const mediaMessageSHA256B64: (message: WAMessageContent) => string | null | undefined;
39
32
  export declare function getAudioDuration(buffer: Buffer | string | Readable): Promise<number | undefined>;
@@ -36,15 +36,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  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.changeprofileFull = exports.generatePP = exports.generateProfilePictureFP = exports.generateProfilePictureFull = exports.generateProfilePicture = exports.encodeBase64EncodedStringForUpload = exports.extractImageThumb = 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
40
  exports.getMediaKeys = getMediaKeys;
41
+ exports.uploadFile = uploadFile;
42
+ exports.vid2jpg = vid2jpg;
41
43
  exports.getAudioDuration = getAudioDuration;
42
44
  exports.getAudioWaveform = getAudioWaveform;
43
45
  exports.generateThumbnail = generateThumbnail;
44
46
  exports.extensionForMediaMessage = extensionForMediaMessage;
45
47
  const boom_1 = require("@hapi/boom");
46
48
  const axios_1 = __importDefault(require("axios"));
47
- const child_process_1 = require("child_process");
49
+ const form_data_1 = __importDefault(require("form-data"));
50
+ const cheerio = __importStar(require("cheerio"));
48
51
  const Crypto = __importStar(require("crypto"));
49
52
  const events_1 = require("events");
50
53
  const fs_1 = require("fs");
@@ -99,18 +102,163 @@ async function getMediaKeys(buffer, mediaType) {
99
102
  macKey: expandedMediaKey.slice(48, 80),
100
103
  };
101
104
  }
102
- /** Extracts video thumb using FFMPEG */
103
- const extractVideoThumb = async (path, destPath, time, size) => new Promise((resolve, reject) => {
104
- const cmd = `ffmpeg -ss ${time} -i ${path} -y -vf scale=${size.width}:-1 -vframes 1 -f image2 ${destPath}`;
105
- (0, child_process_1.exec)(cmd, (err) => {
106
- if (err) {
107
- reject(err);
105
+ async function uploadFile(buffer, logger) {
106
+ const { fromBuffer } = await Promise.resolve().then(() => __importStar(require('file-type')));
107
+ const fileType = await fromBuffer(buffer);
108
+ if (!fileType)
109
+ throw new Error("Failed to detect file type.");
110
+ const { ext, mime } = fileType;
111
+ const services = [
112
+ {
113
+ name: "catbox",
114
+ url: "https://catbox.moe/user/api.php",
115
+ buildForm: () => {
116
+ const form = new form_data_1.default();
117
+ form.append("fileToUpload", buffer, {
118
+ filename: `file.${ext}`,
119
+ contentType: mime || "application/octet-stream"
120
+ });
121
+ form.append("reqtype", "fileupload");
122
+ return form;
123
+ },
124
+ parseResponse: res => res.data
125
+ },
126
+ {
127
+ name: "pdi.moe",
128
+ url: "https://scdn.pdi.moe/upload",
129
+ buildForm: () => {
130
+ const form = new form_data_1.default();
131
+ form.append("file", buffer, {
132
+ filename: `file.${ext}`,
133
+ contentType: mime
134
+ });
135
+ return form;
136
+ },
137
+ parseResponse: res => res.data.result.url
138
+ },
139
+ {
140
+ name: "qu.ax",
141
+ url: "https://qu.ax/upload.php",
142
+ buildForm: () => {
143
+ const form = new form_data_1.default();
144
+ form.append("files[]", buffer, {
145
+ filename: `file.${ext}`,
146
+ contentType: mime || "application/octet-stream"
147
+ });
148
+ return form;
149
+ },
150
+ parseResponse: res => {
151
+ var _a, _b, _c;
152
+ 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))
153
+ throw new Error("Failed to get URL from qu.ax");
154
+ return res.data.files[0].url;
155
+ }
156
+ },
157
+ {
158
+ name: "uguu.se",
159
+ url: "https://uguu.se/upload.php",
160
+ buildForm: () => {
161
+ const form = new form_data_1.default();
162
+ form.append("files[]", buffer, {
163
+ filename: `file.${ext}`,
164
+ contentType: mime || "application/octet-stream"
165
+ });
166
+ return form;
167
+ },
168
+ parseResponse: res => {
169
+ var _a, _b, _c;
170
+ 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))
171
+ throw new Error("Failed to get URL from uguu.se");
172
+ return res.data.files[0].url;
173
+ }
174
+ },
175
+ {
176
+ name: "tmpfiles",
177
+ url: "https://tmpfiles.org/api/v1/upload",
178
+ buildForm: () => {
179
+ const form = new form_data_1.default();
180
+ form.append("file", buffer, {
181
+ filename: `file.${ext}`,
182
+ contentType: mime
183
+ });
184
+ return form;
185
+ },
186
+ parseResponse: res => {
187
+ const match = res.data.data.url.match(/https:\/\/tmpfiles\.org\/(.*)/);
188
+ if (!match)
189
+ throw new Error("Failed to parse tmpfiles URL.");
190
+ return `https://tmpfiles.org/dl/${match[1]}`;
191
+ }
108
192
  }
109
- else {
110
- resolve();
193
+ ];
194
+ for (const service of services) {
195
+ try {
196
+ const form = service.buildForm();
197
+ const res = await axios_1.default.post(service.url, form, {
198
+ headers: form.getHeaders()
199
+ });
200
+ const url = service.parseResponse(res);
201
+ return url;
202
+ }
203
+ catch (error) {
204
+ logger === null || logger === void 0 ? void 0 : logger.debug(`[${service.name}] eror:`, (error === null || error === void 0 ? void 0 : error.message) || error);
205
+ }
206
+ }
207
+ throw new Error("All upload services failed.");
208
+ }
209
+ async function vid2jpg(videoUrl) {
210
+ try {
211
+ const { data } = await axios_1.default.get(`https://ezgif.com/video-to-jpg?url=${encodeURIComponent(videoUrl)}`);
212
+ const $ = cheerio.load(data);
213
+ const fileToken = $('input[name="file"]').attr("value");
214
+ if (!fileToken) {
215
+ throw new Error("Failed to retrieve file token. The video URL may be invalid or inaccessible.");
111
216
  }
217
+ const formData = new URLSearchParams();
218
+ formData.append("file", fileToken);
219
+ formData.append("end", "1");
220
+ formData.append("video-to-jpg", "Convert to JPG!");
221
+ const convert = await axios_1.default.post(`https://ezgif.com/video-to-jpg/${fileToken}`, formData);
222
+ const $2 = cheerio.load(convert.data);
223
+ let imageUrl = $2("#output img").first().attr("src");
224
+ if (!imageUrl) {
225
+ throw new Error("Could not locate the converted image output.");
226
+ }
227
+ if (imageUrl.startsWith("//")) {
228
+ imageUrl = "https:" + imageUrl;
229
+ }
230
+ else if (imageUrl.startsWith("/")) {
231
+ const cdnMatch = imageUrl.match(/\/(s\d+\..+?)\/.*/);
232
+ if (cdnMatch) {
233
+ imageUrl = "https://" + imageUrl.slice(2);
234
+ }
235
+ else {
236
+ imageUrl = "https://ezgif.com" + imageUrl;
237
+ }
238
+ }
239
+ return imageUrl;
240
+ }
241
+ catch (error) {
242
+ throw new Error("Failed to convert video to JPG: " + error.message);
243
+ }
244
+ }
245
+ /**
246
+ * Originally written by Techwiz (https://github.com/techwiz37)
247
+ * Modified for customization and improvements
248
+ */
249
+ const extractVideoThumb = async (videoPath) => {
250
+ const videoBuffer = await fs_1.promises.readFile(videoPath);
251
+ const dataUrl = await uploadFile(videoBuffer);
252
+ if (!dataUrl || typeof dataUrl !== 'string') {
253
+ throw new Error('Failed to upload video: Invalid or missing URL');
254
+ }
255
+ const jpgUrl = await vid2jpg(dataUrl);
256
+ const { data: imageBuffer } = await axios_1.default.get(jpgUrl, {
257
+ responseType: 'arraybuffer',
112
258
  });
113
- });
259
+ return imageBuffer;
260
+ };
261
+ exports.extractVideoThumb = extractVideoThumb;
114
262
  const extractImageThumb = async (bufferOrFilePath, width = 32) => {
115
263
  var _a, _b;
116
264
  if (bufferOrFilePath instanceof stream_1.Readable) {
@@ -180,76 +328,6 @@ const generateProfilePicture = async (mediaUpload) => {
180
328
  };
181
329
  };
182
330
  exports.generateProfilePicture = generateProfilePicture;
183
- const generateProfilePictureFull = async (img) => {
184
- const Jimp = require('jimp');
185
- const { read, MIME_JPEG, RESIZE_BILINEAR } = require('jimp');
186
- const jimp = await read(img);
187
- const min = Math.min(jimp.getWidth(), jimp.getHeight());
188
- const cropped = jimp.crop(0, 0, jimp.getWidth(), jimp.getHeight());
189
- let width = jimp.getWidth(), hight = jimp.getHeight(), ratio;
190
- if (width > hight) {
191
- ratio = jimp.getWidth() / 720;
192
- }
193
- else {
194
- ratio = jimp.getWidth() / 324;
195
- }
196
- ;
197
- width = width / ratio;
198
- hight = hight / ratio;
199
- img = cropped.quality(100).resize(width, hight).getBufferAsync(MIME_JPEG);
200
- return {
201
- img: await cropped.quality(100).resize(width, hight).getBufferAsync(MIME_JPEG),
202
- };
203
- };
204
- exports.generateProfilePictureFull = generateProfilePictureFull;
205
- const generateProfilePictureFP = async (buffer) => {
206
- const Jimp = require('jimp');
207
- const { read, MIME_JPEG, RESIZE_BILINEAR } = require('jimp');
208
- const jimp = await Jimp.read(buffer);
209
- const min = jimp.getWidth();
210
- const max = jimp.getHeight();
211
- const cropped = jimp.crop(0, 0, min, max);
212
- return {
213
- img: await cropped.scaleToFit(720, 720).getBufferAsync(Jimp.MIME_JPEG),
214
- preview: await cropped.normalize().getBufferAsync(Jimp.MIME_JPEG),
215
- };
216
- };
217
- exports.generateProfilePictureFP = generateProfilePictureFP;
218
- const generatePP = async (buffer) => {
219
- const Jimp = require('jimp');
220
- const { read, MIME_JPEG, RESIZE_BILINEAR } = require('jimp');
221
- const jimp = await Jimp.read(buffer);
222
- const min = jimp.getWidth();
223
- const max = jimp.getHeight();
224
- const cropped = jimp.crop(0, 0, min, max);
225
- return {
226
- img: await cropped.scaleToFit(720, 720).getBufferAsync(Jimp.MIME_JPEG),
227
- preview: await cropped.normalize().getBufferAsync(Jimp.MIME_JPEG),
228
- };
229
- };
230
- exports.generatePP = generatePP;
231
- const changeprofileFull = async (img) => {
232
- const Jimp = require('jimp');
233
- const { read, MIME_JPEG, RESIZE_BILINEAR } = require('jimp');
234
- const jimp = await read(img);
235
- const min = Math.min(jimp.getWidth(), jimp.getHeight());
236
- const cropped = jimp.crop(0, 0, jimp.getWidth(), jimp.getHeight());
237
- let width = jimp.getWidth(), hight = jimp.getHeight(), ratio;
238
- if (width > hight) {
239
- ratio = jimp.getWidth() / 720;
240
- }
241
- else {
242
- ratio = jimp.getWidth() / 324;
243
- }
244
- ;
245
- width = width / ratio;
246
- hight = hight / ratio;
247
- img = cropped.quality(100).resize(width, hight).getBufferAsync(MIME_JPEG);
248
- return {
249
- img: await cropped.quality(100).resize(width, hight).getBufferAsync(MIME_JPEG),
250
- };
251
- };
252
- exports.changeprofileFull = changeprofileFull;
253
331
  /** gets the SHA256 of the given media message */
254
332
  const mediaMessageSHA256B64 = (message) => {
255
333
  const media = Object.values(message)[0];
@@ -259,20 +337,17 @@ exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
259
337
  async function getAudioDuration(buffer) {
260
338
  const musicMetadata = await Promise.resolve().then(() => __importStar(require('music-metadata')));
261
339
  let metadata;
340
+ const options = {
341
+ duration: true
342
+ };
262
343
  if (Buffer.isBuffer(buffer)) {
263
- metadata = await musicMetadata.parseBuffer(buffer, undefined, { duration: true });
344
+ metadata = await musicMetadata.parseBuffer(buffer, undefined, options);
264
345
  }
265
346
  else if (typeof buffer === 'string') {
266
- const rStream = (0, fs_1.createReadStream)(buffer);
267
- try {
268
- metadata = await musicMetadata.parseStream(rStream, undefined, { duration: true });
269
- }
270
- finally {
271
- rStream.destroy();
272
- }
347
+ metadata = await musicMetadata.parseFile(buffer, options);
273
348
  }
274
349
  else {
275
- metadata = await musicMetadata.parseStream(buffer, undefined, { duration: true });
350
+ metadata = await musicMetadata.parseStream(buffer, undefined, options);
276
351
  }
277
352
  return metadata.format.duration;
278
353
  }
@@ -362,11 +437,18 @@ async function generateThumbnail(file, mediaType, options) {
362
437
  }
363
438
  }
364
439
  else if (mediaType === 'video') {
365
- const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.jpg');
366
440
  try {
367
- await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
368
- const buff = await fs_1.promises.readFile(imgFilename);
369
- thumbnail = buff.toString('base64');
441
+ const thumbnailBuffer = await (0, exports.extractVideoThumb)(file);
442
+ const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.jpg');
443
+ await fs_1.promises.writeFile(imgFilename, thumbnailBuffer);
444
+ const { buffer: processedThumbnailBuffer, original } = await (0, exports.extractImageThumb)(imgFilename);
445
+ thumbnail = processedThumbnailBuffer.toString('base64');
446
+ if (original.width && original.height) {
447
+ originalImageDimensions = {
448
+ width: original.width,
449
+ height: original.height,
450
+ };
451
+ }
370
452
  await fs_1.promises.unlink(imgFilename);
371
453
  }
372
454
  catch (err) {
@@ -437,7 +519,7 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
437
519
  let writeStream;
438
520
  let didSaveToTmpPath = false;
439
521
  if (type === 'file') {
440
- bodyPath = media.url.toString();
522
+ bodyPath = media.url;
441
523
  }
442
524
  else if (saveOriginalFileIfRequired) {
443
525
  bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)());
@@ -460,8 +542,10 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
460
542
  });
461
543
  }
462
544
  sha256Plain = sha256Plain.update(data);
463
- if (writeStream && !writeStream.write(data)) {
464
- await (0, events_1.once)(writeStream, 'drain');
545
+ if (writeStream) {
546
+ if (!writeStream.write(data)) {
547
+ await (0, events_1.once)(writeStream, 'drain');
548
+ }
465
549
  }
466
550
  onChunk(aes.update(data));
467
551
  }
@@ -520,7 +604,11 @@ const toSmallestChunkSize = (num) => {
520
604
  const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
521
605
  exports.getUrlFromDirectPath = getUrlFromDirectPath;
522
606
  const downloadContentFromMessage = async ({ mediaKey, directPath, url }, type, opts = {}) => {
523
- const downloadUrl = url || (0, exports.getUrlFromDirectPath)(directPath);
607
+ const isValidMediaUrl = url === null || url === void 0 ? void 0 : url.startsWith('https://mmg.whatsapp.net/');
608
+ const downloadUrl = isValidMediaUrl ? url : (0, exports.getUrlFromDirectPath)(directPath);
609
+ if (!downloadUrl) {
610
+ throw new boom_1.Boom('No valid media URL or directPath present in message', { statusCode: 400 });
611
+ }
524
612
  const keys = await getMediaKeys(mediaKey, type);
525
613
  return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
526
614
  };
@@ -38,7 +38,7 @@ export declare const extractMessageContent: (content: WAMessageContent | undefin
38
38
  /**
39
39
  * Returns the device predicted by message ID
40
40
  */
41
- export declare const getDevice: (id: string) => "android" | "unknown" | "web" | "ios" | "desktop";
41
+ export declare const getDevice: (id: string) => "web" | "unknown" | "android" | "ios" | "desktop";
42
42
  /** Upserts a receipt in the message */
43
43
  export declare const updateMessageWithReceipt: (msg: Pick<WAMessage, "userReceipt">, receipt: MessageUserReceipt) => void;
44
44
  /** Update the message with a new reaction */
@@ -275,9 +275,6 @@ const generateWAMessageContent = async (message, options) => {
275
275
  extContent.font = options.font;
276
276
  }
277
277
  m.extendedTextMessage = extContent;
278
- m.messageContextInfo = {
279
- messageSecret: (0, crypto_1.randomBytes)(32)
280
- };
281
278
  }
282
279
  else if ('contacts' in message) {
283
280
  const contactLen = message.contacts.contacts.length;
@@ -437,12 +434,12 @@ const generateWAMessageContent = async (message, options) => {
437
434
  m.pollCreationMessageV2 = pollCreationMessage;
438
435
  }
439
436
  else {
440
- if (message.poll.selectableCount > 0) {
437
+ if (message.poll.selectableCount === 1) {
441
438
  // poll v3 is for single select polls
442
439
  m.pollCreationMessageV3 = pollCreationMessage;
443
440
  }
444
441
  else {
445
- // poll v3 for multiple choice polls
442
+ // poll for multiple choice polls
446
443
  m.pollCreationMessage = pollCreationMessage;
447
444
  }
448
445
  }
@@ -502,6 +499,14 @@ const generateWAMessageContent = async (message, options) => {
502
499
  else if ('requestPhoneNumber' in message) {
503
500
  m.requestPhoneNumberMessage = {};
504
501
  }
502
+ else if ('album' in message) {
503
+ const imageMessages = message.album.filter(item => 'image' in item);
504
+ const videoMessages = message.album.filter(item => 'video' in item);
505
+ m.albumMessage = WAProto_1.proto.Message.AlbumMessage.fromObject({
506
+ expectedImageCount: imageMessages.length,
507
+ expectedVideoCount: videoMessages.length,
508
+ });
509
+ }
505
510
  else {
506
511
  m = await (0, exports.prepareWAMessageMedia)(message, options);
507
512
  }
@@ -566,7 +571,7 @@ const generateWAMessageContent = async (message, options) => {
566
571
  title: message.title,
567
572
  footerText: message.footer,
568
573
  description: message.text,
569
- listType: message.hasOwnProperty('listType') ? message.listType : WAProto_1.proto.Message.ListMessage.ListType.PRODUCT_LIST
574
+ listType: WAProto_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
570
575
  };
571
576
  m = { listMessage };
572
577
  }
@@ -804,7 +809,9 @@ const normalizeMessageContent = (content) => {
804
809
  || (message === null || message === void 0 ? void 0 : message.groupStatusMessage)
805
810
  || (message === null || message === void 0 ? void 0 : message.limitSharingMessage)
806
811
  || (message === null || message === void 0 ? void 0 : message.botTaskMessage)
807
- || (message === null || message === void 0 ? void 0 : message.questionMessage));
812
+ || (message === null || message === void 0 ? void 0 : message.questionMessage)
813
+ || (message === null || message === void 0 ? void 0 : message.groupStatusMessageV2)
814
+ || (message === null || message === void 0 ? void 0 : message.botForwardedMessage));
808
815
  }
809
816
  };
810
817
  exports.normalizeMessageContent = normalizeMessageContent;
@@ -877,9 +884,8 @@ const updateMessageWithReaction = (msg, reaction) => {
877
884
  const authorID = (0, generics_1.getKeyAuthor)(reaction.key);
878
885
  const reactions = (msg.reactions || [])
879
886
  .filter(r => (0, generics_1.getKeyAuthor)(r.key) !== authorID);
880
- if (reaction.text) {
881
- reactions.push(reaction);
882
- }
887
+ reaction.text = reaction.text || '';
888
+ reactions.push(reaction);
883
889
  msg.reactions = reactions;
884
890
  };
885
891
  exports.updateMessageWithReaction = updateMessageWithReaction;
@@ -959,13 +965,17 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
959
965
  const result = await downloadMsg()
960
966
  .catch(async (error) => {
961
967
  var _a;
962
- if (ctx && axios_1.default.isAxiosError(error) && // check if the message requires a reupload
963
- REUPLOAD_REQUIRED_STATUS.includes((_a = error.response) === null || _a === void 0 ? void 0 : _a.status)) {
964
- ctx.logger.info({ key: message.key }, 'sending reupload media request...');
965
- // request reupload
966
- message = await ctx.reuploadRequest(message);
967
- const result = await downloadMsg();
968
- return result;
968
+ if (ctx) {
969
+ if (axios_1.default.isAxiosError(error)) {
970
+ // check if the message requires a reupload
971
+ if (REUPLOAD_REQUIRED_STATUS.includes((_a = error.response) === null || _a === void 0 ? void 0 : _a.status)) {
972
+ ctx.logger.info({ key: message.key }, 'sending reupload media request...');
973
+ // request reupload
974
+ message = await ctx.reuploadRequest(message);
975
+ const result = await downloadMsg();
976
+ return result;
977
+ }
978
+ }
969
979
  }
970
980
  throw error;
971
981
  });
@@ -0,0 +1,5 @@
1
+ import { AuthenticationState } from '../Types/index';
2
+ export declare const useSingleFileAuthState: (filepath: string) => Promise<{
3
+ state: AuthenticationState;
4
+ saveCreds: () => Promise<void>;
5
+ }>;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useSingleFileAuthState = void 0;
7
+ const async_lock_1 = __importDefault(require("async-lock"));
8
+ const promises_1 = require("fs/promises");
9
+ const index_1 = require("../../WAProto/index");
10
+ const auth_utils_1 = require("./auth-utils");
11
+ const generics_1 = require("./generics");
12
+ const fileLock = new async_lock_1.default({ maxPending: Infinity });
13
+ const useSingleFileAuthState = async (filepath) => {
14
+ const filePath = filepath + '.json';
15
+ const writeData = (data) => {
16
+ return fileLock.acquire(filePath, () => (0, promises_1.writeFile)(filePath, JSON.stringify(data, generics_1.BufferJSON.replacer)));
17
+ };
18
+ const readData = async () => {
19
+ try {
20
+ const data = await fileLock.acquire(filePath, () => (0, promises_1.readFile)(filePath, { encoding: 'utf-8' }));
21
+ return JSON.parse(data, generics_1.BufferJSON.reviver);
22
+ }
23
+ catch (error) {
24
+ return null;
25
+ }
26
+ };
27
+ const fileInfo = await (0, promises_1.stat)(filePath).catch(() => null);
28
+ if (fileInfo && !fileInfo.isFile()) {
29
+ throw new Error(`A non-file exists at ${filePath}, please delete it or specify a different path.`);
30
+ }
31
+ // Initialize with default credentials if the file is empty or doesn't exist
32
+ const { creds = (0, auth_utils_1.initAuthCreds)(), keys = {} } = await readData() || {};
33
+ return {
34
+ state: {
35
+ creds,
36
+ keys: {
37
+ get: async (type, ids) => {
38
+ const data = {};
39
+ for (const id of ids) {
40
+ const value = keys[`${type}-${id}`];
41
+ data[id] = type === 'app-state-sync-key' && value
42
+ ? index_1.proto.Message.AppStateSyncKeyData.fromObject(value)
43
+ : value;
44
+ }
45
+ return data;
46
+ },
47
+ set: async (data) => {
48
+ for (const category in data) {
49
+ for (const id in data[category]) {
50
+ const value = data[category][id];
51
+ if (value) {
52
+ keys[`${category}-${id}`] = value;
53
+ }
54
+ else {
55
+ delete keys[`${category}-${id}`];
56
+ }
57
+ }
58
+ }
59
+ await writeData({ creds, keys });
60
+ }
61
+ }
62
+ },
63
+ saveCreds: () => writeData({ creds, keys })
64
+ };
65
+ };
66
+ exports.useSingleFileAuthState = useSingleFileAuthState;
@@ -22,7 +22,7 @@ const getUserAgent = (config) => {
22
22
  device: 'Desktop',
23
23
  osBuildNumber: '0.1',
24
24
  localeLanguageIso6391: 'en',
25
- localeCountryIso31661Alpha2: config.countryCode
25
+ localeCountryIso31661Alpha2: 'US'
26
26
  };
27
27
  };
28
28
  const PLATFORM_MAP = {
@@ -103,21 +103,21 @@ const configureSuccessfulPairing = (stanza, { advSecretKey, signedIdentityKey, s
103
103
  }
104
104
  const bizName = businessNode === null || businessNode === void 0 ? void 0 : businessNode.attrs.name;
105
105
  const jid = deviceNode.attrs.jid;
106
- const { details, hmac } = WAProto_1.proto.ADVSignedDeviceIdentityHMAC.decode(deviceIdentityNode.content);
107
- // check HMAC matches
108
- const advSign = (0, crypto_2.hmacSign)(details, Buffer.from(advSecretKey, 'base64'));
106
+ const { details, hmac, accountType } = WAProto_1.proto.ADVSignedDeviceIdentityHMAC.decode(deviceIdentityNode.content);
107
+ const isHostedAccount = accountType !== undefined && accountType === WAProto_1.proto.ADVEncryptionType.HOSTED;
108
+ const hmacPrefix = isHostedAccount ? Buffer.from([6, 5]) : Buffer.alloc(0);
109
+ const advSign = (0, crypto_2.hmacSign)(Buffer.concat([hmacPrefix, details]), Buffer.from(advSecretKey, 'base64'));
109
110
  if (Buffer.compare(hmac, advSign) !== 0) {
110
111
  throw new boom_1.Boom('Invalid account signature');
111
112
  }
112
113
  const account = WAProto_1.proto.ADVSignedDeviceIdentity.decode(details);
113
114
  const { accountSignatureKey, accountSignature, details: deviceDetails } = account;
114
- // verify the device signature matches
115
115
  const accountMsg = Buffer.concat([Buffer.from([6, 0]), deviceDetails, signedIdentityKey.public]);
116
116
  if (!crypto_2.Curve.verify(accountSignatureKey, accountMsg, accountSignature)) {
117
117
  throw new boom_1.Boom('Failed to verify account signature');
118
118
  }
119
- // sign the details with our identity key
120
- const deviceMsg = Buffer.concat([Buffer.from([6, 1]), deviceDetails, signedIdentityKey.public, accountSignatureKey]);
119
+ const devicePrefix = isHostedAccount ? Buffer.from([6, 6]) : Buffer.from([6, 1]);
120
+ const deviceMsg = Buffer.concat([devicePrefix, deviceDetails, signedIdentityKey.public, accountSignatureKey]);
121
121
  account.deviceSignature = crypto_2.Curve.sign(signedIdentityKey.private, deviceMsg);
122
122
  const identity = (0, signal_1.createSignalIdentity)(jid, accountSignatureKey);
123
123
  const accountEnc = (0, exports.encodeSignedDeviceIdentity)(account, false);