Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jajbshjahavahh
GitHub Repository: jajbshjahavahh/Gojo-Satoru
Path: blob/master/node_modules/@adiwajshing/baileys/lib/Utils/messages.js
2593 views
1
"use strict";
2
Object.defineProperty(exports, "__esModule", { value: true });
3
exports.updateMessageWithReceipt = exports.getDevice = exports.extractMessageContent = exports.getContentType = exports.generateWAMessage = exports.generateWAMessageFromContent = exports.generateWAMessageContent = exports.generateForwardMessageContent = exports.prepareDisappearingMessageSettingContent = exports.prepareWAMessageMedia = void 0;
4
const boom_1 = require("@hapi/boom");
5
const fs_1 = require("fs");
6
const WAProto_1 = require("../../WAProto");
7
const Defaults_1 = require("../Defaults");
8
const Types_1 = require("../Types");
9
const generics_1 = require("./generics");
10
const messages_media_1 = require("./messages-media");
11
const MIMETYPE_MAP = {
12
image: 'image/jpeg',
13
video: 'video/mp4',
14
document: 'application/pdf',
15
audio: 'audio/ogg; codecs=opus',
16
sticker: 'image/webp',
17
history: 'application/x-protobuf',
18
'md-app-state': 'application/x-protobuf',
19
};
20
const MessageTypeProto = {
21
'image': Types_1.WAProto.ImageMessage,
22
'video': Types_1.WAProto.VideoMessage,
23
'audio': Types_1.WAProto.AudioMessage,
24
'sticker': Types_1.WAProto.StickerMessage,
25
'document': Types_1.WAProto.DocumentMessage,
26
};
27
const ButtonType = WAProto_1.proto.ButtonsMessage.ButtonsMessageHeaderType;
28
const prepareWAMessageMedia = async (message, options) => {
29
const logger = options.logger;
30
let mediaType;
31
for (const key of Defaults_1.MEDIA_KEYS) {
32
if (key in message) {
33
mediaType = key;
34
}
35
}
36
const uploadData = {
37
...message,
38
media: message[mediaType]
39
};
40
delete uploadData[mediaType];
41
// check if cacheable + generate cache key
42
const cacheableKey = typeof uploadData.media === 'object' &&
43
('url' in uploadData.media) &&
44
!!uploadData.media.url &&
45
!!options.mediaCache && (
46
// generate the key
47
mediaType + ':' + uploadData.media.url.toString());
48
if (mediaType === 'document' && !uploadData.fileName) {
49
uploadData.fileName = 'file';
50
}
51
if (!uploadData.mimetype) {
52
uploadData.mimetype = MIMETYPE_MAP[mediaType];
53
}
54
// check for cache hit
55
if (cacheableKey) {
56
const mediaBuff = options.mediaCache.get(cacheableKey);
57
if (mediaBuff) {
58
logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'got media cache hit');
59
const obj = Types_1.WAProto.Message.decode(mediaBuff);
60
const key = `${mediaType}Message`;
61
delete uploadData.media;
62
Object.assign(obj[key], { ...uploadData });
63
return obj;
64
}
65
}
66
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
67
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
68
(typeof uploadData['jpegThumbnail'] === 'undefined');
69
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
70
const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath } = await messages_media_1.encryptedStream(uploadData.media, mediaType, requiresOriginalForSomeProcessing);
71
// url safe Base64 encode the SHA256 hash of the body
72
const fileEncSha256B64 = encodeURIComponent(fileEncSha256.toString('base64')
73
.replace(/\+/g, '-')
74
.replace(/\//g, '_')
75
.replace(/\=+$/, ''));
76
const [{ mediaUrl, directPath }] = await Promise.all([
77
(async () => {
78
const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
79
logger === null || logger === void 0 ? void 0 : logger.debug('uploaded media');
80
return result;
81
})(),
82
(async () => {
83
try {
84
if (requiresThumbnailComputation) {
85
uploadData.jpegThumbnail = await messages_media_1.generateThumbnail(bodyPath, mediaType, options);
86
logger === null || logger === void 0 ? void 0 : logger.debug('generated thumbnail');
87
}
88
if (requiresDurationComputation) {
89
uploadData.seconds = await messages_media_1.getAudioDuration(bodyPath);
90
logger === null || logger === void 0 ? void 0 : logger.debug('computed audio duration');
91
}
92
}
93
catch (error) {
94
logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'failed to obtain extra info');
95
}
96
})(),
97
])
98
.finally(async () => {
99
encWriteStream.destroy();
100
// remove tmp files
101
if (didSaveToTmpPath && bodyPath) {
102
await fs_1.promises.unlink(bodyPath);
103
logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp files');
104
}
105
});
106
delete uploadData.media;
107
const obj = Types_1.WAProto.Message.fromObject({
108
[`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
109
url: mediaUrl,
110
directPath,
111
mediaKey,
112
fileEncSha256,
113
fileSha256,
114
fileLength,
115
mediaKeyTimestamp: generics_1.unixTimestampSeconds(),
116
...uploadData
117
})
118
});
119
if (cacheableKey) {
120
logger.debug({ cacheableKey }, 'set cache');
121
options.mediaCache.set(cacheableKey, Types_1.WAProto.Message.encode(obj).finish());
122
}
123
return obj;
124
};
125
exports.prepareWAMessageMedia = prepareWAMessageMedia;
126
const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
127
ephemeralExpiration = ephemeralExpiration || 0;
128
const content = {
129
ephemeralMessage: {
130
message: {
131
protocolMessage: {
132
type: Types_1.WAProto.ProtocolMessage.ProtocolMessageType.EPHEMERAL_SETTING,
133
ephemeralExpiration
134
}
135
}
136
}
137
};
138
return Types_1.WAProto.Message.fromObject(content);
139
};
140
exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent;
141
/**
142
* Generate forwarded message content like WA does
143
* @param message the message to forward
144
* @param options.forceForward will show the message as forwarded even if it is from you
145
*/
146
const generateForwardMessageContent = (message, forceForward) => {
147
var _a;
148
let content = message.message;
149
if (!content) {
150
throw new boom_1.Boom('no content in message', { statusCode: 400 });
151
}
152
// hacky copy
153
content = WAProto_1.proto.Message.decode(WAProto_1.proto.Message.encode(message.message).finish());
154
let key = Object.keys(content)[0];
155
let score = ((_a = content[key].contextInfo) === null || _a === void 0 ? void 0 : _a.forwardingScore) || 0;
156
score += message.key.fromMe && !forceForward ? 0 : 1;
157
if (key === 'conversation') {
158
content.extendedTextMessage = { text: content[key] };
159
delete content.conversation;
160
key = 'extendedTextMessage';
161
}
162
if (score > 0) {
163
content[key].contextInfo = { forwardingScore: score, isForwarded: true };
164
}
165
else {
166
content[key].contextInfo = {};
167
}
168
return content;
169
};
170
exports.generateForwardMessageContent = generateForwardMessageContent;
171
const generateWAMessageContent = async (message, options) => {
172
var _a, _b;
173
let m = {};
174
if ('text' in message) {
175
const extContent = { ...message };
176
if (!!options.getUrlInfo && message.text.match(Defaults_1.URL_REGEX)) {
177
try {
178
const data = await options.getUrlInfo(message.text);
179
extContent.canonicalUrl = data['canonical-url'];
180
extContent.matchedText = data['matched-text'];
181
extContent.jpegThumbnail = data.jpegThumbnail;
182
extContent.description = data.description;
183
extContent.title = data.title;
184
extContent.previewType = 0;
185
}
186
catch (error) { // ignore if fails
187
(_a = options.logger) === null || _a === void 0 ? void 0 : _a.warn({ trace: error.stack }, 'url generation failed');
188
}
189
}
190
m.extendedTextMessage = extContent;
191
}
192
else if ('contacts' in message) {
193
const contactLen = message.contacts.contacts.length;
194
if (!contactLen) {
195
throw new boom_1.Boom('require atleast 1 contact', { statusCode: 400 });
196
}
197
if (contactLen === 1) {
198
m.contactMessage = Types_1.WAProto.ContactMessage.fromObject(message.contacts.contacts[0]);
199
}
200
else {
201
m.contactsArrayMessage = Types_1.WAProto.ContactsArrayMessage.fromObject(message.contacts);
202
}
203
}
204
else if ('location' in message) {
205
m.locationMessage = Types_1.WAProto.LocationMessage.fromObject(message.location);
206
}
207
else if ('delete' in message) {
208
m.protocolMessage = {
209
key: message.delete,
210
type: Types_1.WAProto.ProtocolMessage.ProtocolMessageType.REVOKE
211
};
212
}
213
else if ('forward' in message) {
214
m = exports.generateForwardMessageContent(message.forward, message.force);
215
}
216
else if ('disappearingMessagesInChat' in message) {
217
const exp = typeof message.disappearingMessagesInChat === 'boolean' ?
218
(message.disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
219
message.disappearingMessagesInChat;
220
m = exports.prepareDisappearingMessageSettingContent(exp);
221
}
222
else {
223
m = await exports.prepareWAMessageMedia(message, options);
224
}
225
if ('buttons' in message && !!message.buttons) {
226
const buttonsMessage = {
227
buttons: message.buttons.map(b => ({ ...b, type: WAProto_1.proto.Button.ButtonType.RESPONSE }))
228
};
229
if ('text' in message) {
230
buttonsMessage.contentText = message.text;
231
buttonsMessage.headerType = ButtonType.EMPTY;
232
}
233
else {
234
if ('caption' in message) {
235
buttonsMessage.contentText = message.caption;
236
}
237
const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
238
buttonsMessage.headerType = ButtonType[type];
239
Object.assign(buttonsMessage, m);
240
}
241
if ('footer' in message && !!message.footer) {
242
buttonsMessage.footerText = message.footer;
243
}
244
m = { buttonsMessage };
245
}
246
else if ('templateButtons' in message && !!message.templateButtons) {
247
const templateMessage = {
248
hydratedTemplate: {
249
hydratedButtons: message.templateButtons
250
}
251
};
252
if ('text' in message) {
253
templateMessage.hydratedTemplate.hydratedContentText = message.text;
254
}
255
else {
256
if ('caption' in message) {
257
templateMessage.hydratedTemplate.hydratedContentText = message.caption;
258
}
259
Object.assign(templateMessage.hydratedTemplate, m);
260
}
261
if ('footer' in message && !!message.footer) {
262
templateMessage.hydratedTemplate.hydratedFooterText = message.footer;
263
}
264
m = { templateMessage };
265
}
266
if ('sections' in message && !!message.sections) {
267
const listMessage = {
268
sections: message.sections,
269
buttonText: message.buttonText,
270
title: message.title,
271
footerText: message.footer,
272
description: message.text,
273
listType: WAProto_1.proto.ListMessage.ListMessageListType['SINGLE_SELECT']
274
};
275
m = { listMessage };
276
}
277
if ('viewOnce' in message && !!message.viewOnce) {
278
m = { viewOnceMessage: { message: m } };
279
}
280
if ('mentions' in message && ((_b = message.mentions) === null || _b === void 0 ? void 0 : _b.length)) {
281
const [messageType] = Object.keys(m);
282
m[messageType].contextInfo = m[messageType] || {};
283
m[messageType].contextInfo.mentionedJid = message.mentions;
284
}
285
return Types_1.WAProto.Message.fromObject(m);
286
};
287
exports.generateWAMessageContent = generateWAMessageContent;
288
const generateWAMessageFromContent = (jid, message, options) => {
289
if (!options.timestamp) {
290
options.timestamp = new Date();
291
} // set timestamp to now
292
const key = Object.keys(message)[0];
293
const timestamp = generics_1.unixTimestampSeconds(options.timestamp);
294
const { quoted, userJid } = options;
295
if (quoted) {
296
const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid);
297
message[key].contextInfo = message[key].contextInfo || {};
298
message[key].contextInfo.participant = participant;
299
message[key].contextInfo.stanzaId = quoted.key.id;
300
message[key].contextInfo.quotedMessage = quoted.message;
301
// if a participant is quoted, then it must be a group
302
// hence, remoteJid of group must also be entered
303
if (quoted.key.participant || quoted.participant) {
304
message[key].contextInfo.remoteJid = quoted.key.remoteJid;
305
}
306
}
307
if (
308
// if we want to send a disappearing message
309
!!(options === null || options === void 0 ? void 0 : options.ephemeralExpiration) &&
310
// and it's not a protocol message -- delete, toggle disappear message
311
key !== 'protocolMessage' &&
312
// already not converted to disappearing message
313
key !== 'ephemeralMessage') {
314
message[key].contextInfo = {
315
...(message[key].contextInfo || {}),
316
expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL,
317
//ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
318
};
319
message = {
320
ephemeralMessage: {
321
message
322
}
323
};
324
}
325
message = Types_1.WAProto.Message.fromObject(message);
326
const messageJSON = {
327
key: {
328
remoteJid: jid,
329
fromMe: true,
330
id: (options === null || options === void 0 ? void 0 : options.messageId) || generics_1.generateMessageID(),
331
},
332
message: message,
333
messageTimestamp: timestamp,
334
messageStubParameters: [],
335
participant: jid.includes('@g.us') ? userJid : undefined,
336
status: Types_1.WAMessageStatus.PENDING
337
};
338
return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON);
339
};
340
exports.generateWAMessageFromContent = generateWAMessageFromContent;
341
const generateWAMessage = async (jid, content, options) => {
342
var _a;
343
// ensure msg ID is with every log
344
options.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) === null || _a === void 0 ? void 0 : _a.child({ msgId: options.messageId });
345
return exports.generateWAMessageFromContent(jid, await exports.generateWAMessageContent(content, options), options);
346
};
347
exports.generateWAMessage = generateWAMessage;
348
/** Get the key to access the true type of content */
349
const getContentType = (content) => {
350
if (content) {
351
const keys = Object.keys(content);
352
const key = keys.find(k => (k === 'conversation' || k.endsWith('Message')) && k !== 'senderKeyDistributionMessage');
353
return key;
354
}
355
};
356
exports.getContentType = getContentType;
357
/**
358
* Extract the true message content from a message
359
* Eg. extracts the inner message from a disappearing message/view once message
360
*/
361
const extractMessageContent = (content) => {
362
var _a, _b, _c, _d, _e, _f, _g, _h;
363
const extractFromTemplateMessage = (msg) => {
364
if (msg.imageMessage) {
365
return { imageMessage: msg.imageMessage };
366
}
367
else if (msg.documentMessage) {
368
return { documentMessage: msg.documentMessage };
369
}
370
else if (msg.videoMessage) {
371
return { videoMessage: msg.videoMessage };
372
}
373
else if (msg.locationMessage) {
374
return { locationMessage: msg.locationMessage };
375
}
376
else {
377
return { conversation: 'contentText' in msg ? msg.contentText : ('hydratedContentText' in msg ? msg.hydratedContentText : '') };
378
}
379
};
380
content = ((_a = content === null || content === void 0 ? void 0 : content.ephemeralMessage) === null || _a === void 0 ? void 0 : _a.message) ||
381
((_b = content === null || content === void 0 ? void 0 : content.viewOnceMessage) === null || _b === void 0 ? void 0 : _b.message) ||
382
content ||
383
undefined;
384
if (content === null || content === void 0 ? void 0 : content.buttonsMessage) {
385
return extractFromTemplateMessage(content.buttonsMessage);
386
}
387
if ((_c = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _c === void 0 ? void 0 : _c.hydratedFourRowTemplate) {
388
return extractFromTemplateMessage((_d = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _d === void 0 ? void 0 : _d.hydratedFourRowTemplate);
389
}
390
if ((_e = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _e === void 0 ? void 0 : _e.hydratedTemplate) {
391
return extractFromTemplateMessage((_f = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _f === void 0 ? void 0 : _f.hydratedTemplate);
392
}
393
if ((_g = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _g === void 0 ? void 0 : _g.fourRowTemplate) {
394
return extractFromTemplateMessage((_h = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _h === void 0 ? void 0 : _h.fourRowTemplate);
395
}
396
return content;
397
};
398
exports.extractMessageContent = extractMessageContent;
399
/**
400
* Returns the device predicted by message ID
401
*/
402
const getDevice = (id) => {
403
const deviceType = id.length > 21 ? 'android' : id.substring(0, 2) === '3A' ? 'ios' : 'web';
404
return deviceType;
405
};
406
exports.getDevice = getDevice;
407
const updateMessageWithReceipt = (msg, receipt) => {
408
msg.userReceipt = msg.userReceipt || [];
409
const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
410
if (recp) {
411
Object.assign(recp, receipt);
412
}
413
else {
414
msg.userReceipt.push(receipt);
415
}
416
};
417
exports.updateMessageWithReceipt = updateMessageWithReceipt;
418
419