Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MR414N-ID
GitHub Repository: MR414N-ID/botku2
Path: blob/master/node_modules/@adiwajshing/baileys/lib/Utils/messages-media.js
1129 views
1
"use strict";
2
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
if (k2 === undefined) k2 = k;
4
var desc = Object.getOwnPropertyDescriptor(m, k);
5
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
desc = { enumerable: true, get: function() { return m[k]; } };
7
}
8
Object.defineProperty(o, k2, desc);
9
}) : (function(o, m, k, k2) {
10
if (k2 === undefined) k2 = k;
11
o[k2] = m[k];
12
}));
13
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
Object.defineProperty(o, "default", { enumerable: true, value: v });
15
}) : function(o, v) {
16
o["default"] = v;
17
});
18
var __importStar = (this && this.__importStar) || function (mod) {
19
if (mod && mod.__esModule) return mod;
20
var result = {};
21
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
__setModuleDefault(result, mod);
23
return result;
24
};
25
Object.defineProperty(exports, "__esModule", { value: true });
26
exports.getStatusCodeForMediaRetry = exports.decryptMediaRetryData = exports.decodeMediaRetryNode = exports.encryptMediaRetryRequest = exports.getWAUploadToServer = exports.extensionForMediaMessage = exports.downloadEncryptedContent = exports.downloadContentFromMessage = exports.getUrlFromDirectPath = exports.encryptedStream = exports.getHttpStream = exports.generateThumbnail = exports.getStream = exports.toBuffer = exports.toReadable = exports.getAudioDuration = exports.mediaMessageSHA256B64 = exports.generateProfilePicture = exports.extractImageThumb = exports.getMediaKeys = exports.hkdfInfoKey = void 0;
27
const boom_1 = require("@hapi/boom");
28
const child_process_1 = require("child_process");
29
const Crypto = __importStar(require("crypto"));
30
const events_1 = require("events");
31
const fs_1 = require("fs");
32
const os_1 = require("os");
33
const path_1 = require("path");
34
const stream_1 = require("stream");
35
const WAProto_1 = require("../../WAProto");
36
const Defaults_1 = require("../Defaults");
37
const WABinary_1 = require("../WABinary");
38
const crypto_1 = require("./crypto");
39
const generics_1 = require("./generics");
40
const getTmpFilesDirectory = () => (0, os_1.tmpdir)();
41
const getImageProcessingLibrary = async () => {
42
const [jimp, sharp] = await Promise.all([
43
(async () => {
44
const jimp = await (Promise.resolve().then(() => __importStar(require('jimp'))).catch(() => { }));
45
return jimp;
46
})(),
47
(async () => {
48
const sharp = await (Promise.resolve().then(() => __importStar(require('sharp'))).catch(() => { }));
49
return sharp;
50
})()
51
]);
52
if (sharp) {
53
return { sharp };
54
}
55
if (jimp) {
56
return { jimp };
57
}
58
throw new boom_1.Boom('No image processing library available');
59
};
60
const hkdfInfoKey = (type) => {
61
let str = type;
62
if (type === 'sticker') {
63
str = 'image';
64
}
65
if (type === 'md-app-state') {
66
str = 'App State';
67
}
68
const hkdfInfo = str[0].toUpperCase() + str.slice(1);
69
return `WhatsApp ${hkdfInfo} Keys`;
70
};
71
exports.hkdfInfoKey = hkdfInfoKey;
72
/** generates all the keys required to encrypt/decrypt & sign a media message */
73
function getMediaKeys(buffer, mediaType) {
74
if (!buffer) {
75
throw new boom_1.Boom('Cannot derive from empty media key');
76
}
77
if (typeof buffer === 'string') {
78
buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64');
79
}
80
// expand using HKDF to 112 bytes, also pass in the relevant app info
81
const expandedMediaKey = (0, crypto_1.hkdf)(buffer, 112, { info: (0, exports.hkdfInfoKey)(mediaType) });
82
return {
83
iv: expandedMediaKey.slice(0, 16),
84
cipherKey: expandedMediaKey.slice(16, 48),
85
macKey: expandedMediaKey.slice(48, 80),
86
};
87
}
88
exports.getMediaKeys = getMediaKeys;
89
/** Extracts video thumb using FFMPEG */
90
const extractVideoThumb = async (path, destPath, time, size) => new Promise((resolve, reject) => {
91
const cmd = `ffmpeg -ss ${time} -i ${path} -y -vf scale=${size.width}:-1 -vframes 1 -f image2 ${destPath}`;
92
(0, child_process_1.exec)(cmd, (err) => {
93
if (err) {
94
reject(err);
95
}
96
else {
97
resolve();
98
}
99
});
100
});
101
const extractImageThumb = async (bufferOrFilePath, width = 32) => {
102
if (bufferOrFilePath instanceof stream_1.Readable) {
103
bufferOrFilePath = await (0, exports.toBuffer)(bufferOrFilePath);
104
}
105
const lib = await getImageProcessingLibrary();
106
if ('sharp' in lib) {
107
const result = await lib.sharp.default(bufferOrFilePath)
108
.resize(width)
109
.jpeg({ quality: 50 })
110
.toBuffer();
111
return result;
112
}
113
else {
114
const { read, MIME_JPEG, RESIZE_BILINEAR, AUTO } = lib.jimp;
115
const jimp = await read(bufferOrFilePath);
116
const result = await jimp
117
.quality(50)
118
.resize(width, AUTO, RESIZE_BILINEAR)
119
.getBufferAsync(MIME_JPEG);
120
return result;
121
}
122
};
123
exports.extractImageThumb = extractImageThumb;
124
const generateProfilePicture = async (mediaUpload) => {
125
let bufferOrFilePath;
126
if (Buffer.isBuffer(mediaUpload)) {
127
bufferOrFilePath = mediaUpload;
128
}
129
else if ('url' in mediaUpload) {
130
bufferOrFilePath = mediaUpload.url.toString();
131
}
132
else {
133
bufferOrFilePath = await (0, exports.toBuffer)(mediaUpload.stream);
134
}
135
const lib = await getImageProcessingLibrary();
136
let img;
137
if ('sharp' in lib) {
138
img = lib.sharp.default(bufferOrFilePath)
139
.resize(640, 640)
140
.jpeg({
141
quality: 50,
142
})
143
.toBuffer();
144
}
145
else {
146
const { read, MIME_JPEG, RESIZE_BILINEAR } = lib.jimp;
147
const jimp = await read(bufferOrFilePath);
148
const min = Math.min(jimp.getWidth(), jimp.getHeight());
149
const cropped = jimp.crop(0, 0, min, min);
150
img = cropped
151
.quality(50)
152
.resize(640, 640, RESIZE_BILINEAR)
153
.getBufferAsync(MIME_JPEG);
154
}
155
return {
156
img: await img,
157
};
158
};
159
exports.generateProfilePicture = generateProfilePicture;
160
/** gets the SHA256 of the given media message */
161
const mediaMessageSHA256B64 = (message) => {
162
const media = Object.values(message)[0];
163
return (media === null || media === void 0 ? void 0 : media.fileSha256) && Buffer.from(media.fileSha256).toString('base64');
164
};
165
exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
166
async function getAudioDuration(buffer) {
167
const musicMetadata = await Promise.resolve().then(() => __importStar(require('music-metadata')));
168
let metadata;
169
if (Buffer.isBuffer(buffer)) {
170
metadata = await musicMetadata.parseBuffer(buffer, undefined, { duration: true });
171
}
172
else if (typeof buffer === 'string') {
173
const rStream = (0, fs_1.createReadStream)(buffer);
174
metadata = await musicMetadata.parseStream(rStream, undefined, { duration: true });
175
rStream.close();
176
}
177
else {
178
metadata = await musicMetadata.parseStream(buffer, undefined, { duration: true });
179
}
180
return metadata.format.duration;
181
}
182
exports.getAudioDuration = getAudioDuration;
183
const toReadable = (buffer) => {
184
const readable = new stream_1.Readable({ read: () => { } });
185
readable.push(buffer);
186
readable.push(null);
187
return readable;
188
};
189
exports.toReadable = toReadable;
190
const toBuffer = async (stream) => {
191
let buff = Buffer.alloc(0);
192
for await (const chunk of stream) {
193
buff = Buffer.concat([buff, chunk]);
194
}
195
stream.destroy();
196
return buff;
197
};
198
exports.toBuffer = toBuffer;
199
const getStream = async (item) => {
200
if (Buffer.isBuffer(item)) {
201
return { stream: (0, exports.toReadable)(item), type: 'buffer' };
202
}
203
if ('stream' in item) {
204
return { stream: item.stream, type: 'readable' };
205
}
206
if (item.url.toString().startsWith('http://') || item.url.toString().startsWith('https://')) {
207
return { stream: await (0, exports.getHttpStream)(item.url), type: 'remote' };
208
}
209
return { stream: (0, fs_1.createReadStream)(item.url), type: 'file' };
210
};
211
exports.getStream = getStream;
212
/** generates a thumbnail for a given media, if required */
213
async function generateThumbnail(file, mediaType, options) {
214
var _a;
215
let thumbnail;
216
if (mediaType === 'image') {
217
const buff = await (0, exports.extractImageThumb)(file);
218
thumbnail = buff.toString('base64');
219
}
220
else if (mediaType === 'video') {
221
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
222
try {
223
await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
224
const buff = await fs_1.promises.readFile(imgFilename);
225
thumbnail = buff.toString('base64');
226
await fs_1.promises.unlink(imgFilename);
227
}
228
catch (err) {
229
(_a = options.logger) === null || _a === void 0 ? void 0 : _a.debug('could not generate video thumb: ' + err);
230
}
231
}
232
return thumbnail;
233
}
234
exports.generateThumbnail = generateThumbnail;
235
const getHttpStream = async (url, options = {}) => {
236
const { default: axios } = await Promise.resolve().then(() => __importStar(require('axios')));
237
const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
238
return fetched.data;
239
};
240
exports.getHttpStream = getHttpStream;
241
const encryptedStream = async (media, mediaType, saveOriginalFileIfRequired = true, logger) => {
242
const { stream, type } = await (0, exports.getStream)(media);
243
logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
244
const mediaKey = Crypto.randomBytes(32);
245
const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
246
// random name
247
//const encBodyPath = join(getTmpFilesDirectory(), mediaType + generateMessageID() + '.enc')
248
// const encWriteStream = createWriteStream(encBodyPath)
249
const encWriteStream = new stream_1.Readable({ read: () => { } });
250
let bodyPath;
251
let writeStream;
252
let didSaveToTmpPath = false;
253
if (type === 'file') {
254
bodyPath = media.url;
255
}
256
else if (saveOriginalFileIfRequired) {
257
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
258
writeStream = (0, fs_1.createWriteStream)(bodyPath);
259
didSaveToTmpPath = true;
260
}
261
let fileLength = 0;
262
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
263
let hmac = Crypto.createHmac('sha256', macKey).update(iv);
264
let sha256Plain = Crypto.createHash('sha256');
265
let sha256Enc = Crypto.createHash('sha256');
266
const onChunk = (buff) => {
267
sha256Enc = sha256Enc.update(buff);
268
hmac = hmac.update(buff);
269
encWriteStream.push(buff);
270
};
271
try {
272
for await (const data of stream) {
273
fileLength += data.length;
274
sha256Plain = sha256Plain.update(data);
275
if (writeStream) {
276
if (!writeStream.write(data)) {
277
await (0, events_1.once)(writeStream, 'drain');
278
}
279
}
280
onChunk(aes.update(data));
281
}
282
onChunk(aes.final());
283
const mac = hmac.digest().slice(0, 10);
284
sha256Enc = sha256Enc.update(mac);
285
const fileSha256 = sha256Plain.digest();
286
const fileEncSha256 = sha256Enc.digest();
287
encWriteStream.push(mac);
288
encWriteStream.push(null);
289
writeStream && writeStream.end();
290
stream.destroy();
291
logger === null || logger === void 0 ? void 0 : logger.debug('encrypted data successfully');
292
return {
293
mediaKey,
294
encWriteStream,
295
bodyPath,
296
mac,
297
fileEncSha256,
298
fileSha256,
299
fileLength,
300
didSaveToTmpPath
301
};
302
}
303
catch (error) {
304
encWriteStream.destroy(error);
305
writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy(error);
306
aes.destroy(error);
307
hmac.destroy(error);
308
sha256Plain.destroy(error);
309
sha256Enc.destroy(error);
310
stream.destroy(error);
311
throw error;
312
}
313
};
314
exports.encryptedStream = encryptedStream;
315
const DEF_HOST = 'mmg.whatsapp.net';
316
const AES_CHUNK_SIZE = 16;
317
const toSmallestChunkSize = (num) => {
318
return Math.floor(num / AES_CHUNK_SIZE) * AES_CHUNK_SIZE;
319
};
320
const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
321
exports.getUrlFromDirectPath = getUrlFromDirectPath;
322
const downloadContentFromMessage = ({ mediaKey, directPath, url }, type, opts = {}) => {
323
const downloadUrl = url || (0, exports.getUrlFromDirectPath)(directPath);
324
const keys = getMediaKeys(mediaKey, type);
325
return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
326
};
327
exports.downloadContentFromMessage = downloadContentFromMessage;
328
/**
329
* Decrypts and downloads an AES256-CBC encrypted file given the keys.
330
* Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
331
* */
332
const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte } = {}) => {
333
let bytesFetched = 0;
334
let startChunk = 0;
335
let firstBlockIsIV = false;
336
// if a start byte is specified -- then we need to fetch the previous chunk as that will form the IV
337
if (startByte) {
338
const chunk = toSmallestChunkSize(startByte || 0);
339
if (chunk) {
340
startChunk = chunk - AES_CHUNK_SIZE;
341
bytesFetched = chunk;
342
firstBlockIsIV = true;
343
}
344
}
345
const endChunk = endByte ? toSmallestChunkSize(endByte || 0) + AES_CHUNK_SIZE : undefined;
346
const headers = {
347
Origin: Defaults_1.DEFAULT_ORIGIN,
348
};
349
if (startChunk || endChunk) {
350
headers.Range = `bytes=${startChunk}-`;
351
if (endChunk) {
352
headers.Range += endChunk;
353
}
354
}
355
// download the message
356
const fetched = await (0, exports.getHttpStream)(downloadUrl, {
357
headers,
358
maxBodyLength: Infinity,
359
maxContentLength: Infinity,
360
});
361
let remainingBytes = Buffer.from([]);
362
let aes;
363
const pushBytes = (bytes, push) => {
364
if (startByte || endByte) {
365
const start = bytesFetched >= startByte ? undefined : Math.max(startByte - bytesFetched, 0);
366
const end = bytesFetched + bytes.length < endByte ? undefined : Math.max(endByte - bytesFetched, 0);
367
push(bytes.slice(start, end));
368
bytesFetched += bytes.length;
369
}
370
else {
371
push(bytes);
372
}
373
};
374
const output = new stream_1.Transform({
375
transform(chunk, _, callback) {
376
let data = Buffer.concat([remainingBytes, chunk]);
377
const decryptLength = toSmallestChunkSize(data.length);
378
remainingBytes = data.slice(decryptLength);
379
data = data.slice(0, decryptLength);
380
if (!aes) {
381
let ivValue = iv;
382
if (firstBlockIsIV) {
383
ivValue = data.slice(0, AES_CHUNK_SIZE);
384
data = data.slice(AES_CHUNK_SIZE);
385
}
386
aes = Crypto.createDecipheriv('aes-256-cbc', cipherKey, ivValue);
387
// if an end byte that is not EOF is specified
388
// stop auto padding (PKCS7) -- otherwise throws an error for decryption
389
if (endByte) {
390
aes.setAutoPadding(false);
391
}
392
}
393
try {
394
pushBytes(aes.update(data), b => this.push(b));
395
callback();
396
}
397
catch (error) {
398
callback(error);
399
}
400
},
401
final(callback) {
402
try {
403
pushBytes(aes.final(), b => this.push(b));
404
callback();
405
}
406
catch (error) {
407
callback(error);
408
}
409
},
410
});
411
return fetched.pipe(output, { end: true });
412
};
413
exports.downloadEncryptedContent = downloadEncryptedContent;
414
function extensionForMediaMessage(message) {
415
const getExtension = (mimetype) => mimetype.split(';')[0].split('/')[1];
416
const type = Object.keys(message)[0];
417
let extension;
418
if (type === 'locationMessage' ||
419
type === 'liveLocationMessage' ||
420
type === 'productMessage') {
421
extension = '.jpeg';
422
}
423
else {
424
const messageContent = message[type];
425
extension = getExtension(messageContent.mimetype);
426
}
427
return extension;
428
}
429
exports.extensionForMediaMessage = extensionForMediaMessage;
430
const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger }, refreshMediaConn) => {
431
return async (stream, { mediaType, fileEncSha256B64, timeoutMs }) => {
432
var _a, _b;
433
const { default: axios } = await Promise.resolve().then(() => __importStar(require('axios')));
434
// send a query JSON to obtain the url & auth token to upload our media
435
let uploadInfo = await refreshMediaConn(false);
436
let urls;
437
const hosts = [...customUploadHosts, ...uploadInfo.hosts];
438
const chunks = [];
439
for await (const chunk of stream) {
440
chunks.push(chunk);
441
}
442
const reqBody = Buffer.concat(chunks);
443
for (const { hostname, maxContentLengthBytes } of hosts) {
444
logger.debug(`uploading to "${hostname}"`);
445
const auth = encodeURIComponent(uploadInfo.auth); // the auth token
446
const url = `https://${hostname}${Defaults_1.MEDIA_PATH_MAP[mediaType]}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
447
let result;
448
try {
449
if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
450
throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
451
}
452
const body = await axios.post(url, reqBody, {
453
headers: {
454
'Content-Type': 'application/octet-stream',
455
'Origin': Defaults_1.DEFAULT_ORIGIN
456
},
457
httpsAgent: fetchAgent,
458
timeout: timeoutMs,
459
responseType: 'json',
460
maxBodyLength: Infinity,
461
maxContentLength: Infinity,
462
});
463
result = body.data;
464
if ((result === null || result === void 0 ? void 0 : result.url) || (result === null || result === void 0 ? void 0 : result.directPath)) {
465
urls = {
466
mediaUrl: result.url,
467
directPath: result.direct_path
468
};
469
break;
470
}
471
else {
472
uploadInfo = await refreshMediaConn(true);
473
throw new Error(`upload failed, reason: ${JSON.stringify(result)}`);
474
}
475
}
476
catch (error) {
477
if (axios.isAxiosError(error)) {
478
result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
479
}
480
const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
481
logger.warn({ trace: error.stack, uploadResult: result }, `Error in uploading to ${hostname} ${isLast ? '' : ', retrying...'}`);
482
}
483
}
484
if (!urls) {
485
throw new boom_1.Boom('Media upload failed on all hosts', { statusCode: 500 });
486
}
487
return urls;
488
};
489
};
490
exports.getWAUploadToServer = getWAUploadToServer;
491
const getMediaRetryKey = (mediaKey) => {
492
return (0, crypto_1.hkdf)(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
493
};
494
/**
495
* Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
496
*/
497
const encryptMediaRetryRequest = (key, mediaKey, meId) => {
498
const recp = { stanzaId: key.id };
499
const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
500
const iv = Crypto.randomBytes(12);
501
const retryKey = getMediaRetryKey(mediaKey);
502
const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
503
const req = {
504
tag: 'receipt',
505
attrs: {
506
id: key.id,
507
to: (0, WABinary_1.jidNormalizedUser)(meId),
508
type: 'server-error'
509
},
510
content: [
511
// this encrypt node is actually pretty useless
512
// the media is returned even without this node
513
// keeping it here to maintain parity with WA Web
514
{
515
tag: 'encrypt',
516
attrs: {},
517
content: [
518
{ tag: 'enc_p', attrs: {}, content: ciphertext },
519
{ tag: 'enc_iv', attrs: {}, content: iv }
520
]
521
},
522
{
523
tag: 'rmr',
524
attrs: {
525
jid: key.remoteJid,
526
from_me: (!!key.fromMe).toString(),
527
// @ts-ignore
528
participant: key.participant || undefined
529
}
530
}
531
]
532
};
533
return req;
534
};
535
exports.encryptMediaRetryRequest = encryptMediaRetryRequest;
536
const decodeMediaRetryNode = (node) => {
537
const rmrNode = (0, WABinary_1.getBinaryNodeChild)(node, 'rmr');
538
const event = {
539
key: {
540
id: node.attrs.id,
541
remoteJid: rmrNode.attrs.jid,
542
fromMe: rmrNode.attrs.from_me === 'true',
543
participant: rmrNode.attrs.participant
544
}
545
};
546
const errorNode = (0, WABinary_1.getBinaryNodeChild)(node, 'error');
547
if (errorNode) {
548
const errorCode = +errorNode.attrs.code;
549
event.error = new boom_1.Boom(`Failed to re-upload media (${errorCode})`, { data: errorNode.attrs, statusCode: (0, exports.getStatusCodeForMediaRetry)(errorCode) });
550
}
551
else {
552
const encryptedInfoNode = (0, WABinary_1.getBinaryNodeChild)(node, 'encrypt');
553
const ciphertext = (0, WABinary_1.getBinaryNodeChildBuffer)(encryptedInfoNode, 'enc_p');
554
const iv = (0, WABinary_1.getBinaryNodeChildBuffer)(encryptedInfoNode, 'enc_iv');
555
if (ciphertext && iv) {
556
event.media = { ciphertext, iv };
557
}
558
else {
559
event.error = new boom_1.Boom('Failed to re-upload media (missing ciphertext)', { statusCode: 404 });
560
}
561
}
562
return event;
563
};
564
exports.decodeMediaRetryNode = decodeMediaRetryNode;
565
const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
566
const retryKey = getMediaRetryKey(mediaKey);
567
const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
568
return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
569
};
570
exports.decryptMediaRetryData = decryptMediaRetryData;
571
const getStatusCodeForMediaRetry = (code) => MEDIA_RETRY_STATUS_MAP[code];
572
exports.getStatusCodeForMediaRetry = getStatusCodeForMediaRetry;
573
const MEDIA_RETRY_STATUS_MAP = {
574
[WAProto_1.proto.MediaRetryNotification.ResultType.SUCCESS]: 200,
575
[WAProto_1.proto.MediaRetryNotification.ResultType.DECRYPTION_ERROR]: 412,
576
[WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
577
[WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
578
};
579
580