@genuxofficial/baileys 3.0.0 → 4.0.0
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/WAProto/WAProto.proto +24 -206
- package/WAProto/index.d.ts +219 -2233
- package/WAProto/index.js +525 -6773
- package/WAProto/shizo.x +1 -0
- package/lib/Defaults/baileys-version.json +1 -1
- package/lib/Defaults/index.d.ts +231 -0
- package/lib/Defaults/index.js +17 -1
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Socket/Client/index.d.ts +3 -2
- package/lib/Socket/Client/index.js +3 -2
- package/lib/Socket/Client/mobile-socket-client.d.ts +13 -0
- package/lib/Socket/Client/mobile-socket-client.js +65 -0
- package/lib/Socket/Client/{websocket.d.ts → web-socket-client.d.ts} +1 -1
- package/lib/Socket/Client/{websocket.js → web-socket-client.js} +2 -2
- package/lib/Socket/business.d.ts +7 -9
- package/lib/Socket/chats.d.ts +5 -8
- package/lib/Socket/chats.js +8 -38
- package/lib/Socket/groups.d.ts +5 -7
- package/lib/Socket/groups.js +2 -14
- package/lib/Socket/index.d.ts +9 -9
- package/lib/Socket/index.js +2 -2
- package/lib/Socket/messages-recv.d.ts +8 -10
- package/lib/Socket/messages-recv.js +11 -18
- package/lib/Socket/messages-send.d.ts +7 -14
- package/lib/Socket/messages-send.js +13 -36
- package/lib/Socket/newsletter.d.ts +7 -9
- package/lib/Socket/newsletter.js +3 -11
- package/lib/Socket/registration.d.ts +271 -0
- package/lib/Socket/registration.js +166 -0
- package/lib/Socket/socket.d.ts +4 -5
- package/lib/Socket/socket.js +18 -15
- package/lib/Socket/usync.d.ts +4 -4
- package/lib/Store/index.d.ts +2 -1
- package/lib/Store/index.js +3 -1
- package/lib/Store/make-cache-manager-store.d.ts +14 -0
- package/lib/Store/make-cache-manager-store.js +83 -0
- package/lib/Store/make-in-memory-store.js +10 -8
- package/lib/Store/make-ordered-dictionary.js +2 -2
- package/lib/Types/Auth.d.ts +6 -0
- package/lib/Types/Chat.d.ts +0 -4
- package/lib/Types/Contact.d.ts +1 -1
- package/lib/Types/GroupMetadata.d.ts +0 -6
- package/lib/Types/Message.d.ts +5 -29
- package/lib/Types/Message.js +2 -0
- package/lib/Types/Socket.d.ts +4 -7
- package/lib/Utils/auth-utils.d.ts +1 -1
- package/lib/Utils/auth-utils.js +9 -2
- package/lib/Utils/business.js +3 -15
- package/lib/Utils/chat-utils.d.ts +4 -4
- package/lib/Utils/chat-utils.js +2 -1
- package/lib/Utils/decode-wa-message.d.ts +2 -4
- package/lib/Utils/decode-wa-message.js +24 -145
- package/lib/Utils/event-buffer.js +6 -4
- package/lib/Utils/generics.d.ts +4 -7
- package/lib/Utils/generics.js +17 -9
- package/lib/Utils/lt-hash.d.ts +3 -3
- package/lib/Utils/lt-hash.js +45 -11
- package/lib/Utils/messages-media.d.ts +4 -4
- package/lib/Utils/messages-media.js +57 -69
- package/lib/Utils/messages.js +39 -33
- package/lib/Utils/noise-handler.d.ts +2 -1
- package/lib/Utils/noise-handler.js +10 -5
- package/lib/Utils/use-multi-file-auth-state.js +11 -48
- package/lib/Utils/validate-connection.d.ts +1 -0
- package/lib/Utils/validate-connection.js +44 -10
- package/lib/WABinary/constants.js +5 -5
- package/lib/WABinary/encode.js +10 -23
- package/lib/WABinary/generic-utils.d.ts +5 -3
- package/lib/WABinary/generic-utils.js +19 -34
- package/lib/WABinary/jid-utils.d.ts +2 -11
- package/lib/WABinary/jid-utils.js +2 -27
- package/lib/WAM/BinaryInfo.d.ts +2 -2
- package/lib/WAM/constants.d.ts +2 -3
- package/lib/WAM/encode.js +2 -2
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +12 -21
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +3 -3
- package/lib/WAUSync/USyncQuery.d.ts +0 -2
- package/lib/WAUSync/USyncQuery.js +0 -10
- package/lib/WAUSync/USyncUser.d.ts +0 -2
- package/lib/WAUSync/USyncUser.js +0 -4
- package/package.json +5 -6
- package/LICENSE +0 -21
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +0 -25
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +0 -53
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -8
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +0 -24
- /package/lib/Socket/Client/{types.d.ts → abstract-socket-client.d.ts} +0 -0
- /package/lib/Socket/Client/{types.js → abstract-socket-client.js} +0 -0
@@ -282,7 +282,7 @@ async function generateThumbnail(file, mediaType, options) {
|
|
282
282
|
}
|
283
283
|
}
|
284
284
|
else if (mediaType === 'video') {
|
285
|
-
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.
|
285
|
+
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
|
286
286
|
try {
|
287
287
|
await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
|
288
288
|
const buff = await fs_1.promises.readFile(imgFilename);
|
@@ -307,34 +307,25 @@ exports.getHttpStream = getHttpStream;
|
|
307
307
|
const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
|
308
308
|
const { stream, type } = await (0, exports.getStream)(media, opts);
|
309
309
|
logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
|
310
|
-
const encFilePath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)() + '-enc');
|
311
|
-
const encFileWriteStream = (0, fs_1.createWriteStream)(encFilePath);
|
312
|
-
let originalFilePath;
|
313
|
-
let didSaveToTmpPath = false;
|
314
310
|
let bodyPath;
|
311
|
+
let didSaveToTmpPath = false;
|
315
312
|
try {
|
316
313
|
const buffer = await (0, exports.toBuffer)(stream);
|
317
|
-
|
318
|
-
encFileWriteStream.write(buffer);
|
319
|
-
encFileWriteStream.end();
|
320
|
-
// Save original file if required
|
321
|
-
if (saveOriginalFileIfRequired) {
|
322
|
-
originalFilePath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)() + '-original');
|
323
|
-
(0, fs_1.writeFileSync)(originalFilePath, buffer);
|
324
|
-
bodyPath = originalFilePath;
|
325
|
-
didSaveToTmpPath = true;
|
326
|
-
}
|
327
|
-
else if (type === 'file' && typeof media.url === 'string') {
|
314
|
+
if (type === 'file') {
|
328
315
|
bodyPath = media.url;
|
329
316
|
}
|
317
|
+
else if (saveOriginalFileIfRequired) {
|
318
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
319
|
+
(0, fs_1.writeFileSync)(bodyPath, buffer);
|
320
|
+
didSaveToTmpPath = true;
|
321
|
+
}
|
330
322
|
const fileLength = buffer.length;
|
331
323
|
const fileSha256 = Crypto.createHash('sha256').update(buffer).digest();
|
332
324
|
stream === null || stream === void 0 ? void 0 : stream.destroy();
|
333
|
-
logger === null || logger === void 0 ? void 0 : logger.debug('
|
325
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('prepare stream data successfully');
|
334
326
|
return {
|
335
327
|
mediaKey: undefined,
|
336
|
-
|
337
|
-
originalFilePath,
|
328
|
+
encWriteStream: buffer,
|
338
329
|
fileLength,
|
339
330
|
fileSha256,
|
340
331
|
fileEncSha256: undefined,
|
@@ -343,17 +334,14 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
343
334
|
};
|
344
335
|
}
|
345
336
|
catch (error) {
|
337
|
+
// destroy all streams with error
|
346
338
|
stream.destroy();
|
347
|
-
|
348
|
-
await fs_1.promises.unlink(encFilePath);
|
349
|
-
}
|
350
|
-
catch (_) { }
|
351
|
-
if (didSaveToTmpPath && bodyPath) {
|
339
|
+
if (didSaveToTmpPath) {
|
352
340
|
try {
|
353
341
|
await fs_1.promises.unlink(bodyPath);
|
354
342
|
}
|
355
343
|
catch (err) {
|
356
|
-
logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to
|
344
|
+
logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
|
357
345
|
}
|
358
346
|
}
|
359
347
|
throw error;
|
@@ -361,29 +349,27 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
361
349
|
};
|
362
350
|
exports.prepareStream = prepareStream;
|
363
351
|
const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
|
364
|
-
var _a, _b;
|
365
352
|
const { stream, type } = await (0, exports.getStream)(media, opts);
|
366
353
|
logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
|
367
354
|
const mediaKey = Crypto.randomBytes(32);
|
368
355
|
const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
|
369
|
-
const
|
370
|
-
|
371
|
-
let
|
372
|
-
let
|
373
|
-
if (
|
374
|
-
|
375
|
-
|
356
|
+
const encWriteStream = new stream_1.Readable({ read: () => { } });
|
357
|
+
let bodyPath;
|
358
|
+
let writeStream;
|
359
|
+
let didSaveToTmpPath = false;
|
360
|
+
if (type === 'file') {
|
361
|
+
bodyPath = media.url;
|
362
|
+
}
|
363
|
+
else if (saveOriginalFileIfRequired) {
|
364
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
365
|
+
writeStream = (0, fs_1.createWriteStream)(bodyPath);
|
366
|
+
didSaveToTmpPath = true;
|
376
367
|
}
|
377
368
|
let fileLength = 0;
|
378
369
|
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
|
379
370
|
let hmac = Crypto.createHmac('sha256', macKey).update(iv);
|
380
371
|
let sha256Plain = Crypto.createHash('sha256');
|
381
372
|
let sha256Enc = Crypto.createHash('sha256');
|
382
|
-
const onChunk = (buff) => {
|
383
|
-
sha256Enc.update(buff);
|
384
|
-
hmac.update(buff);
|
385
|
-
encFileWriteStream.write(buff);
|
386
|
-
};
|
387
373
|
try {
|
388
374
|
for await (const data of stream) {
|
389
375
|
fileLength += data.length;
|
@@ -394,12 +380,12 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
394
380
|
data: { media, type }
|
395
381
|
});
|
396
382
|
}
|
397
|
-
|
398
|
-
|
399
|
-
|
383
|
+
sha256Plain = sha256Plain.update(data);
|
384
|
+
if (writeStream) {
|
385
|
+
if (!writeStream.write(data)) {
|
386
|
+
await (0, events_1.once)(writeStream, 'drain');
|
400
387
|
}
|
401
388
|
}
|
402
|
-
sha256Plain.update(data);
|
403
389
|
onChunk(aes.update(data));
|
404
390
|
}
|
405
391
|
onChunk(aes.final());
|
@@ -407,43 +393,46 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
407
393
|
sha256Enc = sha256Enc.update(mac);
|
408
394
|
const fileSha256 = sha256Plain.digest();
|
409
395
|
const fileEncSha256 = sha256Enc.digest();
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
encFileWriteStream.end();
|
414
|
-
(_a = originalFileStream === null || originalFileStream === void 0 ? void 0 : originalFileStream.end) === null || _a === void 0 ? void 0 : _a.call(originalFileStream);
|
396
|
+
encWriteStream.push(mac);
|
397
|
+
encWriteStream.push(null);
|
398
|
+
writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
|
415
399
|
stream.destroy();
|
416
400
|
logger === null || logger === void 0 ? void 0 : logger.debug('encrypted data successfully');
|
417
401
|
return {
|
418
402
|
mediaKey,
|
419
|
-
|
420
|
-
|
403
|
+
encWriteStream,
|
404
|
+
bodyPath,
|
421
405
|
mac,
|
422
406
|
fileEncSha256,
|
423
407
|
fileSha256,
|
424
|
-
fileLength
|
408
|
+
fileLength,
|
409
|
+
didSaveToTmpPath
|
425
410
|
};
|
426
411
|
}
|
427
412
|
catch (error) {
|
428
413
|
// destroy all streams with error
|
429
|
-
|
430
|
-
|
414
|
+
encWriteStream.destroy();
|
415
|
+
writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
|
431
416
|
aes.destroy();
|
432
417
|
hmac.destroy();
|
433
418
|
sha256Plain.destroy();
|
434
419
|
sha256Enc.destroy();
|
435
420
|
stream.destroy();
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
421
|
+
if (didSaveToTmpPath) {
|
422
|
+
try {
|
423
|
+
await fs_1.promises.unlink(bodyPath);
|
424
|
+
}
|
425
|
+
catch (err) {
|
426
|
+
logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
|
440
427
|
}
|
441
|
-
}
|
442
|
-
catch (err) {
|
443
|
-
logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed deleting tmp files');
|
444
428
|
}
|
445
429
|
throw error;
|
446
430
|
}
|
431
|
+
function onChunk(buff) {
|
432
|
+
sha256Enc = sha256Enc.update(buff);
|
433
|
+
hmac = hmac.update(buff);
|
434
|
+
encWriteStream.push(buff);
|
435
|
+
}
|
447
436
|
};
|
448
437
|
exports.encryptedStream = encryptedStream;
|
449
438
|
const DEF_HOST = 'mmg.whatsapp.net';
|
@@ -564,19 +553,19 @@ function extensionForMediaMessage(message) {
|
|
564
553
|
}
|
565
554
|
exports.extensionForMediaMessage = extensionForMediaMessage;
|
566
555
|
const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
567
|
-
return async (
|
556
|
+
return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
|
568
557
|
var _a, _b;
|
569
558
|
// send a query JSON to obtain the url & auth token to upload our media
|
570
559
|
let uploadInfo = await refreshMediaConn(false);
|
571
560
|
let urls;
|
572
561
|
const hosts = [...customUploadHosts, ...uploadInfo.hosts];
|
573
|
-
|
562
|
+
const chunks = [];
|
574
563
|
if (!Buffer.isBuffer(stream)) {
|
575
564
|
for await (const chunk of stream) {
|
576
|
-
chunks.push(chunk)
|
565
|
+
chunks.push(chunk);
|
577
566
|
}
|
578
|
-
}
|
579
|
-
|
567
|
+
}
|
568
|
+
const reqBody = Buffer.isBuffer(stream) ? stream : Buffer.concat(chunks);
|
580
569
|
fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
|
581
570
|
let media = Defaults_1.MEDIA_PATH_MAP[mediaType];
|
582
571
|
if (newsletter) {
|
@@ -588,12 +577,11 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
|
|
588
577
|
const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
|
589
578
|
let result;
|
590
579
|
try {
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
const body = await axios_1.default.post(url,
|
580
|
+
if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
|
581
|
+
throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
|
582
|
+
}
|
583
|
+
const body = await axios_1.default.post(url, reqBody, {
|
595
584
|
...options,
|
596
|
-
maxRedirects: 0,
|
597
585
|
headers: {
|
598
586
|
...options.headers || {},
|
599
587
|
'Content-Type': 'application/octet-stream',
|
package/lib/Utils/messages.js
CHANGED
@@ -81,17 +81,20 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
81
81
|
media: message[mediaType]
|
82
82
|
};
|
83
83
|
delete uploadData[mediaType];
|
84
|
+
// check if cacheable + generate cache key
|
84
85
|
const cacheableKey = typeof uploadData.media === 'object' &&
|
85
|
-
'url' in uploadData.media &&
|
86
|
+
('url' in uploadData.media) &&
|
86
87
|
!!uploadData.media.url &&
|
87
|
-
!!options.mediaCache &&
|
88
|
-
|
88
|
+
!!options.mediaCache && (
|
89
|
+
// generate the key
|
90
|
+
mediaType + ':' + uploadData.media.url.toString());
|
89
91
|
if (mediaType === 'document' && !uploadData.fileName) {
|
90
92
|
uploadData.fileName = 'file';
|
91
93
|
}
|
92
94
|
if (!uploadData.mimetype) {
|
93
95
|
uploadData.mimetype = MIMETYPE_MAP[mediaType];
|
94
96
|
}
|
97
|
+
// check for cache hit
|
95
98
|
if (cacheableKey) {
|
96
99
|
const mediaBuff = options.mediaCache.get(cacheableKey);
|
97
100
|
if (mediaBuff) {
|
@@ -103,26 +106,28 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
103
106
|
}
|
104
107
|
}
|
105
108
|
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
|
106
|
-
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
|
109
|
+
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
|
110
|
+
(typeof uploadData['jpegThumbnail'] === 'undefined');
|
107
111
|
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
|
108
112
|
const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
|
109
113
|
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
|
110
|
-
const { mediaKey,
|
114
|
+
const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
|
111
115
|
logger,
|
112
116
|
saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
|
113
117
|
opts: options.options
|
114
118
|
});
|
119
|
+
// url safe Base64 encode the SHA256 hash of the body
|
115
120
|
const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256).toString('base64');
|
116
121
|
const [{ mediaUrl, directPath, handle }] = await Promise.all([
|
117
122
|
(async () => {
|
118
|
-
const result = await options.upload(
|
123
|
+
const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
|
119
124
|
logger === null || logger === void 0 ? void 0 : logger.debug({ mediaType, cacheableKey }, 'uploaded media');
|
120
125
|
return result;
|
121
126
|
})(),
|
122
127
|
(async () => {
|
123
128
|
try {
|
124
129
|
if (requiresThumbnailComputation) {
|
125
|
-
const { thumbnail, originalImageDimensions } = await (0, messages_media_1.generateThumbnail)(
|
130
|
+
const { thumbnail, originalImageDimensions } = await (0, messages_media_1.generateThumbnail)(bodyPath, mediaType, options);
|
126
131
|
uploadData.jpegThumbnail = thumbnail;
|
127
132
|
if (!uploadData.width && originalImageDimensions) {
|
128
133
|
uploadData.width = originalImageDimensions.width;
|
@@ -132,11 +137,11 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
132
137
|
logger === null || logger === void 0 ? void 0 : logger.debug('generated thumbnail');
|
133
138
|
}
|
134
139
|
if (requiresDurationComputation) {
|
135
|
-
uploadData.seconds = await (0, messages_media_1.getAudioDuration)(
|
140
|
+
uploadData.seconds = await (0, messages_media_1.getAudioDuration)(bodyPath);
|
136
141
|
logger === null || logger === void 0 ? void 0 : logger.debug('computed audio duration');
|
137
142
|
}
|
138
143
|
if (requiresWaveformProcessing) {
|
139
|
-
uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(
|
144
|
+
uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(bodyPath, logger);
|
140
145
|
logger === null || logger === void 0 ? void 0 : logger.debug('processed waveform');
|
141
146
|
}
|
142
147
|
if (requiresAudioBackground) {
|
@@ -150,15 +155,19 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
150
155
|
})(),
|
151
156
|
])
|
152
157
|
.finally(async () => {
|
153
|
-
|
154
|
-
|
155
|
-
if (originalFilePath) {
|
156
|
-
await fs_1.promises.unlink(originalFilePath);
|
157
|
-
}
|
158
|
-
logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp files');
|
158
|
+
if (!Buffer.isBuffer(encWriteStream)) {
|
159
|
+
encWriteStream.destroy();
|
159
160
|
}
|
160
|
-
|
161
|
-
|
161
|
+
// remove tmp files
|
162
|
+
if (didSaveToTmpPath && bodyPath) {
|
163
|
+
try {
|
164
|
+
await fs_1.promises.access(bodyPath);
|
165
|
+
await fs_1.promises.unlink(bodyPath);
|
166
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp file');
|
167
|
+
}
|
168
|
+
catch (error) {
|
169
|
+
logger === null || logger === void 0 ? void 0 : logger.warn('failed to remove tmp file');
|
170
|
+
}
|
162
171
|
}
|
163
172
|
});
|
164
173
|
const obj = Types_1.WAProto.Message.fromObject({
|
@@ -265,10 +274,6 @@ const generateWAMessageContent = async (message, options) => {
|
|
265
274
|
extContent.font = options.font;
|
266
275
|
}
|
267
276
|
m.extendedTextMessage = extContent;
|
268
|
-
//WhatsApp always sends secretMessage along with the text message
|
269
|
-
m.messageContextInfo = {
|
270
|
-
messageSecret: (0, crypto_1.randomBytes)(32)
|
271
|
-
};
|
272
277
|
}
|
273
278
|
else if ('contacts' in message) {
|
274
279
|
const contactLen = message.contacts.contacts.length;
|
@@ -728,7 +733,7 @@ const generateWAMessageFromContent = (jid, message, options) => {
|
|
728
733
|
key: {
|
729
734
|
remoteJid: jid,
|
730
735
|
fromMe: true,
|
731
|
-
id: (options === null || options === void 0 ? void 0 : options.messageId) || (0, generics_1.
|
736
|
+
id: (options === null || options === void 0 ? void 0 : options.messageId) || (0, generics_1.generateMessageID)(),
|
732
737
|
},
|
733
738
|
message: message,
|
734
739
|
messageTimestamp: timestamp,
|
@@ -792,10 +797,7 @@ const normalizeMessageContent = (content) => {
|
|
792
797
|
|| (message === null || message === void 0 ? void 0 : message.pollCreationMessageV4)
|
793
798
|
|| (message === null || message === void 0 ? void 0 : message.pollCreationMessageV5)
|
794
799
|
|| (message === null || message === void 0 ? void 0 : message.statusAddYours)
|
795
|
-
|| (message === null || message === void 0 ? void 0 : message.groupStatusMessage)
|
796
|
-
|| (message === null || message === void 0 ? void 0 : message.limitSharingMessage)
|
797
|
-
|| (message === null || message === void 0 ? void 0 : message.botTaskMessage)
|
798
|
-
|| (message === null || message === void 0 ? void 0 : message.questionMessage));
|
800
|
+
|| (message === null || message === void 0 ? void 0 : message.groupStatusMessage));
|
799
801
|
}
|
800
802
|
};
|
801
803
|
exports.normalizeMessageContent = normalizeMessageContent;
|
@@ -951,13 +953,17 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
951
953
|
const result = await downloadMsg()
|
952
954
|
.catch(async (error) => {
|
953
955
|
var _a;
|
954
|
-
if (ctx
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
956
|
+
if (ctx) {
|
957
|
+
if (axios_1.default.isAxiosError(error)) {
|
958
|
+
// check if the message requires a reupload
|
959
|
+
if (REUPLOAD_REQUIRED_STATUS.includes((_a = error.response) === null || _a === void 0 ? void 0 : _a.status)) {
|
960
|
+
ctx.logger.info({ key: message.key }, 'sending reupload media request...');
|
961
|
+
// request reupload
|
962
|
+
message = await ctx.reuploadRequest(message);
|
963
|
+
const result = await downloadMsg();
|
964
|
+
return result;
|
965
|
+
}
|
966
|
+
}
|
961
967
|
}
|
962
968
|
throw error;
|
963
969
|
});
|
@@ -4,9 +4,10 @@ import { ILogger } from './logger';
|
|
4
4
|
import { proto } from '../../WAProto';
|
5
5
|
import { KeyPair } from '../Types';
|
6
6
|
import { BinaryNode } from '../WABinary';
|
7
|
-
export declare const makeNoiseHandler: ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, logger, routingInfo }: {
|
7
|
+
export declare const makeNoiseHandler: ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, mobile, logger, routingInfo }: {
|
8
8
|
keyPair: KeyPair;
|
9
9
|
NOISE_HEADER: Uint8Array;
|
10
|
+
mobile: boolean;
|
10
11
|
logger: ILogger;
|
11
12
|
routingInfo?: Buffer | undefined;
|
12
13
|
}) => {
|
@@ -11,7 +11,7 @@ const generateIV = (counter) => {
|
|
11
11
|
new DataView(iv).setUint32(8, counter);
|
12
12
|
return new Uint8Array(iv);
|
13
13
|
};
|
14
|
-
const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, logger, routingInfo }) => {
|
14
|
+
const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, mobile, logger, routingInfo }) => {
|
15
15
|
logger = logger.child({ class: 'ns' });
|
16
16
|
const authenticate = (data) => {
|
17
17
|
if (!isFinished) {
|
@@ -83,10 +83,15 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
|
|
83
83
|
const decStaticContent = decrypt(serverHello.static);
|
84
84
|
await mixIntoKey(crypto_1.Curve.sharedKey(privateKey, decStaticContent));
|
85
85
|
const certDecoded = decrypt(serverHello.payload);
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
if (mobile) {
|
87
|
+
WAProto_1.proto.CertChain.NoiseCertificate.decode(certDecoded);
|
88
|
+
}
|
89
|
+
else {
|
90
|
+
const { intermediate: certIntermediate } = WAProto_1.proto.CertChain.decode(certDecoded);
|
91
|
+
const { issuerSerial } = WAProto_1.proto.CertChain.NoiseCertificate.Details.decode(certIntermediate.details);
|
92
|
+
if (issuerSerial !== Defaults_1.WA_CERT_DETAILS.SERIAL) {
|
93
|
+
throw new boom_1.Boom('certification match failed', { statusCode: 400 });
|
94
|
+
}
|
90
95
|
}
|
91
96
|
const keyEnc = encrypt(noiseKey.public);
|
92
97
|
await mixIntoKey(crypto_1.Curve.sharedKey(noiseKey.private, serverHello.ephemeral));
|
@@ -1,26 +1,16 @@
|
|
1
1
|
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
6
|
exports.useMultiFileAuthState = void 0;
|
4
|
-
const async_mutex_1 = require("async-mutex");
|
5
7
|
const promises_1 = require("fs/promises");
|
6
8
|
const path_1 = require("path");
|
7
9
|
const WAProto_1 = require("../../WAProto");
|
8
10
|
const auth_utils_1 = require("./auth-utils");
|
9
11
|
const generics_1 = require("./generics");
|
10
|
-
|
11
|
-
|
12
|
-
// https://github.com/nodejs/node/issues/26338
|
13
|
-
// Use a Map to store mutexes for each file path
|
14
|
-
const fileLocks = new Map();
|
15
|
-
// Get or create a mutex for a specific file path
|
16
|
-
const getFileLock = (path) => {
|
17
|
-
let mutex = fileLocks.get(path);
|
18
|
-
if (!mutex) {
|
19
|
-
mutex = new async_mutex_1.Mutex();
|
20
|
-
fileLocks.set(path, mutex);
|
21
|
-
}
|
22
|
-
return mutex;
|
23
|
-
};
|
12
|
+
const async_lock_1 = __importDefault(require("async-lock"));
|
13
|
+
const fileLock = new async_lock_1.default({ maxPending: Infinity });
|
24
14
|
/**
|
25
15
|
* stores the full authentication state in a single folder.
|
26
16
|
* Far more efficient than singlefileauthstate
|
@@ -29,32 +19,15 @@ const getFileLock = (path) => {
|
|
29
19
|
* Would recommend writing an auth state for use with a proper SQL or No-SQL DB
|
30
20
|
* */
|
31
21
|
const useMultiFileAuthState = async (folder) => {
|
32
|
-
|
33
|
-
const writeData = async (data, file) => {
|
22
|
+
const writeData = (data, file) => {
|
34
23
|
const filePath = (0, path_1.join)(folder, fixFileName(file));
|
35
|
-
|
36
|
-
return mutex.acquire().then(async (release) => {
|
37
|
-
try {
|
38
|
-
await (0, promises_1.writeFile)(filePath, JSON.stringify(data, generics_1.BufferJSON.replacer));
|
39
|
-
}
|
40
|
-
finally {
|
41
|
-
release();
|
42
|
-
}
|
43
|
-
});
|
24
|
+
return fileLock.acquire(filePath, () => (0, promises_1.writeFile)((0, path_1.join)(filePath), JSON.stringify(data, generics_1.BufferJSON.replacer)));
|
44
25
|
};
|
45
26
|
const readData = async (file) => {
|
46
27
|
try {
|
47
28
|
const filePath = (0, path_1.join)(folder, fixFileName(file));
|
48
|
-
const
|
49
|
-
return
|
50
|
-
try {
|
51
|
-
const data = await (0, promises_1.readFile)(filePath, { encoding: 'utf-8' });
|
52
|
-
return JSON.parse(data, generics_1.BufferJSON.reviver);
|
53
|
-
}
|
54
|
-
finally {
|
55
|
-
release();
|
56
|
-
}
|
57
|
-
});
|
29
|
+
const data = await fileLock.acquire(filePath, () => (0, promises_1.readFile)(filePath, { encoding: 'utf-8' }));
|
30
|
+
return JSON.parse(data, generics_1.BufferJSON.reviver);
|
58
31
|
}
|
59
32
|
catch (error) {
|
60
33
|
return null;
|
@@ -63,17 +36,7 @@ const useMultiFileAuthState = async (folder) => {
|
|
63
36
|
const removeData = async (file) => {
|
64
37
|
try {
|
65
38
|
const filePath = (0, path_1.join)(folder, fixFileName(file));
|
66
|
-
|
67
|
-
return mutex.acquire().then(async (release) => {
|
68
|
-
try {
|
69
|
-
await (0, promises_1.unlink)(filePath);
|
70
|
-
}
|
71
|
-
catch (_a) {
|
72
|
-
}
|
73
|
-
finally {
|
74
|
-
release();
|
75
|
-
}
|
76
|
-
});
|
39
|
+
await fileLock.acquire(filePath, () => (0, promises_1.unlink)(filePath));
|
77
40
|
}
|
78
41
|
catch (_a) {
|
79
42
|
}
|
@@ -117,7 +80,7 @@ const useMultiFileAuthState = async (folder) => {
|
|
117
80
|
}
|
118
81
|
}
|
119
82
|
},
|
120
|
-
saveCreds:
|
83
|
+
saveCreds: () => {
|
121
84
|
return writeData(creds, 'creds.json');
|
122
85
|
}
|
123
86
|
};
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { proto } from '../../WAProto';
|
2
2
|
import type { AuthenticationCreds, SignalCreds, SocketConfig } from '../Types';
|
3
3
|
import { BinaryNode } from '../WABinary';
|
4
|
+
export declare const generateMobileNode: (config: SocketConfig) => proto.IClientPayload;
|
4
5
|
export declare const generateLoginNode: (userJid: string, config: SocketConfig) => proto.IClientPayload;
|
5
6
|
export declare const generateRegistrationNode: ({ registrationId, signedPreKey, signedIdentityKey }: SignalCreds, config: SocketConfig) => proto.ClientPayload;
|
6
7
|
export declare const configureSuccessfulPairing: (stanza: BinaryNode, { advSecretKey, signedIdentityKey, signalIdentities }: Pick<AuthenticationCreds, 'advSecretKey' | 'signedIdentityKey' | 'signalIdentities'>) => {
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.encodeSignedDeviceIdentity = exports.configureSuccessfulPairing = exports.generateRegistrationNode = exports.generateLoginNode = void 0;
|
3
|
+
exports.encodeSignedDeviceIdentity = exports.configureSuccessfulPairing = exports.generateRegistrationNode = exports.generateLoginNode = exports.generateMobileNode = void 0;
|
4
4
|
const boom_1 = require("@hapi/boom");
|
5
5
|
const crypto_1 = require("crypto");
|
6
6
|
const WAProto_1 = require("../../WAProto");
|
@@ -10,19 +10,30 @@ const crypto_2 = require("./crypto");
|
|
10
10
|
const generics_1 = require("./generics");
|
11
11
|
const signal_1 = require("./signal");
|
12
12
|
const getUserAgent = (config) => {
|
13
|
+
var _a, _b;
|
14
|
+
const osVersion = config.mobile ? '15.3.1' : '0.1';
|
15
|
+
const version = config.mobile ? [2, 24, 6] : config.version;
|
16
|
+
const device = config.mobile ? 'iPhone_7' : 'Desktop';
|
17
|
+
const manufacturer = config.mobile ? 'Apple' : '';
|
18
|
+
const platform = config.mobile ? WAProto_1.proto.ClientPayload.UserAgent.Platform.IOS : WAProto_1.proto.ClientPayload.UserAgent.Platform.WEB;
|
19
|
+
const phoneId = config.mobile ? { phoneId: config.auth.creds.phoneId } : {};
|
13
20
|
return {
|
14
21
|
appVersion: {
|
15
|
-
primary:
|
16
|
-
secondary:
|
17
|
-
tertiary:
|
22
|
+
primary: version[0],
|
23
|
+
secondary: version[1],
|
24
|
+
tertiary: version[2],
|
18
25
|
},
|
19
|
-
platform
|
26
|
+
platform,
|
20
27
|
releaseChannel: WAProto_1.proto.ClientPayload.UserAgent.ReleaseChannel.RELEASE,
|
21
|
-
|
22
|
-
|
23
|
-
|
28
|
+
mcc: ((_a = config.auth.creds.registration) === null || _a === void 0 ? void 0 : _a.phoneNumberMobileCountryCode) || '000',
|
29
|
+
mnc: ((_b = config.auth.creds.registration) === null || _b === void 0 ? void 0 : _b.phoneNumberMobileNetworkCode) || '000',
|
30
|
+
osVersion: osVersion,
|
31
|
+
manufacturer,
|
32
|
+
device,
|
33
|
+
osBuildNumber: osVersion,
|
24
34
|
localeLanguageIso6391: 'en',
|
25
|
-
localeCountryIso31661Alpha2: config.countryCode
|
35
|
+
localeCountryIso31661Alpha2: config.countryCode,
|
36
|
+
...phoneId
|
26
37
|
};
|
27
38
|
};
|
28
39
|
const PLATFORM_MAP = {
|
@@ -42,9 +53,32 @@ const getClientPayload = (config) => {
|
|
42
53
|
connectReason: WAProto_1.proto.ClientPayload.ConnectReason.USER_ACTIVATED,
|
43
54
|
userAgent: getUserAgent(config),
|
44
55
|
};
|
45
|
-
|
56
|
+
if (!config.mobile) {
|
57
|
+
payload.webInfo = getWebInfo(config);
|
58
|
+
}
|
46
59
|
return payload;
|
47
60
|
};
|
61
|
+
const generateMobileNode = (config) => {
|
62
|
+
if (!config.auth.creds) {
|
63
|
+
throw new boom_1.Boom('No registration data found', { data: config });
|
64
|
+
}
|
65
|
+
const payload = {
|
66
|
+
...getClientPayload(config),
|
67
|
+
sessionId: Math.floor(Math.random() * 999999999 + 1),
|
68
|
+
shortConnect: true,
|
69
|
+
connectAttemptCount: 0,
|
70
|
+
device: 0,
|
71
|
+
dnsSource: {
|
72
|
+
appCached: false,
|
73
|
+
dnsMethod: WAProto_1.proto.ClientPayload.DNSSource.DNSResolutionMethod.SYSTEM,
|
74
|
+
},
|
75
|
+
passive: false,
|
76
|
+
pushName: 'test',
|
77
|
+
username: Number(`${config.auth.creds.registration.phoneNumberCountryCode}${config.auth.creds.registration.phoneNumberNationalNumber}`),
|
78
|
+
};
|
79
|
+
return WAProto_1.proto.ClientPayload.fromObject(payload);
|
80
|
+
};
|
81
|
+
exports.generateMobileNode = generateMobileNode;
|
48
82
|
const generateLoginNode = (userJid, config) => {
|
49
83
|
const { user, device } = (0, WABinary_1.jidDecode)(userJid);
|
50
84
|
const payload = {
|
@@ -30,11 +30,11 @@ exports.SINGLE_BYTE_TOKENS = [
|
|
30
30
|
'', 'xmlstreamstart', 'xmlstreamend', 's.whatsapp.net', 'type', 'participant', 'from', 'receipt', 'id', 'broadcast', 'status', 'message', 'notification', 'notify', 'to', 'jid', 'user', 'class', 'offline', 'g.us', 'result', 'mediatype', 'enc', 'skmsg', 'off_cnt', 'xmlns', 'presence', 'participants', 'ack', 't', 'iq', 'device_hash', 'read', 'value', 'media', 'picture', 'chatstate', 'unavailable', 'text', 'urn:xmpp:whatsapp:push', 'devices', 'verified_name', 'contact', 'composing', 'edge_routing', 'routing_info', 'item', 'image', 'verified_level', 'get', 'fallback_hostname', '2', 'media_conn', '1', 'v', 'handshake', 'fallback_class', 'count', 'config', 'offline_preview', 'download_buckets', 'w:profile:picture', 'set', 'creation', 'location', 'fallback_ip4', 'msg', 'urn:xmpp:ping', 'fallback_ip6', 'call-creator', 'relaylatency', 'success', 'subscribe', 'video', 'business_hours_config', 'platform', 'hostname', 'version', 'unknown', '0', 'ping', 'hash', 'edit', 'subject', 'max_buckets', 'download', 'delivery', 'props', 'sticker', 'name', 'last', 'contacts', 'business', 'primary', 'preview', 'w:p', 'pkmsg', 'call-id', 'retry', 'prop', 'call', 'auth_ttl', 'available', 'relay_id', 'last_id', 'day_of_week', 'w', 'host', 'seen', 'bits', 'list', 'atn', 'upload', 'is_new', 'w:stats', 'key', 'paused', 'specific_hours', 'multicast', 'stream:error', 'mmg.whatsapp.net', 'code', 'deny', 'played', 'profile', 'fna', 'device-list', 'close_time', 'latency', 'gcm', 'pop', 'audio', '26', 'w:web', 'open_time', 'error', 'auth', 'ip4', 'update', 'profile_options', 'config_value', 'category', 'catalog_not_created', '00', 'config_code', 'mode', 'catalog_status', 'ip6', 'blocklist', 'registration', '7', 'web', 'fail', 'w:m', 'cart_enabled', 'ttl', 'gif', '300', 'device_orientation', 'identity', 'query', '401', 'media-gig2-1.cdn.whatsapp.net', 'in', '3', 'te2', 'add', 'fallback', 'categories', 'ptt', 'encrypt', 'notice', 'thumbnail-document', 'item-not-found', '12', 'thumbnail-image', 'stage', 'thumbnail-link', 'usync', 'out', 'thumbnail-video', '8', '01', 'context', 'sidelist', 'thumbnail-gif', 'terminate', 'not-authorized', 'orientation', 'dhash', 'capability', 'side_list', 'md-app-state', 'description', 'serial', 'readreceipts', 'te', 'business_hours', 'md-msg-hist', 'tag', 'attribute_padding', 'document', 'open_24h', 'delete', 'expiration', 'active', 'prev_v_id', 'true', 'passive', 'index', '4', 'conflict', 'remove', 'w:gp2', 'config_expo_key', 'screen_height', 'replaced', '02', 'screen_width', 'uploadfieldstat', '2:47DEQpj8', 'media-bog1-1.cdn.whatsapp.net', 'encopt', 'url', 'catalog_exists', 'keygen', 'rate', 'offer', 'opus', 'media-mia3-1.cdn.whatsapp.net', 'privacy', 'media-mia3-2.cdn.whatsapp.net', 'signature', 'preaccept', 'token_id', 'media-eze1-1.cdn.whatsapp.net'
|
31
31
|
];
|
32
32
|
exports.TOKEN_MAP = {};
|
33
|
-
for (
|
34
|
-
exports.TOKEN_MAP[
|
33
|
+
for (let i = 0; i < exports.SINGLE_BYTE_TOKENS.length; i++) {
|
34
|
+
exports.TOKEN_MAP[exports.SINGLE_BYTE_TOKENS[i]] = { index: i };
|
35
35
|
}
|
36
|
-
for (
|
37
|
-
for (
|
38
|
-
exports.TOKEN_MAP[
|
36
|
+
for (let i = 0; i < exports.DOUBLE_BYTE_TOKENS.length; i++) {
|
37
|
+
for (let j = 0; j < exports.DOUBLE_BYTE_TOKENS[i].length; j++) {
|
38
|
+
exports.TOKEN_MAP[exports.DOUBLE_BYTE_TOKENS[i][j]] = { dict: i, index: j };
|
39
39
|
}
|
40
40
|
}
|