@ryuu-reinzz/baileys 3.0.0-beta.2 → 3.0.0-beta.21
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/LICENSE +1 -1
- package/README.md +6 -0
- package/WAProto/fix-imports.js +70 -18
- package/WAProto/index.js +197 -160
- package/lib/Defaults/index.js +17 -4
- package/lib/Signal/libsignal.js +63 -2
- package/lib/Signal/lid-mapping.js +170 -70
- package/lib/Socket/Client/websocket.js +5 -1
- package/lib/Socket/business.js +11 -8
- package/lib/Socket/chats.js +55 -28
- package/lib/Socket/index.js +0 -6
- package/lib/Socket/messages-recv.js +152 -75
- package/lib/Socket/messages-send.js +230 -148
- package/lib/Socket/socket.js +69 -15
- package/lib/Utils/auth-utils.js +53 -20
- package/lib/Utils/chat-utils.js +100 -51
- package/lib/Utils/crypto.js +2 -26
- package/lib/Utils/event-buffer.js +33 -7
- package/lib/Utils/generics.js +4 -1
- package/lib/Utils/history.js +46 -5
- package/lib/Utils/identity-change-handler.js +49 -0
- package/lib/Utils/index.js +2 -0
- package/lib/Utils/lt-hash.js +2 -42
- package/lib/Utils/make-mutex.js +20 -27
- package/lib/Utils/message-retry-manager.js +58 -5
- package/lib/Utils/messages-media.js +151 -40
- package/lib/Utils/messages.js +43 -23
- package/lib/Utils/noise-handler.js +139 -85
- package/lib/Utils/process-message.js +57 -14
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/sync-action-utils.js +48 -0
- package/lib/Utils/tc-token-utils.js +18 -0
- package/lib/Utils/use-sqlite-auth-state.js +122 -0
- package/lib/WABinary/decode.js +24 -0
- package/lib/WABinary/encode.js +5 -1
- package/lib/WABinary/generic-utils.js +19 -8
- package/package.json +7 -2
|
@@ -75,7 +75,7 @@ export async function getMediaKeys(buffer, mediaType) {
|
|
|
75
75
|
buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64');
|
|
76
76
|
}
|
|
77
77
|
// expand using HKDF to 112 bytes, also pass in the relevant app info
|
|
78
|
-
const expandedMediaKey =
|
|
78
|
+
const expandedMediaKey = hkdf(buffer, 112, { info: hkdfInfoKey(mediaType) });
|
|
79
79
|
return {
|
|
80
80
|
iv: expandedMediaKey.slice(0, 16),
|
|
81
81
|
cipherKey: expandedMediaKey.slice(16, 48),
|
|
@@ -217,7 +217,7 @@ export async function getAudioWaveform(buffer, logger) {
|
|
|
217
217
|
const blockStart = blockSize * i; // the location of the first sample in the block
|
|
218
218
|
let sum = 0;
|
|
219
219
|
for (let j = 0; j < blockSize; j++) {
|
|
220
|
-
sum = sum + Math.abs(rawData[blockStart + j]); // find the sum of all the samples in the block
|
|
220
|
+
sum = sum + Math.abs(rawData[blockStart + j] ?? 0); // find the sum of all the samples in the block
|
|
221
221
|
}
|
|
222
222
|
filteredData.push(sum / blockSize); // divide the sum by the block size to get the average
|
|
223
223
|
}
|
|
@@ -324,10 +324,13 @@ export const encryptedStream = async (media, mediaType, { logger, saveOriginalFi
|
|
|
324
324
|
const hmac = Crypto.createHmac('sha256', macKey).update(iv);
|
|
325
325
|
const sha256Plain = Crypto.createHash('sha256');
|
|
326
326
|
const sha256Enc = Crypto.createHash('sha256');
|
|
327
|
-
const onChunk = (buff) => {
|
|
327
|
+
const onChunk = async (buff) => {
|
|
328
328
|
sha256Enc.update(buff);
|
|
329
329
|
hmac.update(buff);
|
|
330
|
-
|
|
330
|
+
// Handle backpressure: if write returns false, wait for drain
|
|
331
|
+
if (!encFileWriteStream.write(buff)) {
|
|
332
|
+
await once(encFileWriteStream, 'drain');
|
|
333
|
+
}
|
|
331
334
|
};
|
|
332
335
|
try {
|
|
333
336
|
for await (const data of stream) {
|
|
@@ -345,17 +348,23 @@ export const encryptedStream = async (media, mediaType, { logger, saveOriginalFi
|
|
|
345
348
|
}
|
|
346
349
|
}
|
|
347
350
|
sha256Plain.update(data);
|
|
348
|
-
onChunk(aes.update(data));
|
|
351
|
+
await onChunk(aes.update(data));
|
|
349
352
|
}
|
|
350
|
-
onChunk(aes.final());
|
|
353
|
+
await onChunk(aes.final());
|
|
351
354
|
const mac = hmac.digest().slice(0, 10);
|
|
352
355
|
sha256Enc.update(mac);
|
|
353
356
|
const fileSha256 = sha256Plain.digest();
|
|
354
357
|
const fileEncSha256 = sha256Enc.digest();
|
|
355
358
|
encFileWriteStream.write(mac);
|
|
359
|
+
const encFinishPromise = once(encFileWriteStream, 'finish');
|
|
360
|
+
const originalFinishPromise = originalFileStream ? once(originalFileStream, 'finish') : Promise.resolve();
|
|
356
361
|
encFileWriteStream.end();
|
|
357
362
|
originalFileStream?.end?.();
|
|
358
363
|
stream.destroy();
|
|
364
|
+
// Wait for write streams to fully flush to disk
|
|
365
|
+
// This helps reduce memory pressure by allowing OS to release buffers
|
|
366
|
+
await encFinishPromise;
|
|
367
|
+
await originalFinishPromise;
|
|
359
368
|
logger?.debug('encrypted data successfully');
|
|
360
369
|
return {
|
|
361
370
|
mediaKey,
|
|
@@ -506,6 +515,117 @@ export function extensionForMediaMessage(message) {
|
|
|
506
515
|
}
|
|
507
516
|
return extension;
|
|
508
517
|
}
|
|
518
|
+
const isNodeRuntime = () => {
|
|
519
|
+
return (typeof process !== 'undefined' &&
|
|
520
|
+
process.versions?.node !== null &&
|
|
521
|
+
typeof process.versions.bun === 'undefined' &&
|
|
522
|
+
typeof globalThis.Deno === 'undefined');
|
|
523
|
+
};
|
|
524
|
+
export const uploadWithNodeHttp = async ({ url, filePath, headers, timeoutMs, agent }, redirectCount = 0) => {
|
|
525
|
+
if (redirectCount > 5) {
|
|
526
|
+
throw new Error('Too many redirects');
|
|
527
|
+
}
|
|
528
|
+
const parsedUrl = new URL(url);
|
|
529
|
+
const httpModule = parsedUrl.protocol === 'https:' ? await import('https') : await import('http');
|
|
530
|
+
// Get file size for Content-Length header (required for Node.js streaming)
|
|
531
|
+
const fileStats = await fs.stat(filePath);
|
|
532
|
+
const fileSize = fileStats.size;
|
|
533
|
+
return new Promise((resolve, reject) => {
|
|
534
|
+
const req = httpModule.request({
|
|
535
|
+
hostname: parsedUrl.hostname,
|
|
536
|
+
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
|
|
537
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
538
|
+
method: 'POST',
|
|
539
|
+
headers: {
|
|
540
|
+
...headers,
|
|
541
|
+
'Content-Length': fileSize
|
|
542
|
+
},
|
|
543
|
+
agent,
|
|
544
|
+
timeout: timeoutMs
|
|
545
|
+
}, res => {
|
|
546
|
+
// Handle redirects (3xx)
|
|
547
|
+
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
548
|
+
res.resume(); // Consume response to free resources
|
|
549
|
+
const newUrl = new URL(res.headers.location, url).toString();
|
|
550
|
+
resolve(uploadWithNodeHttp({
|
|
551
|
+
url: newUrl,
|
|
552
|
+
filePath,
|
|
553
|
+
headers,
|
|
554
|
+
timeoutMs,
|
|
555
|
+
agent
|
|
556
|
+
}, redirectCount + 1));
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
let body = '';
|
|
560
|
+
res.on('data', chunk => (body += chunk));
|
|
561
|
+
res.on('end', () => {
|
|
562
|
+
try {
|
|
563
|
+
resolve(JSON.parse(body));
|
|
564
|
+
}
|
|
565
|
+
catch {
|
|
566
|
+
resolve(undefined);
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
});
|
|
570
|
+
req.on('error', reject);
|
|
571
|
+
req.on('timeout', () => {
|
|
572
|
+
req.destroy();
|
|
573
|
+
reject(new Error('Upload timeout'));
|
|
574
|
+
});
|
|
575
|
+
const stream = createReadStream(filePath);
|
|
576
|
+
stream.pipe(req);
|
|
577
|
+
stream.on('error', err => {
|
|
578
|
+
req.destroy();
|
|
579
|
+
reject(err);
|
|
580
|
+
});
|
|
581
|
+
});
|
|
582
|
+
};
|
|
583
|
+
const uploadWithFetch = async ({ url, filePath, headers, timeoutMs, agent }) => {
|
|
584
|
+
// Convert Node.js Readable to Web ReadableStream
|
|
585
|
+
const nodeStream = createReadStream(filePath);
|
|
586
|
+
const webStream = Readable.toWeb(nodeStream);
|
|
587
|
+
const response = await fetch(url, {
|
|
588
|
+
dispatcher: agent,
|
|
589
|
+
method: 'POST',
|
|
590
|
+
body: webStream,
|
|
591
|
+
headers,
|
|
592
|
+
duplex: 'half',
|
|
593
|
+
signal: timeoutMs ? AbortSignal.timeout(timeoutMs) : undefined
|
|
594
|
+
});
|
|
595
|
+
try {
|
|
596
|
+
return (await response.json());
|
|
597
|
+
}
|
|
598
|
+
catch {
|
|
599
|
+
return undefined;
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
/**
|
|
603
|
+
* Uploads media to WhatsApp servers.
|
|
604
|
+
*
|
|
605
|
+
* ## Why we have two upload implementations:
|
|
606
|
+
*
|
|
607
|
+
* Node.js's native `fetch` (powered by undici) has a known bug where it buffers
|
|
608
|
+
* the entire request body in memory before sending, even when using streams.
|
|
609
|
+
* This causes memory issues with large files (e.g., 1GB file = 1GB+ memory usage).
|
|
610
|
+
* See: https://github.com/nodejs/undici/issues/4058
|
|
611
|
+
*
|
|
612
|
+
* Other runtimes (Bun, Deno, browsers) correctly stream the request body without
|
|
613
|
+
* buffering, so we can use the web-standard Fetch API there.
|
|
614
|
+
*
|
|
615
|
+
* ## Future considerations:
|
|
616
|
+
* Once the undici bug is fixed, we can simplify this to use only the Fetch API
|
|
617
|
+
* across all runtimes. Monitor the GitHub issue for updates.
|
|
618
|
+
*/
|
|
619
|
+
const uploadMedia = async (params, logger) => {
|
|
620
|
+
if (isNodeRuntime()) {
|
|
621
|
+
logger?.debug('Using Node.js https module for upload (avoids undici buffering bug)');
|
|
622
|
+
return uploadWithNodeHttp(params);
|
|
623
|
+
}
|
|
624
|
+
else {
|
|
625
|
+
logger?.debug('Using web-standard Fetch API for upload');
|
|
626
|
+
return uploadWithFetch(params);
|
|
627
|
+
}
|
|
628
|
+
};
|
|
509
629
|
export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
510
630
|
return async (filePath, { mediaType, fileEncSha256B64, timeoutMs }) => {
|
|
511
631
|
// send a query JSON to obtain the url & auth token to upload our media
|
|
@@ -513,41 +633,32 @@ export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, opt
|
|
|
513
633
|
let urls;
|
|
514
634
|
const hosts = [...customUploadHosts, ...uploadInfo.hosts];
|
|
515
635
|
fileEncSha256B64 = encodeBase64EncodedStringForUpload(fileEncSha256B64);
|
|
636
|
+
// Prepare common headers
|
|
637
|
+
const customHeaders = (() => {
|
|
638
|
+
const hdrs = options?.headers;
|
|
639
|
+
if (!hdrs)
|
|
640
|
+
return {};
|
|
641
|
+
return Array.isArray(hdrs) ? Object.fromEntries(hdrs) : hdrs;
|
|
642
|
+
})();
|
|
643
|
+
const headers = {
|
|
644
|
+
...customHeaders,
|
|
645
|
+
'Content-Type': 'application/octet-stream',
|
|
646
|
+
Origin: DEFAULT_ORIGIN
|
|
647
|
+
};
|
|
516
648
|
for (const { hostname } of hosts) {
|
|
517
649
|
logger.debug(`uploading to "${hostname}"`);
|
|
518
|
-
const auth = encodeURIComponent(uploadInfo.auth);
|
|
650
|
+
const auth = encodeURIComponent(uploadInfo.auth);
|
|
519
651
|
const url = `https://${hostname}${MEDIA_PATH_MAP[mediaType]}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
|
|
520
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
521
652
|
let result;
|
|
522
653
|
try {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
if (!hdrs)
|
|
532
|
-
return {};
|
|
533
|
-
return Array.isArray(hdrs) ? Object.fromEntries(hdrs) : hdrs;
|
|
534
|
-
})(),
|
|
535
|
-
'Content-Type': 'application/octet-stream',
|
|
536
|
-
Origin: DEFAULT_ORIGIN
|
|
537
|
-
},
|
|
538
|
-
duplex: 'half',
|
|
539
|
-
// Note: custom agents/proxy require undici Agent; omitted here.
|
|
540
|
-
signal: timeoutMs ? AbortSignal.timeout(timeoutMs) : undefined
|
|
541
|
-
});
|
|
542
|
-
let parsed = undefined;
|
|
543
|
-
try {
|
|
544
|
-
parsed = await response.json();
|
|
545
|
-
}
|
|
546
|
-
catch {
|
|
547
|
-
parsed = undefined;
|
|
548
|
-
}
|
|
549
|
-
result = parsed;
|
|
550
|
-
if (result?.url || result?.directPath) {
|
|
654
|
+
result = await uploadMedia({
|
|
655
|
+
url,
|
|
656
|
+
filePath,
|
|
657
|
+
headers,
|
|
658
|
+
timeoutMs,
|
|
659
|
+
agent: fetchAgent
|
|
660
|
+
}, logger);
|
|
661
|
+
if (result?.url || result?.direct_path) {
|
|
551
662
|
urls = {
|
|
552
663
|
mediaUrl: result.url,
|
|
553
664
|
directPath: result.direct_path,
|
|
@@ -579,11 +690,11 @@ const getMediaRetryKey = (mediaKey) => {
|
|
|
579
690
|
/**
|
|
580
691
|
* Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
|
|
581
692
|
*/
|
|
582
|
-
export const encryptMediaRetryRequest =
|
|
693
|
+
export const encryptMediaRetryRequest = (key, mediaKey, meId) => {
|
|
583
694
|
const recp = { stanzaId: key.id };
|
|
584
695
|
const recpBuffer = proto.ServerErrorReceipt.encode(recp).finish();
|
|
585
696
|
const iv = Crypto.randomBytes(12);
|
|
586
|
-
const retryKey =
|
|
697
|
+
const retryKey = getMediaRetryKey(mediaKey);
|
|
587
698
|
const ciphertext = aesEncryptGCM(recpBuffer, retryKey, iv, Buffer.from(key.id));
|
|
588
699
|
const req = {
|
|
589
700
|
tag: 'receipt',
|
|
@@ -648,8 +759,8 @@ export const decodeMediaRetryNode = (node) => {
|
|
|
648
759
|
}
|
|
649
760
|
return event;
|
|
650
761
|
};
|
|
651
|
-
export const decryptMediaRetryData =
|
|
652
|
-
const retryKey =
|
|
762
|
+
export const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
|
|
763
|
+
const retryKey = getMediaRetryKey(mediaKey);
|
|
653
764
|
const plaintext = aesDecryptGCM(ciphertext, retryKey, iv, Buffer.from(msgId));
|
|
654
765
|
return proto.MediaRetryNotification.decode(plaintext);
|
|
655
766
|
};
|
package/lib/Utils/messages.js
CHANGED
|
@@ -9,6 +9,7 @@ import { isJidGroup, isJidNewsletter, isJidStatusBroadcast, jidNormalizedUser }
|
|
|
9
9
|
import { sha256 } from './crypto.js';
|
|
10
10
|
import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './generics.js';
|
|
11
11
|
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getRawMediaUploadData } from './messages-media.js';
|
|
12
|
+
import { shouldIncludeReportingToken } from './reporting-utils.js';
|
|
12
13
|
const MIMETYPE_MAP = {
|
|
13
14
|
image: 'image/jpeg',
|
|
14
15
|
video: 'video/mp4',
|
|
@@ -259,10 +260,20 @@ export const generateForwardMessageContent = (message, forceForward) => {
|
|
|
259
260
|
}
|
|
260
261
|
return content;
|
|
261
262
|
};
|
|
263
|
+
export const hasNonNullishProperty = (message, key) => {
|
|
264
|
+
return (typeof message === 'object' &&
|
|
265
|
+
message !== null &&
|
|
266
|
+
key in message &&
|
|
267
|
+
message[key] !== null &&
|
|
268
|
+
message[key] !== undefined);
|
|
269
|
+
};
|
|
270
|
+
function hasOptionalProperty(obj, key) {
|
|
271
|
+
return typeof obj === 'object' && obj !== null && key in obj && obj[key] !== null;
|
|
272
|
+
}
|
|
262
273
|
export const generateWAMessageContent = async (message, options) => {
|
|
263
274
|
var _a, _b;
|
|
264
275
|
let m = {};
|
|
265
|
-
if ('text'
|
|
276
|
+
if (hasNonNullishProperty(message, 'text')) {
|
|
266
277
|
const extContent = { text: message.text };
|
|
267
278
|
let urlInfo = message.linkPreview;
|
|
268
279
|
if (typeof urlInfo === 'undefined') {
|
|
@@ -293,7 +304,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
293
304
|
}
|
|
294
305
|
m.extendedTextMessage = extContent;
|
|
295
306
|
}
|
|
296
|
-
else if ('contacts'
|
|
307
|
+
else if (hasNonNullishProperty(message, 'contacts')) {
|
|
297
308
|
const contactLen = message.contacts.contacts.length;
|
|
298
309
|
if (!contactLen) {
|
|
299
310
|
throw new Boom('require atleast 1 contact', { statusCode: 400 });
|
|
@@ -305,25 +316,25 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
305
316
|
m.contactsArrayMessage = WAProto.Message.ContactsArrayMessage.create(message.contacts);
|
|
306
317
|
}
|
|
307
318
|
}
|
|
308
|
-
else if ('location'
|
|
319
|
+
else if (hasNonNullishProperty(message, 'location')) {
|
|
309
320
|
m.locationMessage = WAProto.Message.LocationMessage.create(message.location);
|
|
310
321
|
}
|
|
311
|
-
else if ('react'
|
|
322
|
+
else if (hasNonNullishProperty(message, 'react')) {
|
|
312
323
|
if (!message.react.senderTimestampMs) {
|
|
313
324
|
message.react.senderTimestampMs = Date.now();
|
|
314
325
|
}
|
|
315
326
|
m.reactionMessage = WAProto.Message.ReactionMessage.create(message.react);
|
|
316
327
|
}
|
|
317
|
-
else if ('delete'
|
|
328
|
+
else if (hasNonNullishProperty(message, 'delete')) {
|
|
318
329
|
m.protocolMessage = {
|
|
319
330
|
key: message.delete,
|
|
320
331
|
type: WAProto.Message.ProtocolMessage.Type.REVOKE
|
|
321
332
|
};
|
|
322
333
|
}
|
|
323
|
-
else if ('forward'
|
|
334
|
+
else if (hasNonNullishProperty(message, 'forward')) {
|
|
324
335
|
m = generateForwardMessageContent(message.forward, message.force);
|
|
325
336
|
}
|
|
326
|
-
else if ('disappearingMessagesInChat'
|
|
337
|
+
else if (hasNonNullishProperty(message, 'disappearingMessagesInChat')) {
|
|
327
338
|
const exp = typeof message.disappearingMessagesInChat === 'boolean'
|
|
328
339
|
? message.disappearingMessagesInChat
|
|
329
340
|
? WA_DEFAULT_EPHEMERAL
|
|
@@ -331,7 +342,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
331
342
|
: message.disappearingMessagesInChat;
|
|
332
343
|
m = prepareDisappearingMessageSettingContent(exp);
|
|
333
344
|
}
|
|
334
|
-
else if ('groupInvite'
|
|
345
|
+
else if (hasNonNullishProperty(message, 'groupInvite')) {
|
|
335
346
|
m.groupInviteMessage = {};
|
|
336
347
|
m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
|
|
337
348
|
m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
|
|
@@ -351,7 +362,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
351
362
|
}
|
|
352
363
|
}
|
|
353
364
|
}
|
|
354
|
-
else if ('pin'
|
|
365
|
+
else if (hasNonNullishProperty(message, 'pin')) {
|
|
355
366
|
m.pinInChatMessage = {};
|
|
356
367
|
m.messageContextInfo = {};
|
|
357
368
|
m.pinInChatMessage.key = message.pin;
|
|
@@ -359,7 +370,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
359
370
|
m.pinInChatMessage.senderTimestampMs = Date.now();
|
|
360
371
|
m.messageContextInfo.messageAddOnDurationInSecs = message.type === 1 ? message.time || 86400 : 0;
|
|
361
372
|
}
|
|
362
|
-
else if ('buttonReply'
|
|
373
|
+
else if (hasNonNullishProperty(message, 'buttonReply')) {
|
|
363
374
|
switch (message.type) {
|
|
364
375
|
case 'template':
|
|
365
376
|
m.templateButtonReplyMessage = {
|
|
@@ -377,11 +388,11 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
377
388
|
break;
|
|
378
389
|
}
|
|
379
390
|
}
|
|
380
|
-
else if ('ptv'
|
|
391
|
+
else if (hasOptionalProperty(message, 'ptv') && message.ptv) {
|
|
381
392
|
const { videoMessage } = await prepareWAMessageMedia({ video: message.video }, options);
|
|
382
393
|
m.ptvMessage = videoMessage;
|
|
383
394
|
}
|
|
384
|
-
else if ('product'
|
|
395
|
+
else if (hasNonNullishProperty(message, 'product')) {
|
|
385
396
|
const { imageMessage } = await prepareWAMessageMedia({ image: message.product.productImage }, options);
|
|
386
397
|
m.productMessage = WAProto.Message.ProductMessage.create({
|
|
387
398
|
...message,
|
|
@@ -391,10 +402,10 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
391
402
|
}
|
|
392
403
|
});
|
|
393
404
|
}
|
|
394
|
-
else if ('listReply'
|
|
405
|
+
else if (hasNonNullishProperty(message, 'listReply')) {
|
|
395
406
|
m.listResponseMessage = { ...message.listReply };
|
|
396
407
|
}
|
|
397
|
-
else if ('event'
|
|
408
|
+
else if (hasNonNullishProperty(message, 'event')) {
|
|
398
409
|
m.eventMessage = {};
|
|
399
410
|
const startTime = Math.floor(message.event.startDate.getTime() / 1000);
|
|
400
411
|
if (message.event.call && options.getCallLink) {
|
|
@@ -414,7 +425,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
414
425
|
m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false;
|
|
415
426
|
m.eventMessage.location = message.event.location;
|
|
416
427
|
}
|
|
417
|
-
else if ('poll'
|
|
428
|
+
else if (hasNonNullishProperty(message, 'poll')) {
|
|
418
429
|
(_a = message.poll).selectableCount || (_a.selectableCount = 0);
|
|
419
430
|
(_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
|
|
420
431
|
if (!Array.isArray(message.poll.values)) {
|
|
@@ -449,15 +460,15 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
449
460
|
}
|
|
450
461
|
}
|
|
451
462
|
}
|
|
452
|
-
else if ('sharePhoneNumber'
|
|
463
|
+
else if (hasNonNullishProperty(message, 'sharePhoneNumber')) {
|
|
453
464
|
m.protocolMessage = {
|
|
454
465
|
type: proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
|
|
455
466
|
};
|
|
456
467
|
}
|
|
457
|
-
else if ('requestPhoneNumber'
|
|
468
|
+
else if (hasNonNullishProperty(message, 'requestPhoneNumber')) {
|
|
458
469
|
m.requestPhoneNumberMessage = {};
|
|
459
470
|
}
|
|
460
|
-
else if ('limitSharing'
|
|
471
|
+
else if (hasNonNullishProperty(message, 'limitSharing')) {
|
|
461
472
|
m.protocolMessage = {
|
|
462
473
|
type: proto.Message.ProtocolMessage.Type.LIMIT_SHARING,
|
|
463
474
|
limitSharing: {
|
|
@@ -471,10 +482,10 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
471
482
|
else {
|
|
472
483
|
m = await prepareWAMessageMedia(message, options);
|
|
473
484
|
}
|
|
474
|
-
if ('viewOnce'
|
|
485
|
+
if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) {
|
|
475
486
|
m = { viewOnceMessage: { message: m } };
|
|
476
487
|
}
|
|
477
|
-
if ('mentions'
|
|
488
|
+
if (hasOptionalProperty(message, 'mentions') && message.mentions?.length) {
|
|
478
489
|
const messageType = Object.keys(m)[0];
|
|
479
490
|
const key = m[messageType];
|
|
480
491
|
if ('contextInfo' in key && !!key.contextInfo) {
|
|
@@ -486,7 +497,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
486
497
|
};
|
|
487
498
|
}
|
|
488
499
|
}
|
|
489
|
-
if ('edit'
|
|
500
|
+
if (hasOptionalProperty(message, 'edit')) {
|
|
490
501
|
m = {
|
|
491
502
|
protocolMessage: {
|
|
492
503
|
key: message.edit,
|
|
@@ -496,7 +507,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
496
507
|
}
|
|
497
508
|
};
|
|
498
509
|
}
|
|
499
|
-
if ('contextInfo'
|
|
510
|
+
if (hasOptionalProperty(message, 'contextInfo') && !!message.contextInfo) {
|
|
500
511
|
const messageType = Object.keys(m)[0];
|
|
501
512
|
const key = m[messageType];
|
|
502
513
|
if ('contextInfo' in key && !!key.contextInfo) {
|
|
@@ -506,6 +517,12 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
506
517
|
key.contextInfo = message.contextInfo;
|
|
507
518
|
}
|
|
508
519
|
}
|
|
520
|
+
if (shouldIncludeReportingToken(m)) {
|
|
521
|
+
m.messageContextInfo = m.messageContextInfo || {};
|
|
522
|
+
if (!m.messageContextInfo.messageSecret) {
|
|
523
|
+
m.messageContextInfo.messageSecret = randomBytes(32);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
509
526
|
return WAProto.Message.create(m);
|
|
510
527
|
};
|
|
511
528
|
export const generateWAMessageFromContent = (jid, message, options) => {
|
|
@@ -614,7 +631,10 @@ export const normalizeMessageContent = (content) => {
|
|
|
614
631
|
message?.documentWithCaptionMessage ||
|
|
615
632
|
message?.viewOnceMessageV2 ||
|
|
616
633
|
message?.viewOnceMessageV2Extension ||
|
|
617
|
-
message?.editedMessage
|
|
634
|
+
message?.editedMessage ||
|
|
635
|
+
message?.associatedChildMessage ||
|
|
636
|
+
message?.groupStatusMessage ||
|
|
637
|
+
message?.groupStatusMessageV2);
|
|
618
638
|
}
|
|
619
639
|
};
|
|
620
640
|
/**
|