@d0v3riz/baileys 6.7.18 → 6.7.19
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.
- package/lib/Types/Message.d.ts +1 -1
- package/lib/Utils/business.js +11 -3
- package/lib/Utils/messages-media.d.ts +2 -3
- package/lib/Utils/messages-media.js +40 -40
- package/lib/Utils/messages.js +13 -15
- package/package.json +1 -1
package/lib/Types/Message.d.ts
CHANGED
|
@@ -217,7 +217,7 @@ export type MiscMessageGenerationOptions = MinimalRelayOptions & {
|
|
|
217
217
|
export type MessageGenerationOptionsFromContent = MiscMessageGenerationOptions & {
|
|
218
218
|
userJid: string;
|
|
219
219
|
};
|
|
220
|
-
export type WAMediaUploadFunction = (
|
|
220
|
+
export type WAMediaUploadFunction = (encFilePath: string, opts: {
|
|
221
221
|
fileEncSha256B64: string;
|
|
222
222
|
mediaType: MediaType;
|
|
223
223
|
timeoutMs?: number;
|
package/lib/Utils/business.js
CHANGED
|
@@ -4,7 +4,11 @@ exports.uploadingNecessaryImages = exports.parseProductNode = exports.toProductN
|
|
|
4
4
|
exports.uploadingNecessaryImagesOfProduct = uploadingNecessaryImagesOfProduct;
|
|
5
5
|
const boom_1 = require("@hapi/boom");
|
|
6
6
|
const crypto_1 = require("crypto");
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const os_1 = require("os");
|
|
9
|
+
const path_1 = require("path");
|
|
7
10
|
const WABinary_1 = require("../WABinary");
|
|
11
|
+
const generics_1 = require("./generics");
|
|
8
12
|
const messages_media_1 = require("./messages-media");
|
|
9
13
|
const parseCatalogNode = (node) => {
|
|
10
14
|
const catalogNode = (0, WABinary_1.getBinaryNodeChild)(node, 'product_catalog');
|
|
@@ -202,17 +206,21 @@ const uploadingNecessaryImages = async (images, waUploadToServer, timeoutMs = 30
|
|
|
202
206
|
}
|
|
203
207
|
const { stream } = await (0, messages_media_1.getStream)(img);
|
|
204
208
|
const hasher = (0, crypto_1.createHash)('sha256');
|
|
205
|
-
const
|
|
209
|
+
const filePath = (0, path_1.join)((0, os_1.tmpdir)(), 'img' + (0, generics_1.generateMessageIDV2)());
|
|
210
|
+
const encFileWriteStream = (0, fs_1.createWriteStream)(filePath);
|
|
206
211
|
for await (const block of stream) {
|
|
207
212
|
hasher.update(block);
|
|
208
|
-
|
|
213
|
+
encFileWriteStream.write(block);
|
|
209
214
|
}
|
|
210
215
|
const sha = hasher.digest('base64');
|
|
211
|
-
const { directPath } = await waUploadToServer(
|
|
216
|
+
const { directPath } = await waUploadToServer(filePath, {
|
|
212
217
|
mediaType: 'product-catalog-image',
|
|
213
218
|
fileEncSha256B64: sha,
|
|
214
219
|
timeoutMs
|
|
215
220
|
});
|
|
221
|
+
await fs_1.promises
|
|
222
|
+
.unlink(filePath)
|
|
223
|
+
.catch(err => console.log('Error deleting temp file ', err));
|
|
216
224
|
return { url: (0, messages_media_1.getUrlFromDirectPath)(directPath) };
|
|
217
225
|
}));
|
|
218
226
|
return results;
|
|
@@ -62,13 +62,12 @@ type EncryptedStreamOptions = {
|
|
|
62
62
|
};
|
|
63
63
|
export declare const encryptedStream: (media: WAMediaUpload, mediaType: MediaType, { logger, saveOriginalFileIfRequired, opts }?: EncryptedStreamOptions) => Promise<{
|
|
64
64
|
mediaKey: Buffer<ArrayBufferLike>;
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
originalFilePath: string | undefined;
|
|
66
|
+
encFilePath: string;
|
|
67
67
|
mac: Buffer<ArrayBuffer>;
|
|
68
68
|
fileEncSha256: Buffer<ArrayBufferLike>;
|
|
69
69
|
fileSha256: Buffer<ArrayBufferLike>;
|
|
70
70
|
fileLength: number;
|
|
71
|
-
didSaveToTmpPath: boolean;
|
|
72
71
|
}>;
|
|
73
72
|
export type MediaDownloadOptions = {
|
|
74
73
|
startByte?: number;
|
|
@@ -331,27 +331,29 @@ const getHttpStream = async (url, options = {}) => {
|
|
|
331
331
|
};
|
|
332
332
|
exports.getHttpStream = getHttpStream;
|
|
333
333
|
const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
|
|
334
|
+
var _a, _b;
|
|
334
335
|
const { stream, type } = await (0, exports.getStream)(media, opts);
|
|
335
336
|
logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
|
|
336
337
|
const mediaKey = Crypto.randomBytes(32);
|
|
337
338
|
const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
let
|
|
341
|
-
let
|
|
342
|
-
if (
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
else if (saveOriginalFileIfRequired) {
|
|
346
|
-
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)());
|
|
347
|
-
writeStream = (0, fs_1.createWriteStream)(bodyPath);
|
|
348
|
-
didSaveToTmpPath = true;
|
|
339
|
+
const encFilePath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)() + '-enc');
|
|
340
|
+
const encFileWriteStream = (0, fs_1.createWriteStream)(encFilePath);
|
|
341
|
+
let originalFileStream;
|
|
342
|
+
let originalFilePath;
|
|
343
|
+
if (saveOriginalFileIfRequired) {
|
|
344
|
+
originalFilePath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)() + '-original');
|
|
345
|
+
originalFileStream = (0, fs_1.createWriteStream)(originalFilePath);
|
|
349
346
|
}
|
|
350
347
|
let fileLength = 0;
|
|
351
348
|
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
349
|
+
const hmac = Crypto.createHmac('sha256', macKey).update(iv);
|
|
350
|
+
const sha256Plain = Crypto.createHash('sha256');
|
|
351
|
+
const sha256Enc = Crypto.createHash('sha256');
|
|
352
|
+
const onChunk = (buff) => {
|
|
353
|
+
sha256Enc.update(buff);
|
|
354
|
+
hmac.update(buff);
|
|
355
|
+
encFileWriteStream.write(buff);
|
|
356
|
+
};
|
|
355
357
|
try {
|
|
356
358
|
for await (const data of stream) {
|
|
357
359
|
fileLength += data.length;
|
|
@@ -362,57 +364,54 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
362
364
|
data: { media, type }
|
|
363
365
|
});
|
|
364
366
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
367
|
+
if (originalFileStream) {
|
|
368
|
+
if (!originalFileStream.write(data)) {
|
|
369
|
+
await (0, events_1.once)(originalFileStream, 'drain');
|
|
370
|
+
}
|
|
368
371
|
}
|
|
372
|
+
sha256Plain.update(data);
|
|
369
373
|
onChunk(aes.update(data));
|
|
370
374
|
}
|
|
371
375
|
onChunk(aes.final());
|
|
372
376
|
const mac = hmac.digest().slice(0, 10);
|
|
373
|
-
sha256Enc
|
|
377
|
+
sha256Enc.update(mac);
|
|
374
378
|
const fileSha256 = sha256Plain.digest();
|
|
375
379
|
const fileEncSha256 = sha256Enc.digest();
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
380
|
+
encFileWriteStream.write(mac);
|
|
381
|
+
encFileWriteStream.end();
|
|
382
|
+
(_a = originalFileStream === null || originalFileStream === void 0 ? void 0 : originalFileStream.end) === null || _a === void 0 ? void 0 : _a.call(originalFileStream);
|
|
379
383
|
stream.destroy();
|
|
380
384
|
logger === null || logger === void 0 ? void 0 : logger.debug('encrypted data successfully');
|
|
381
385
|
return {
|
|
382
386
|
mediaKey,
|
|
383
|
-
|
|
384
|
-
|
|
387
|
+
originalFilePath,
|
|
388
|
+
encFilePath,
|
|
385
389
|
mac,
|
|
386
390
|
fileEncSha256,
|
|
387
391
|
fileSha256,
|
|
388
|
-
fileLength
|
|
389
|
-
didSaveToTmpPath
|
|
392
|
+
fileLength
|
|
390
393
|
};
|
|
391
394
|
}
|
|
392
395
|
catch (error) {
|
|
393
396
|
// destroy all streams with error
|
|
394
|
-
|
|
395
|
-
|
|
397
|
+
encFileWriteStream.destroy();
|
|
398
|
+
(_b = originalFileStream === null || originalFileStream === void 0 ? void 0 : originalFileStream.destroy) === null || _b === void 0 ? void 0 : _b.call(originalFileStream);
|
|
396
399
|
aes.destroy();
|
|
397
400
|
hmac.destroy();
|
|
398
401
|
sha256Plain.destroy();
|
|
399
402
|
sha256Enc.destroy();
|
|
400
403
|
stream.destroy();
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
catch (err) {
|
|
406
|
-
logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
|
|
404
|
+
try {
|
|
405
|
+
await fs_1.promises.unlink(encFilePath);
|
|
406
|
+
if (originalFilePath) {
|
|
407
|
+
await fs_1.promises.unlink(originalFilePath);
|
|
407
408
|
}
|
|
408
409
|
}
|
|
410
|
+
catch (err) {
|
|
411
|
+
logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed deleting tmp files');
|
|
412
|
+
}
|
|
409
413
|
throw error;
|
|
410
414
|
}
|
|
411
|
-
function onChunk(buff) {
|
|
412
|
-
sha256Enc = sha256Enc.update(buff);
|
|
413
|
-
hmac = hmac.update(buff);
|
|
414
|
-
encWriteStream.push(buff);
|
|
415
|
-
}
|
|
416
415
|
};
|
|
417
416
|
exports.encryptedStream = encryptedStream;
|
|
418
417
|
const DEF_HOST = 'mmg.whatsapp.net';
|
|
@@ -532,7 +531,7 @@ function extensionForMediaMessage(message) {
|
|
|
532
531
|
return extension;
|
|
533
532
|
}
|
|
534
533
|
const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
535
|
-
return async (
|
|
534
|
+
return async (filePath, { mediaType, fileEncSha256B64, timeoutMs }) => {
|
|
536
535
|
var _a, _b;
|
|
537
536
|
// send a query JSON to obtain the url & auth token to upload our media
|
|
538
537
|
let uploadInfo = await refreshMediaConn(false);
|
|
@@ -546,8 +545,9 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
|
|
|
546
545
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
547
546
|
let result;
|
|
548
547
|
try {
|
|
549
|
-
const body = await axios_1.default.post(url,
|
|
548
|
+
const body = await axios_1.default.post(url, (0, fs_1.createReadStream)(filePath), {
|
|
550
549
|
...options,
|
|
550
|
+
maxRedirects: 0,
|
|
551
551
|
headers: {
|
|
552
552
|
...options.headers || {},
|
|
553
553
|
'Content-Type': 'application/octet-stream',
|
package/lib/Utils/messages.js
CHANGED
|
@@ -111,7 +111,7 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
111
111
|
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
|
|
112
112
|
const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
|
|
113
113
|
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
|
|
114
|
-
const { mediaKey,
|
|
114
|
+
const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await (0, messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
|
|
115
115
|
logger,
|
|
116
116
|
saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
|
|
117
117
|
opts: options.options
|
|
@@ -120,14 +120,14 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
120
120
|
const fileEncSha256B64 = fileEncSha256.toString('base64');
|
|
121
121
|
const [{ mediaUrl, directPath }] = await Promise.all([
|
|
122
122
|
(async () => {
|
|
123
|
-
const result = await options.upload(
|
|
123
|
+
const result = await options.upload(encFilePath, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
|
|
124
124
|
logger === null || logger === void 0 ? void 0 : logger.debug({ mediaType, cacheableKey }, 'uploaded media');
|
|
125
125
|
return result;
|
|
126
126
|
})(),
|
|
127
127
|
(async () => {
|
|
128
128
|
try {
|
|
129
129
|
if (requiresThumbnailComputation) {
|
|
130
|
-
const { thumbnail, originalImageDimensions } = await (0, messages_media_1.generateThumbnail)(
|
|
130
|
+
const { thumbnail, originalImageDimensions } = await (0, messages_media_1.generateThumbnail)(originalFilePath, mediaType, options);
|
|
131
131
|
uploadData.jpegThumbnail = thumbnail;
|
|
132
132
|
if (!uploadData.width && originalImageDimensions) {
|
|
133
133
|
uploadData.width = originalImageDimensions.width;
|
|
@@ -137,11 +137,11 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
137
137
|
logger === null || logger === void 0 ? void 0 : logger.debug('generated thumbnail');
|
|
138
138
|
}
|
|
139
139
|
if (requiresDurationComputation) {
|
|
140
|
-
uploadData.seconds = await (0, messages_media_1.getAudioDuration)(
|
|
140
|
+
uploadData.seconds = await (0, messages_media_1.getAudioDuration)(originalFilePath);
|
|
141
141
|
logger === null || logger === void 0 ? void 0 : logger.debug('computed audio duration');
|
|
142
142
|
}
|
|
143
143
|
if (requiresWaveformProcessing) {
|
|
144
|
-
uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(
|
|
144
|
+
uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(originalFilePath, logger);
|
|
145
145
|
logger === null || logger === void 0 ? void 0 : logger.debug('processed waveform');
|
|
146
146
|
}
|
|
147
147
|
if (requiresAudioBackground) {
|
|
@@ -155,17 +155,15 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
155
155
|
})(),
|
|
156
156
|
])
|
|
157
157
|
.finally(async () => {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
await fs_1.promises.access(bodyPath);
|
|
163
|
-
await fs_1.promises.unlink(bodyPath);
|
|
164
|
-
logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp file');
|
|
165
|
-
}
|
|
166
|
-
catch (error) {
|
|
167
|
-
logger === null || logger === void 0 ? void 0 : logger.warn('failed to remove tmp file');
|
|
158
|
+
try {
|
|
159
|
+
await fs_1.promises.unlink(encFilePath);
|
|
160
|
+
if (originalFilePath) {
|
|
161
|
+
await fs_1.promises.unlink(originalFilePath);
|
|
168
162
|
}
|
|
163
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp files');
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
logger === null || logger === void 0 ? void 0 : logger.warn('failed to remove tmp file');
|
|
169
167
|
}
|
|
170
168
|
});
|
|
171
169
|
const obj = Types_1.WAProto.Message.fromObject({
|