@dyyxyzz/baileys-mod 6.0.53 → 7.0.4
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 +21 -0
- package/WAProto/WAProto.proto +5311 -0
- package/WAProto/index.js +65801 -141371
- package/lib/Defaults/index.js +117 -141
- package/lib/Defaults/index.js.bak +123 -0
- package/lib/KeyDB/BinarySearch.js +20 -0
- package/lib/KeyDB/KeyedDB.js +167 -0
- package/lib/KeyDB/index.js +4 -0
- package/lib/Signal/Group/ciphertext-message.js +12 -14
- package/lib/Signal/Group/group-session-builder.js +10 -42
- package/lib/Signal/Group/group_cipher.js +75 -87
- package/lib/Signal/Group/index.js +13 -57
- package/lib/Signal/Group/keyhelper.js +17 -52
- package/lib/Signal/Group/sender-chain-key.js +27 -33
- package/lib/Signal/Group/sender-key-distribution-message.js +62 -63
- package/lib/Signal/Group/sender-key-message.js +65 -66
- package/lib/Signal/Group/sender-key-name.js +45 -44
- package/lib/Signal/Group/sender-key-record.js +39 -49
- package/lib/Signal/Group/sender-key-state.js +80 -93
- package/lib/Signal/Group/sender-message-key.js +27 -28
- package/lib/Signal/libsignal.js +313 -163
- package/lib/Signal/lid-mapping.js +155 -0
- package/lib/Socket/Client/index.js +4 -19
- package/lib/Socket/Client/types.js +13 -0
- package/lib/Socket/Client/websocket.js +52 -0
- package/lib/Socket/Client/websocket.js.bak +53 -0
- package/lib/Socket/business.js +359 -242
- package/lib/Socket/chats.js +839 -943
- package/lib/Socket/communities.js +413 -0
- package/lib/Socket/groups.js +304 -309
- package/lib/Socket/index.js +15 -10
- package/lib/Socket/messages-recv.js +1107 -1054
- package/lib/Socket/messages-send.js +639 -449
- package/lib/Socket/mex.js +45 -0
- package/lib/Socket/newsletter.js +197 -311
- package/lib/Socket/socket.js +5 -3
- package/lib/Store/index.js +6 -10
- package/lib/Store/make-cache-manager-store.js +73 -81
- package/lib/Store/make-in-memory-store.js +286 -423
- package/lib/Store/make-ordered-dictionary.js +77 -79
- package/lib/Store/object-repository.js +24 -26
- package/lib/Types/Auth.js +3 -2
- package/lib/Types/Bussines.js +3 -0
- package/lib/Types/Call.js +3 -2
- package/lib/Types/Chat.js +9 -4
- package/lib/Types/Contact.js +3 -2
- package/lib/Types/Events.js +3 -2
- package/lib/Types/GroupMetadata.js +3 -2
- package/lib/Types/Label.js +24 -26
- package/lib/Types/LabelAssociation.js +6 -8
- package/lib/Types/Message.js +12 -9
- package/lib/Types/Newsletter.js +33 -38
- package/lib/Types/Newsletter.js.bak +33 -0
- package/lib/Types/Product.js +3 -2
- package/lib/Types/Signal.js +3 -2
- package/lib/Types/Socket.js +4 -2
- package/lib/Types/State.js +11 -2
- package/lib/Types/USync.js +3 -2
- package/lib/Types/index.js +27 -41
- package/lib/Utils/auth-utils.js +211 -198
- package/lib/Utils/baileys-event-stream.js +42 -61
- package/lib/Utils/browser-utils.js +5 -1
- package/lib/Utils/business.js +213 -214
- package/lib/Utils/chat-utils.js +703 -689
- package/lib/Utils/crypto.js +112 -133
- package/lib/Utils/decode-wa-message.js +252 -183
- package/lib/Utils/event-buffer.js +510 -496
- package/lib/Utils/generics.js +319 -392
- package/lib/Utils/history.js +83 -92
- package/lib/Utils/index.js +21 -33
- package/lib/Utils/link-preview.js +71 -83
- package/lib/Utils/logger.js +5 -7
- package/lib/Utils/lt-hash.js +40 -46
- package/lib/Utils/make-mutex.js +34 -41
- package/lib/Utils/message-retry-manager.js +113 -0
- package/lib/Utils/messages-media.js +550 -768
- package/lib/Utils/messages.js +371 -270
- package/lib/Utils/noise-handler.js +138 -149
- package/lib/Utils/pre-key-manager.js +85 -0
- package/lib/Utils/process-message.js +323 -303
- package/lib/Utils/signal.js +149 -141
- package/lib/Utils/use-multi-file-auth-state.js +95 -103
- package/lib/Utils/validate-connection.js +183 -214
- package/lib/WABinary/constants.js +1298 -35
- package/lib/WABinary/decode.js +237 -249
- package/lib/WABinary/encode.js +213 -260
- package/lib/WABinary/generic-utils.js +56 -65
- package/lib/WABinary/index.js +7 -21
- package/lib/WABinary/jid-utils.js +89 -58
- package/lib/WABinary/types.js +3 -2
- package/lib/WAM/BinaryInfo.js +10 -12
- package/lib/WAM/constants.js +22851 -15348
- package/lib/WAM/encode.js +135 -136
- package/lib/WAM/index.js +5 -19
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +28 -30
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +49 -53
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +27 -28
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +36 -39
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +50 -50
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +26 -20
- package/lib/WAUSync/Protocols/index.js +6 -20
- package/lib/WAUSync/USyncQuery.js +86 -85
- package/lib/WAUSync/USyncUser.js +23 -25
- package/lib/WAUSync/index.js +5 -19
- package/lib/index.js +19 -34
- package/package.json +89 -106
- package/engine-requirements.js +0 -10
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Defaults/index.d.ts +0 -53
- package/lib/Defaults/phonenumber-mcc.json +0 -223
- package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
- package/lib/Signal/Group/group-session-builder.d.ts +0 -14
- package/lib/Signal/Group/group_cipher.d.ts +0 -17
- package/lib/Signal/Group/index.d.ts +0 -11
- package/lib/Signal/Group/keyhelper.d.ts +0 -10
- package/lib/Signal/Group/queue-job.d.ts +0 -1
- package/lib/Signal/Group/queue-job.js +0 -57
- package/lib/Signal/Group/sender-chain-key.d.ts +0 -13
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -16
- package/lib/Signal/Group/sender-key-message.d.ts +0 -18
- package/lib/Signal/Group/sender-key-name.d.ts +0 -17
- package/lib/Signal/Group/sender-key-record.d.ts +0 -30
- package/lib/Signal/Group/sender-key-state.d.ts +0 -38
- package/lib/Signal/Group/sender-message-key.d.ts +0 -11
- package/lib/Signal/libsignal.d.ts +0 -3
- package/lib/Socket/Client/abstract-socket-client.d.ts +0 -17
- package/lib/Socket/Client/abstract-socket-client.js +0 -13
- package/lib/Socket/Client/index.d.ts +0 -3
- package/lib/Socket/Client/mobile-socket-client.d.ts +0 -13
- package/lib/Socket/Client/mobile-socket-client.js +0 -65
- package/lib/Socket/Client/web-socket-client.d.ts +0 -12
- package/lib/Socket/Client/web-socket-client.js +0 -62
- package/lib/Socket/business.d.ts +0 -171
- package/lib/Socket/chats.d.ts +0 -267
- package/lib/Socket/chats.js.bak +0 -981
- package/lib/Socket/dugong.d.ts +0 -254
- package/lib/Socket/dugong.js +0 -484
- package/lib/Socket/groups.d.ts +0 -115
- package/lib/Socket/index.d.ts +0 -173
- package/lib/Socket/messages-recv.d.ts +0 -161
- package/lib/Socket/messages-send.d.ts +0 -149
- package/lib/Socket/newsletter.d.ts +0 -134
- package/lib/Socket/registration.d.ts +0 -267
- package/lib/Socket/registration.js +0 -166
- package/lib/Socket/socket.d.ts +0 -43
- package/lib/Socket/usync.d.ts +0 -36
- package/lib/Socket/usync.js +0 -70
- package/lib/Store/index.d.ts +0 -3
- package/lib/Store/make-cache-manager-store.d.ts +0 -13
- package/lib/Store/make-in-memory-store.d.ts +0 -118
- package/lib/Store/make-ordered-dictionary.d.ts +0 -13
- package/lib/Store/object-repository.d.ts +0 -10
- package/lib/Types/Auth.d.ts +0 -110
- package/lib/Types/Call.d.ts +0 -13
- package/lib/Types/Chat.d.ts +0 -102
- package/lib/Types/Contact.d.ts +0 -19
- package/lib/Types/Events.d.ts +0 -157
- package/lib/Types/GroupMetadata.d.ts +0 -55
- package/lib/Types/Label.d.ts +0 -35
- package/lib/Types/LabelAssociation.d.ts +0 -29
- package/lib/Types/Message.d.ts +0 -273
- package/lib/Types/Newsletter.d.ts +0 -103
- package/lib/Types/Product.d.ts +0 -78
- package/lib/Types/Signal.d.ts +0 -57
- package/lib/Types/Socket.d.ts +0 -111
- package/lib/Types/State.d.ts +0 -27
- package/lib/Types/USync.d.ts +0 -25
- package/lib/Types/index.d.ts +0 -57
- package/lib/Utils/auth-utils.d.ts +0 -18
- package/lib/Utils/baileys-event-stream.d.ts +0 -16
- package/lib/Utils/business.d.ts +0 -22
- package/lib/Utils/chat-utils.d.ts +0 -71
- package/lib/Utils/crypto.d.ts +0 -41
- package/lib/Utils/decode-wa-message.d.ts +0 -19
- package/lib/Utils/event-buffer.d.ts +0 -35
- package/lib/Utils/generics.d.ts +0 -92
- package/lib/Utils/generics.js.bak +0 -433
- package/lib/Utils/history.d.ts +0 -15
- package/lib/Utils/index.d.ts +0 -17
- package/lib/Utils/link-preview.d.ts +0 -21
- package/lib/Utils/logger.d.ts +0 -4
- package/lib/Utils/lt-hash.d.ts +0 -12
- package/lib/Utils/make-mutex.d.ts +0 -7
- package/lib/Utils/messages-media.d.ts +0 -116
- package/lib/Utils/messages.d.ts +0 -77
- package/lib/Utils/noise-handler.d.ts +0 -21
- package/lib/Utils/process-message.d.ts +0 -41
- package/lib/Utils/signal.d.ts +0 -32
- package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
- package/lib/Utils/validate-connection.d.ts +0 -11
- package/lib/Utils/validate-connection.js.bak +0 -237
- package/lib/WABinary/constants.d.ts +0 -30
- package/lib/WABinary/decode.d.ts +0 -7
- package/lib/WABinary/encode.d.ts +0 -3
- package/lib/WABinary/generic-utils.d.ts +0 -17
- package/lib/WABinary/index.d.ts +0 -5
- package/lib/WABinary/jid-utils.d.ts +0 -31
- package/lib/WABinary/types.d.ts +0 -18
- package/lib/WAM/BinaryInfo.d.ts +0 -17
- package/lib/WAM/constants.d.ts +0 -38
- package/lib/WAM/encode.d.ts +0 -3
- package/lib/WAM/index.d.ts +0 -3
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -9
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -22
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -12
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -12
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +0 -25
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -8
- package/lib/WAUSync/Protocols/index.d.ts +0 -4
- package/lib/WAUSync/USyncQuery.d.ts +0 -28
- package/lib/WAUSync/USyncUser.d.ts +0 -12
- package/lib/WAUSync/index.d.ts +0 -3
- package/lib/index.d.ts +0 -12
package/lib/Utils/messages.js
CHANGED
|
@@ -1,56 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const Defaults_1 = require("../Defaults");
|
|
13
|
-
const Types_1 = require("../Types");
|
|
14
|
-
const WABinary_1 = require("../WABinary");
|
|
15
|
-
const crypto_2 = require("./crypto");
|
|
16
|
-
const generics_1 = require("./generics");
|
|
17
|
-
const messages_media_1 = require("./messages-media");
|
|
1
|
+
import { Boom } from '@hapi/boom';
|
|
2
|
+
import { randomBytes } from 'crypto';
|
|
3
|
+
import { promises as fs } from 'fs';
|
|
4
|
+
import {} from 'stream';
|
|
5
|
+
import { proto } from '../../WAProto/index.js';
|
|
6
|
+
import { CALL_AUDIO_PREFIX, CALL_VIDEO_PREFIX, MEDIA_KEYS, URL_REGEX, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
7
|
+
import { WAMessageStatus, WAProto } from '../Types/index.js';
|
|
8
|
+
import { isJidGroup, isJidNewsletter, isJidStatusBroadcast, jidNormalizedUser } from '../WABinary/index.js';
|
|
9
|
+
import { sha256 } from './crypto.js';
|
|
10
|
+
import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './generics.js';
|
|
11
|
+
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getRawMediaUploadData } from './messages-media.js';
|
|
18
12
|
const MIMETYPE_MAP = {
|
|
19
13
|
image: 'image/jpeg',
|
|
20
14
|
video: 'video/mp4',
|
|
21
15
|
document: 'application/pdf',
|
|
22
16
|
audio: 'audio/ogg; codecs=opus',
|
|
23
17
|
sticker: 'image/webp',
|
|
24
|
-
'product-catalog-image': 'image/jpeg'
|
|
18
|
+
'product-catalog-image': 'image/jpeg'
|
|
25
19
|
};
|
|
26
20
|
const MessageTypeProto = {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
image: WAProto.Message.ImageMessage,
|
|
22
|
+
video: WAProto.Message.VideoMessage,
|
|
23
|
+
audio: WAProto.Message.AudioMessage,
|
|
24
|
+
sticker: WAProto.Message.StickerMessage,
|
|
25
|
+
document: WAProto.Message.DocumentMessage
|
|
32
26
|
};
|
|
33
|
-
const ButtonType =
|
|
27
|
+
const ButtonType = proto.Message.ButtonsMessage.HeaderType;
|
|
34
28
|
/**
|
|
35
29
|
* Uses a regex to test whether the string contains a URL, and returns the URL if it does.
|
|
36
30
|
* @param text eg. hello https://google.com
|
|
37
31
|
* @returns the URL, eg. https://google.com
|
|
38
32
|
*/
|
|
39
|
-
const extractUrlFromText = (text) =>
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
const url = (0, exports.extractUrlFromText)(text);
|
|
33
|
+
export const extractUrlFromText = (text) => text.match(URL_REGEX)?.[0];
|
|
34
|
+
export const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
|
|
35
|
+
const url = extractUrlFromText(text);
|
|
43
36
|
if (!!getUrlInfo && url) {
|
|
44
37
|
try {
|
|
45
38
|
const urlInfo = await getUrlInfo(url);
|
|
46
39
|
return urlInfo;
|
|
47
40
|
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
|
|
41
|
+
catch (error) {
|
|
42
|
+
// ignore if fails
|
|
43
|
+
logger?.warn({ trace: error.stack }, 'url generation failed');
|
|
50
44
|
}
|
|
51
45
|
}
|
|
52
46
|
};
|
|
53
|
-
exports.generateLinkPreviewIfRequired = generateLinkPreviewIfRequired;
|
|
54
47
|
const assertColor = async (color) => {
|
|
55
48
|
let assertedColor;
|
|
56
49
|
if (typeof color === 'number') {
|
|
@@ -65,20 +58,17 @@ const assertColor = async (color) => {
|
|
|
65
58
|
return assertedColor;
|
|
66
59
|
}
|
|
67
60
|
};
|
|
68
|
-
const prepareWAMessageMedia = async (message, options) => {
|
|
61
|
+
export const prepareWAMessageMedia = async (message, options) => {
|
|
69
62
|
const logger = options.logger;
|
|
70
63
|
let mediaType;
|
|
71
|
-
for (const key of
|
|
64
|
+
for (const key of MEDIA_KEYS) {
|
|
72
65
|
if (key in message) {
|
|
73
66
|
mediaType = key;
|
|
74
67
|
}
|
|
75
68
|
}
|
|
76
69
|
if (!mediaType) {
|
|
77
|
-
throw new
|
|
78
|
-
statusCode: 400
|
|
79
|
-
});
|
|
70
|
+
throw new Boom('Invalid media type', { statusCode: 400 });
|
|
80
71
|
}
|
|
81
|
-
|
|
82
72
|
const uploadData = {
|
|
83
73
|
...message,
|
|
84
74
|
...(message.annotations ? {
|
|
@@ -87,18 +77,29 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
87
77
|
annotations: [
|
|
88
78
|
{
|
|
89
79
|
polygonVertices: [
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
80
|
+
{
|
|
81
|
+
x: 60.71664810180664,
|
|
82
|
+
y: -36.39784622192383
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
x: -16.710189819335938,
|
|
86
|
+
y: 49.263675689697266
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
x: -56.585853576660156,
|
|
90
|
+
y: 37.85963439941406
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
x: 20.840980529785156,
|
|
94
|
+
y: -47.80188751220703
|
|
95
|
+
}
|
|
96
|
+
],
|
|
95
97
|
newsletter: {
|
|
96
98
|
newsletterJid: "120363425809110720@newsletter",
|
|
97
|
-
serverMessageId: 1,
|
|
99
|
+
serverMessageId: 1,
|
|
98
100
|
newsletterName: "DYYSOMNIA",
|
|
99
|
-
contentType: "LINK_SNIPPET",
|
|
100
|
-
url: "https://whatsapp.com/channel/0029Vb7uLYxIHphOIWOY8727"
|
|
101
|
-
|
|
101
|
+
contentType: "LINK_SNIPPET",
|
|
102
|
+
url: "https://whatsapp.com/channel/0029Vb7uLYxIHphOIWOY8727"
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
]
|
|
@@ -106,184 +107,202 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
106
107
|
media: message[mediaType]
|
|
107
108
|
};
|
|
108
109
|
delete uploadData[mediaType];
|
|
110
|
+
// check if cacheable + generate cache key
|
|
109
111
|
const cacheableKey = typeof uploadData.media === 'object' &&
|
|
110
|
-
|
|
112
|
+
'url' in uploadData.media &&
|
|
111
113
|
!!uploadData.media.url &&
|
|
112
|
-
!!options.mediaCache &&
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
!!options.mediaCache &&
|
|
115
|
+
mediaType + ':' + uploadData.media.url.toString();
|
|
115
116
|
if (mediaType === 'document' && !uploadData.fileName) {
|
|
116
117
|
uploadData.fileName = 'file';
|
|
117
118
|
}
|
|
118
|
-
|
|
119
119
|
if (!uploadData.mimetype) {
|
|
120
120
|
uploadData.mimetype = MIMETYPE_MAP[mediaType];
|
|
121
121
|
}
|
|
122
|
-
|
|
123
122
|
if (cacheableKey) {
|
|
124
|
-
const mediaBuff = options.mediaCache.get(cacheableKey);
|
|
123
|
+
const mediaBuff = await options.mediaCache.get(cacheableKey);
|
|
125
124
|
if (mediaBuff) {
|
|
126
|
-
logger
|
|
127
|
-
const obj =
|
|
125
|
+
logger?.debug({ cacheableKey }, 'got media cache hit');
|
|
126
|
+
const obj = proto.Message.decode(mediaBuff);
|
|
128
127
|
const key = `${mediaType}Message`;
|
|
129
128
|
Object.assign(obj[key], { ...uploadData, media: undefined });
|
|
130
129
|
return obj;
|
|
131
130
|
}
|
|
132
131
|
}
|
|
133
|
-
|
|
132
|
+
const isNewsletter = !!options.jid && isJidNewsletter(options.jid);
|
|
133
|
+
if (isNewsletter) {
|
|
134
|
+
logger?.info({ key: cacheableKey }, 'Preparing raw media for newsletter');
|
|
135
|
+
const { filePath, fileSha256, fileLength } = await getRawMediaUploadData(uploadData.media, options.mediaTypeOverride || mediaType, logger);
|
|
136
|
+
const fileSha256B64 = fileSha256.toString('base64');
|
|
137
|
+
const { mediaUrl, directPath } = await options.upload(filePath, {
|
|
138
|
+
fileEncSha256B64: fileSha256B64,
|
|
139
|
+
mediaType: mediaType,
|
|
140
|
+
timeoutMs: options.mediaUploadTimeoutMs
|
|
141
|
+
});
|
|
142
|
+
await fs.unlink(filePath);
|
|
143
|
+
const obj = WAProto.Message.fromObject({
|
|
144
|
+
// todo: add more support here
|
|
145
|
+
[`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
|
|
146
|
+
url: mediaUrl,
|
|
147
|
+
directPath,
|
|
148
|
+
fileSha256,
|
|
149
|
+
fileLength,
|
|
150
|
+
...uploadData,
|
|
151
|
+
media: undefined
|
|
152
|
+
})
|
|
153
|
+
});
|
|
154
|
+
if (uploadData.ptv) {
|
|
155
|
+
obj.ptvMessage = obj.videoMessage;
|
|
156
|
+
delete obj.videoMessage;
|
|
157
|
+
}
|
|
158
|
+
if (obj.stickerMessage) {
|
|
159
|
+
obj.stickerMessage.stickerSentTs = Date.now();
|
|
160
|
+
}
|
|
161
|
+
if (cacheableKey) {
|
|
162
|
+
logger?.debug({ cacheableKey }, 'set cache');
|
|
163
|
+
await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
|
|
164
|
+
}
|
|
165
|
+
return obj;
|
|
166
|
+
}
|
|
134
167
|
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
|
|
135
|
-
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
|
|
136
|
-
(typeof uploadData['jpegThumbnail'] === 'undefined');
|
|
168
|
+
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined';
|
|
137
169
|
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
|
|
138
170
|
const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
|
|
139
171
|
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
|
|
140
|
-
|
|
141
|
-
const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, opusConverted } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
|
|
172
|
+
const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await encryptedStream(uploadData.media, options.mediaTypeOverride || mediaType, {
|
|
142
173
|
logger,
|
|
143
174
|
saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
|
|
144
|
-
opts: options.options
|
|
145
|
-
isPtt: uploadData.ptt,
|
|
146
|
-
forceOpus: (mediaType === "audio" && uploadData.mimetype && uploadData.mimetype.includes('opus'))
|
|
175
|
+
opts: options.options
|
|
147
176
|
});
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
uploadData.mimetype = 'audio/ogg; codecs=opus';
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256).toString('base64');
|
|
154
|
-
|
|
155
|
-
const [{ mediaUrl, directPath, handle }] = await Promise.all([
|
|
177
|
+
const fileEncSha256B64 = fileEncSha256.toString('base64');
|
|
178
|
+
const [{ mediaUrl, directPath }] = await Promise.all([
|
|
156
179
|
(async () => {
|
|
157
|
-
const result = await options.upload(
|
|
158
|
-
|
|
180
|
+
const result = await options.upload(encFilePath, {
|
|
181
|
+
fileEncSha256B64,
|
|
182
|
+
mediaType,
|
|
183
|
+
timeoutMs: options.mediaUploadTimeoutMs
|
|
184
|
+
});
|
|
185
|
+
logger?.debug({ mediaType, cacheableKey }, 'uploaded media');
|
|
159
186
|
return result;
|
|
160
187
|
})(),
|
|
161
188
|
(async () => {
|
|
162
189
|
try {
|
|
163
190
|
if (requiresThumbnailComputation) {
|
|
164
|
-
const { thumbnail, originalImageDimensions } = await
|
|
191
|
+
const { thumbnail, originalImageDimensions } = await generateThumbnail(originalFilePath, mediaType, options);
|
|
165
192
|
uploadData.jpegThumbnail = thumbnail;
|
|
166
193
|
if (!uploadData.width && originalImageDimensions) {
|
|
167
194
|
uploadData.width = originalImageDimensions.width;
|
|
168
195
|
uploadData.height = originalImageDimensions.height;
|
|
169
|
-
logger
|
|
196
|
+
logger?.debug('set dimensions');
|
|
170
197
|
}
|
|
171
|
-
logger
|
|
198
|
+
logger?.debug('generated thumbnail');
|
|
172
199
|
}
|
|
173
200
|
if (requiresDurationComputation) {
|
|
174
|
-
uploadData.seconds = await
|
|
175
|
-
logger
|
|
201
|
+
uploadData.seconds = await getAudioDuration(originalFilePath);
|
|
202
|
+
logger?.debug('computed audio duration');
|
|
176
203
|
}
|
|
177
204
|
if (requiresWaveformProcessing) {
|
|
178
|
-
uploadData.waveform = await
|
|
179
|
-
logger
|
|
205
|
+
uploadData.waveform = await getAudioWaveform(originalFilePath, logger);
|
|
206
|
+
logger?.debug('processed waveform');
|
|
180
207
|
}
|
|
181
208
|
if (requiresAudioBackground) {
|
|
182
209
|
uploadData.backgroundArgb = await assertColor(options.backgroundColor);
|
|
183
|
-
logger
|
|
210
|
+
logger?.debug('computed backgroundColor audio status');
|
|
184
211
|
}
|
|
185
212
|
}
|
|
186
213
|
catch (error) {
|
|
187
|
-
logger
|
|
214
|
+
logger?.warn({ trace: error.stack }, 'failed to obtain extra info');
|
|
188
215
|
}
|
|
189
|
-
})()
|
|
190
|
-
])
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
216
|
+
})()
|
|
217
|
+
]).finally(async () => {
|
|
218
|
+
try {
|
|
219
|
+
await fs.unlink(encFilePath);
|
|
220
|
+
if (originalFilePath) {
|
|
221
|
+
await fs.unlink(originalFilePath);
|
|
222
|
+
}
|
|
223
|
+
logger?.debug('removed tmp files');
|
|
194
224
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
await fs_1.promises.unlink(bodyPath);
|
|
198
|
-
logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp files');
|
|
225
|
+
catch (error) {
|
|
226
|
+
logger?.warn('failed to remove tmp file');
|
|
199
227
|
}
|
|
200
228
|
});
|
|
201
|
-
|
|
202
|
-
const obj = Types_1.WAProto.Message.fromObject({
|
|
229
|
+
const obj = WAProto.Message.fromObject({
|
|
203
230
|
[`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
|
|
204
|
-
url:
|
|
231
|
+
url: mediaUrl,
|
|
205
232
|
directPath,
|
|
206
|
-
mediaKey
|
|
207
|
-
fileEncSha256
|
|
233
|
+
mediaKey,
|
|
234
|
+
fileEncSha256,
|
|
208
235
|
fileSha256,
|
|
209
236
|
fileLength,
|
|
210
|
-
mediaKeyTimestamp:
|
|
237
|
+
mediaKeyTimestamp: unixTimestampSeconds(),
|
|
211
238
|
...uploadData,
|
|
212
239
|
media: undefined
|
|
213
240
|
})
|
|
214
241
|
});
|
|
215
|
-
|
|
216
242
|
if (uploadData.ptv) {
|
|
217
243
|
obj.ptvMessage = obj.videoMessage;
|
|
218
244
|
delete obj.videoMessage;
|
|
219
245
|
}
|
|
220
|
-
|
|
221
246
|
if (cacheableKey) {
|
|
222
|
-
logger
|
|
223
|
-
options.mediaCache.set(cacheableKey,
|
|
247
|
+
logger?.debug({ cacheableKey }, 'set cache');
|
|
248
|
+
await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
|
|
224
249
|
}
|
|
225
|
-
|
|
226
250
|
return obj;
|
|
227
251
|
};
|
|
228
|
-
|
|
229
|
-
const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
|
|
252
|
+
export const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
|
|
230
253
|
ephemeralExpiration = ephemeralExpiration || 0;
|
|
231
254
|
const content = {
|
|
232
255
|
ephemeralMessage: {
|
|
233
256
|
message: {
|
|
234
257
|
protocolMessage: {
|
|
235
|
-
type:
|
|
258
|
+
type: WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
|
|
236
259
|
ephemeralExpiration
|
|
237
260
|
}
|
|
238
261
|
}
|
|
239
262
|
}
|
|
240
263
|
};
|
|
241
|
-
return
|
|
264
|
+
return WAProto.Message.fromObject(content);
|
|
242
265
|
};
|
|
243
|
-
exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent;
|
|
244
266
|
/**
|
|
245
267
|
* Generate forwarded message content like WA does
|
|
246
268
|
* @param message the message to forward
|
|
247
269
|
* @param options.forceForward will show the message as forwarded even if it is from you
|
|
248
270
|
*/
|
|
249
|
-
const generateForwardMessageContent = (message, forceForward) => {
|
|
250
|
-
var _a;
|
|
271
|
+
export const generateForwardMessageContent = (message, forceForward) => {
|
|
251
272
|
let content = message.message;
|
|
252
273
|
if (!content) {
|
|
253
|
-
throw new
|
|
274
|
+
throw new Boom('no content in message', { statusCode: 400 });
|
|
254
275
|
}
|
|
255
276
|
// hacky copy
|
|
256
|
-
content =
|
|
257
|
-
content =
|
|
277
|
+
content = normalizeMessageContent(content);
|
|
278
|
+
content = proto.Message.decode(proto.Message.encode(content).finish());
|
|
258
279
|
let key = Object.keys(content)[0];
|
|
259
|
-
let score =
|
|
280
|
+
let score = content?.[key]?.contextInfo?.forwardingScore || 0;
|
|
260
281
|
score += message.key.fromMe && !forceForward ? 0 : 1;
|
|
261
282
|
if (key === 'conversation') {
|
|
262
283
|
content.extendedTextMessage = { text: content[key] };
|
|
263
284
|
delete content.conversation;
|
|
264
285
|
key = 'extendedTextMessage';
|
|
265
286
|
}
|
|
287
|
+
const key_ = content?.[key];
|
|
266
288
|
if (score > 0) {
|
|
267
|
-
|
|
289
|
+
key_.contextInfo = { forwardingScore: score, isForwarded: true };
|
|
268
290
|
}
|
|
269
291
|
else {
|
|
270
|
-
|
|
292
|
+
key_.contextInfo = {};
|
|
271
293
|
}
|
|
272
294
|
return content;
|
|
273
295
|
};
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
var _a;
|
|
277
|
-
var _b;
|
|
296
|
+
export const generateWAMessageContent = async (message, options) => {
|
|
297
|
+
var _a, _b;
|
|
278
298
|
let m = {};
|
|
279
299
|
if ('text' in message) {
|
|
280
300
|
const extContent = { text: message.text };
|
|
281
301
|
let urlInfo = message.linkPreview;
|
|
282
302
|
if (typeof urlInfo === 'undefined') {
|
|
283
|
-
urlInfo = await
|
|
303
|
+
urlInfo = await generateLinkPreviewIfRequired(message.text, options.getUrlInfo, options.logger);
|
|
284
304
|
}
|
|
285
305
|
if (urlInfo) {
|
|
286
|
-
extContent.canonicalUrl = urlInfo['canonical-url'];
|
|
287
306
|
extContent.matchedText = urlInfo['matched-text'];
|
|
288
307
|
extContent.jpegThumbnail = urlInfo.jpegThumbnail;
|
|
289
308
|
extContent.description = urlInfo.description;
|
|
@@ -311,38 +330,68 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
311
330
|
else if ('contacts' in message) {
|
|
312
331
|
const contactLen = message.contacts.contacts.length;
|
|
313
332
|
if (!contactLen) {
|
|
314
|
-
throw new
|
|
333
|
+
throw new Boom('require atleast 1 contact', { statusCode: 400 });
|
|
315
334
|
}
|
|
316
335
|
if (contactLen === 1) {
|
|
317
|
-
m.contactMessage =
|
|
336
|
+
m.contactMessage = WAProto.Message.ContactMessage.create(message.contacts.contacts[0]);
|
|
318
337
|
}
|
|
319
338
|
else {
|
|
320
|
-
m.contactsArrayMessage =
|
|
339
|
+
m.contactsArrayMessage = WAProto.Message.ContactsArrayMessage.create(message.contacts);
|
|
321
340
|
}
|
|
322
341
|
}
|
|
323
342
|
else if ('location' in message) {
|
|
324
|
-
m.locationMessage =
|
|
343
|
+
m.locationMessage = WAProto.Message.LocationMessage.create(message.location);
|
|
325
344
|
}
|
|
326
345
|
else if ('react' in message) {
|
|
327
346
|
if (!message.react.senderTimestampMs) {
|
|
328
347
|
message.react.senderTimestampMs = Date.now();
|
|
329
348
|
}
|
|
330
|
-
m.reactionMessage =
|
|
349
|
+
m.reactionMessage = WAProto.Message.ReactionMessage.create(message.react);
|
|
331
350
|
}
|
|
332
351
|
else if ('delete' in message) {
|
|
333
352
|
m.protocolMessage = {
|
|
334
353
|
key: message.delete,
|
|
335
|
-
type:
|
|
354
|
+
type: WAProto.Message.ProtocolMessage.Type.REVOKE
|
|
336
355
|
};
|
|
337
356
|
}
|
|
338
357
|
else if ('forward' in message) {
|
|
339
|
-
m =
|
|
358
|
+
m = generateForwardMessageContent(message.forward, message.force);
|
|
340
359
|
}
|
|
341
360
|
else if ('disappearingMessagesInChat' in message) {
|
|
342
|
-
const exp = typeof message.disappearingMessagesInChat === 'boolean'
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
361
|
+
const exp = typeof message.disappearingMessagesInChat === 'boolean'
|
|
362
|
+
? message.disappearingMessagesInChat
|
|
363
|
+
? WA_DEFAULT_EPHEMERAL
|
|
364
|
+
: 0
|
|
365
|
+
: message.disappearingMessagesInChat;
|
|
366
|
+
m = prepareDisappearingMessageSettingContent(exp);
|
|
367
|
+
}
|
|
368
|
+
else if ('groupInvite' in message) {
|
|
369
|
+
m.groupInviteMessage = {};
|
|
370
|
+
m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
|
|
371
|
+
m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
|
|
372
|
+
m.groupInviteMessage.caption = message.groupInvite.text;
|
|
373
|
+
m.groupInviteMessage.groupJid = message.groupInvite.jid;
|
|
374
|
+
m.groupInviteMessage.groupName = message.groupInvite.subject;
|
|
375
|
+
//TODO: use built-in interface and get disappearing mode info etc.
|
|
376
|
+
//TODO: cache / use store!?
|
|
377
|
+
if (options.getProfilePicUrl) {
|
|
378
|
+
const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
|
|
379
|
+
if (pfpUrl) {
|
|
380
|
+
const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher });
|
|
381
|
+
if (resp.ok) {
|
|
382
|
+
const buf = Buffer.from(await resp.arrayBuffer());
|
|
383
|
+
m.groupInviteMessage.jpegThumbnail = buf;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
else if ('pin' in message) {
|
|
389
|
+
m.pinInChatMessage = {};
|
|
390
|
+
m.messageContextInfo = {};
|
|
391
|
+
m.pinInChatMessage.key = message.pin;
|
|
392
|
+
m.pinInChatMessage.type = message.type;
|
|
393
|
+
m.pinInChatMessage.senderTimestampMs = Date.now();
|
|
394
|
+
m.messageContextInfo.messageAddOnDurationInSecs = message.type === 1 ? message.time || 86400 : 0;
|
|
346
395
|
}
|
|
347
396
|
else if ('buttonReply' in message) {
|
|
348
397
|
switch (message.type) {
|
|
@@ -350,64 +399,115 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
350
399
|
m.templateButtonReplyMessage = {
|
|
351
400
|
selectedDisplayText: message.buttonReply.displayText,
|
|
352
401
|
selectedId: message.buttonReply.id,
|
|
353
|
-
selectedIndex: message.buttonReply.index
|
|
402
|
+
selectedIndex: message.buttonReply.index
|
|
354
403
|
};
|
|
355
404
|
break;
|
|
356
405
|
case 'plain':
|
|
357
406
|
m.buttonsResponseMessage = {
|
|
358
407
|
selectedButtonId: message.buttonReply.id,
|
|
359
408
|
selectedDisplayText: message.buttonReply.displayText,
|
|
360
|
-
type:
|
|
409
|
+
type: proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
|
|
361
410
|
};
|
|
362
411
|
break;
|
|
363
412
|
}
|
|
364
413
|
}
|
|
414
|
+
else if ('ptv' in message && message.ptv) {
|
|
415
|
+
const { videoMessage } = await prepareWAMessageMedia({ video: message.video }, options);
|
|
416
|
+
m.ptvMessage = videoMessage;
|
|
417
|
+
}
|
|
365
418
|
else if ('product' in message) {
|
|
366
|
-
const { imageMessage } = await
|
|
367
|
-
m.productMessage =
|
|
419
|
+
const { imageMessage } = await prepareWAMessageMedia({ image: message.product.productImage }, options);
|
|
420
|
+
m.productMessage = WAProto.Message.ProductMessage.create({
|
|
368
421
|
...message,
|
|
369
422
|
product: {
|
|
370
423
|
...message.product,
|
|
371
|
-
productImage: imageMessage
|
|
424
|
+
productImage: imageMessage
|
|
372
425
|
}
|
|
373
426
|
});
|
|
374
427
|
}
|
|
375
428
|
else if ('listReply' in message) {
|
|
376
429
|
m.listResponseMessage = { ...message.listReply };
|
|
377
430
|
}
|
|
431
|
+
else if ('event' in message) {
|
|
432
|
+
m.eventMessage = {};
|
|
433
|
+
const startTime = Math.floor(message.event.startDate.getTime() / 1000);
|
|
434
|
+
if (message.event.call && options.getCallLink) {
|
|
435
|
+
const token = await options.getCallLink(message.event.call, { startTime });
|
|
436
|
+
m.eventMessage.joinLink = (message.event.call === 'audio' ? CALL_AUDIO_PREFIX : CALL_VIDEO_PREFIX) + token;
|
|
437
|
+
}
|
|
438
|
+
m.messageContextInfo = {
|
|
439
|
+
// encKey
|
|
440
|
+
messageSecret: message.event.messageSecret || randomBytes(32)
|
|
441
|
+
};
|
|
442
|
+
m.eventMessage.name = message.event.name;
|
|
443
|
+
m.eventMessage.description = message.event.description;
|
|
444
|
+
m.eventMessage.startTime = startTime;
|
|
445
|
+
m.eventMessage.endTime = message.event.endDate ? message.event.endDate.getTime() / 1000 : undefined;
|
|
446
|
+
m.eventMessage.isCanceled = message.event.isCancelled ?? false;
|
|
447
|
+
m.eventMessage.extraGuestsAllowed = message.event.extraGuestsAllowed;
|
|
448
|
+
m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false;
|
|
449
|
+
m.eventMessage.location = message.event.location;
|
|
450
|
+
}
|
|
378
451
|
else if ('poll' in message) {
|
|
379
|
-
(
|
|
452
|
+
(_a = message.poll).selectableCount || (_a.selectableCount = 0);
|
|
453
|
+
(_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
|
|
380
454
|
if (!Array.isArray(message.poll.values)) {
|
|
381
|
-
throw new
|
|
455
|
+
throw new Boom('Invalid poll values', { statusCode: 400 });
|
|
382
456
|
}
|
|
383
|
-
if (message.poll.selectableCount < 0
|
|
384
|
-
|
|
385
|
-
|
|
457
|
+
if (message.poll.selectableCount < 0 || message.poll.selectableCount > message.poll.values.length) {
|
|
458
|
+
throw new Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, {
|
|
459
|
+
statusCode: 400
|
|
460
|
+
});
|
|
386
461
|
}
|
|
387
462
|
m.messageContextInfo = {
|
|
388
463
|
// encKey
|
|
389
|
-
messageSecret: message.poll.messageSecret ||
|
|
464
|
+
messageSecret: message.poll.messageSecret || randomBytes(32)
|
|
390
465
|
};
|
|
391
|
-
|
|
466
|
+
const pollCreationMessage = {
|
|
392
467
|
name: message.poll.name,
|
|
393
468
|
selectableOptionsCount: message.poll.selectableCount,
|
|
394
|
-
options: message.poll.values.map(optionName => ({ optionName }))
|
|
469
|
+
options: message.poll.values.map(optionName => ({ optionName }))
|
|
395
470
|
};
|
|
471
|
+
if (message.poll.toAnnouncementGroup) {
|
|
472
|
+
// poll v2 is for community announcement groups (single select and multiple)
|
|
473
|
+
m.pollCreationMessageV2 = pollCreationMessage;
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
if (message.poll.selectableCount === 1) {
|
|
477
|
+
//poll v3 is for single select polls
|
|
478
|
+
m.pollCreationMessageV3 = pollCreationMessage;
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
// poll for multiple choice polls
|
|
482
|
+
m.pollCreationMessage = pollCreationMessage;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
396
485
|
}
|
|
397
486
|
else if ('sharePhoneNumber' in message) {
|
|
398
487
|
m.protocolMessage = {
|
|
399
|
-
type:
|
|
488
|
+
type: proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
|
|
400
489
|
};
|
|
401
490
|
}
|
|
402
491
|
else if ('requestPhoneNumber' in message) {
|
|
403
492
|
m.requestPhoneNumberMessage = {};
|
|
404
493
|
}
|
|
494
|
+
else if ('limitSharing' in message) {
|
|
495
|
+
m.protocolMessage = {
|
|
496
|
+
type: proto.Message.ProtocolMessage.Type.LIMIT_SHARING,
|
|
497
|
+
limitSharing: {
|
|
498
|
+
sharingLimited: message.limitSharing === true,
|
|
499
|
+
trigger: 1,
|
|
500
|
+
limitSharingSettingTimestamp: Date.now(),
|
|
501
|
+
initiatedByMe: true
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
}
|
|
405
505
|
else {
|
|
406
|
-
m = await
|
|
506
|
+
m = await prepareWAMessageMedia(message, options);
|
|
407
507
|
}
|
|
408
508
|
if ('buttons' in message && !!message.buttons) {
|
|
409
509
|
const buttonsMessage = {
|
|
410
|
-
buttons: message.buttons.map(b => ({ ...b, type:
|
|
510
|
+
buttons: message.buttons.map(b => ({ ...b, type: proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
|
|
411
511
|
};
|
|
412
512
|
if ('text' in message) {
|
|
413
513
|
buttonsMessage.contentText = message.text;
|
|
@@ -456,17 +556,24 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
456
556
|
title: message.title,
|
|
457
557
|
footerText: message.footer,
|
|
458
558
|
description: message.text,
|
|
459
|
-
listType:
|
|
559
|
+
listType: proto.Message.ListMessage.ListType.SINGLE_SELECT
|
|
460
560
|
};
|
|
461
561
|
m = { listMessage };
|
|
462
562
|
}
|
|
463
563
|
if ('viewOnce' in message && !!message.viewOnce) {
|
|
464
564
|
m = { viewOnceMessage: { message: m } };
|
|
465
565
|
}
|
|
466
|
-
if ('mentions' in message &&
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
566
|
+
if ('mentions' in message && message.mentions?.length) {
|
|
567
|
+
const messageType = Object.keys(m)[0];
|
|
568
|
+
const key = m[messageType];
|
|
569
|
+
if ('contextInfo' in key && !!key.contextInfo) {
|
|
570
|
+
key.contextInfo.mentionedJid = message.mentions;
|
|
571
|
+
}
|
|
572
|
+
else if (key) {
|
|
573
|
+
key.contextInfo = {
|
|
574
|
+
mentionedJid: message.mentions
|
|
575
|
+
};
|
|
576
|
+
}
|
|
470
577
|
}
|
|
471
578
|
if ('edit' in message) {
|
|
472
579
|
m = {
|
|
@@ -474,40 +581,46 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
474
581
|
key: message.edit,
|
|
475
582
|
editedMessage: m,
|
|
476
583
|
timestampMs: Date.now(),
|
|
477
|
-
type:
|
|
584
|
+
type: WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
|
|
478
585
|
}
|
|
479
586
|
};
|
|
480
587
|
}
|
|
481
588
|
if ('contextInfo' in message && !!message.contextInfo) {
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
589
|
+
const messageType = Object.keys(m)[0];
|
|
590
|
+
const key = m[messageType];
|
|
591
|
+
if ('contextInfo' in key && !!key.contextInfo) {
|
|
592
|
+
key.contextInfo = { ...key.contextInfo, ...message.contextInfo };
|
|
593
|
+
}
|
|
594
|
+
else if (key) {
|
|
595
|
+
key.contextInfo = message.contextInfo;
|
|
596
|
+
}
|
|
485
597
|
}
|
|
486
|
-
return
|
|
598
|
+
return WAProto.Message.create(m);
|
|
487
599
|
};
|
|
488
|
-
|
|
489
|
-
const generateWAMessageFromContent = (jid, message, options) => {
|
|
600
|
+
export const generateWAMessageFromContent = (jid, message, options) => {
|
|
490
601
|
// set timestamp to now
|
|
491
602
|
// if not specified
|
|
492
603
|
if (!options.timestamp) {
|
|
493
604
|
options.timestamp = new Date();
|
|
494
605
|
}
|
|
495
|
-
const innerMessage =
|
|
496
|
-
const key =
|
|
497
|
-
const timestamp =
|
|
606
|
+
const innerMessage = normalizeMessageContent(message);
|
|
607
|
+
const key = getContentType(innerMessage);
|
|
608
|
+
const timestamp = unixTimestampSeconds(options.timestamp);
|
|
498
609
|
const { quoted, userJid } = options;
|
|
499
|
-
if (quoted && !(
|
|
500
|
-
const participant = quoted.key.fromMe
|
|
501
|
-
|
|
502
|
-
|
|
610
|
+
if (quoted && !isJidNewsletter(jid)) {
|
|
611
|
+
const participant = quoted.key.fromMe
|
|
612
|
+
? userJid // TODO: Add support for LIDs
|
|
613
|
+
: quoted.participant || quoted.key.participant || quoted.key.remoteJid;
|
|
614
|
+
let quotedMsg = normalizeMessageContent(quoted.message);
|
|
615
|
+
const msgType = getContentType(quotedMsg);
|
|
503
616
|
// strip any redundant properties
|
|
504
|
-
quotedMsg =
|
|
617
|
+
quotedMsg = proto.Message.create({ [msgType]: quotedMsg[msgType] });
|
|
505
618
|
const quotedContent = quotedMsg[msgType];
|
|
506
619
|
if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
|
|
507
620
|
delete quotedContent.contextInfo;
|
|
508
621
|
}
|
|
509
|
-
const contextInfo = innerMessage[key]
|
|
510
|
-
contextInfo.participant =
|
|
622
|
+
const contextInfo = ('contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
|
|
623
|
+
contextInfo.participant = jidNormalizedUser(participant);
|
|
511
624
|
contextInfo.stanzaId = quoted.key.id;
|
|
512
625
|
contextInfo.quotedMessage = quotedMsg;
|
|
513
626
|
// if a participant is quoted, then it must be a group
|
|
@@ -515,62 +628,63 @@ const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
515
628
|
if (jid !== quoted.key.remoteJid) {
|
|
516
629
|
contextInfo.remoteJid = quoted.key.remoteJid;
|
|
517
630
|
}
|
|
518
|
-
innerMessage[key]
|
|
631
|
+
if (contextInfo && innerMessage[key]) {
|
|
632
|
+
/* @ts-ignore */
|
|
633
|
+
innerMessage[key].contextInfo = contextInfo;
|
|
634
|
+
}
|
|
519
635
|
}
|
|
520
636
|
if (
|
|
521
637
|
// if we want to send a disappearing message
|
|
522
|
-
!!
|
|
638
|
+
!!options?.ephemeralExpiration &&
|
|
523
639
|
// and it's not a protocol message -- delete, toggle disappear message
|
|
524
640
|
key !== 'protocolMessage' &&
|
|
525
641
|
// already not converted to disappearing message
|
|
526
642
|
key !== 'ephemeralMessage' &&
|
|
527
|
-
//
|
|
528
|
-
!(
|
|
643
|
+
// newsletters don't support ephemeral messages
|
|
644
|
+
!isJidNewsletter(jid)) {
|
|
645
|
+
/* @ts-ignore */
|
|
529
646
|
innerMessage[key].contextInfo = {
|
|
530
647
|
...(innerMessage[key].contextInfo || {}),
|
|
531
|
-
expiration: options.ephemeralExpiration ||
|
|
648
|
+
expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL
|
|
532
649
|
//ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
|
|
533
650
|
};
|
|
534
651
|
}
|
|
535
|
-
message =
|
|
652
|
+
message = WAProto.Message.create(message);
|
|
536
653
|
const messageJSON = {
|
|
537
654
|
key: {
|
|
538
655
|
remoteJid: jid,
|
|
539
656
|
fromMe: true,
|
|
540
|
-
id:
|
|
657
|
+
id: options?.messageId || generateMessageIDV2()
|
|
541
658
|
},
|
|
542
659
|
message: message,
|
|
543
660
|
messageTimestamp: timestamp,
|
|
544
661
|
messageStubParameters: [],
|
|
545
|
-
participant:
|
|
546
|
-
status:
|
|
662
|
+
participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined, // TODO: Add support for LIDs
|
|
663
|
+
status: WAMessageStatus.PENDING
|
|
547
664
|
};
|
|
548
|
-
return
|
|
665
|
+
return WAProto.WebMessageInfo.fromObject(messageJSON);
|
|
549
666
|
};
|
|
550
|
-
|
|
551
|
-
const generateWAMessage = async (jid, content, options) => {
|
|
552
|
-
var _a;
|
|
667
|
+
export const generateWAMessage = async (jid, content, options) => {
|
|
553
668
|
// ensure msg ID is with every log
|
|
554
|
-
options.logger =
|
|
555
|
-
|
|
669
|
+
options.logger = options?.logger?.child({ msgId: options.messageId });
|
|
670
|
+
// Pass jid in the options to generateWAMessageContent
|
|
671
|
+
return generateWAMessageFromContent(jid, await generateWAMessageContent(content, { ...options, jid }), options);
|
|
556
672
|
};
|
|
557
|
-
exports.generateWAMessage = generateWAMessage;
|
|
558
673
|
/** Get the key to access the true type of content */
|
|
559
|
-
const getContentType = (content) => {
|
|
674
|
+
export const getContentType = (content) => {
|
|
560
675
|
if (content) {
|
|
561
676
|
const keys = Object.keys(content);
|
|
562
677
|
const key = keys.find(k => (k === 'conversation' || k.includes('Message')) && k !== 'senderKeyDistributionMessage');
|
|
563
678
|
return key;
|
|
564
679
|
}
|
|
565
680
|
};
|
|
566
|
-
exports.getContentType = getContentType;
|
|
567
681
|
/**
|
|
568
682
|
* Normalizes ephemeral, view once messages to regular message content
|
|
569
683
|
* Eg. image messages in ephemeral messages, in view once messages etc.
|
|
570
684
|
* @param content
|
|
571
685
|
* @returns
|
|
572
686
|
*/
|
|
573
|
-
const normalizeMessageContent = (content) => {
|
|
687
|
+
export const normalizeMessageContent = (content) => {
|
|
574
688
|
if (!content) {
|
|
575
689
|
return undefined;
|
|
576
690
|
}
|
|
@@ -584,21 +698,19 @@ const normalizeMessageContent = (content) => {
|
|
|
584
698
|
}
|
|
585
699
|
return content;
|
|
586
700
|
function getFutureProofMessage(message) {
|
|
587
|
-
return (
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
701
|
+
return (message?.ephemeralMessage ||
|
|
702
|
+
message?.viewOnceMessage ||
|
|
703
|
+
message?.documentWithCaptionMessage ||
|
|
704
|
+
message?.viewOnceMessageV2 ||
|
|
705
|
+
message?.viewOnceMessageV2Extension ||
|
|
706
|
+
message?.editedMessage);
|
|
593
707
|
}
|
|
594
708
|
};
|
|
595
|
-
exports.normalizeMessageContent = normalizeMessageContent;
|
|
596
709
|
/**
|
|
597
710
|
* Extract the true message content from a message
|
|
598
711
|
* Eg. extracts the inner message from a disappearing message/view once message
|
|
599
712
|
*/
|
|
600
|
-
const extractMessageContent = (content) => {
|
|
601
|
-
var _a, _b, _c, _d, _e, _f;
|
|
713
|
+
export const extractMessageContent = (content) => {
|
|
602
714
|
const extractFromTemplateMessage = (msg) => {
|
|
603
715
|
if (msg.imageMessage) {
|
|
604
716
|
return { imageMessage: msg.imageMessage };
|
|
@@ -614,35 +726,39 @@ const extractMessageContent = (content) => {
|
|
|
614
726
|
}
|
|
615
727
|
else {
|
|
616
728
|
return {
|
|
617
|
-
conversation: 'contentText' in msg
|
|
618
|
-
? msg.contentText
|
|
619
|
-
: ('hydratedContentText' in msg ? msg.hydratedContentText : '')
|
|
729
|
+
conversation: 'contentText' in msg ? msg.contentText : 'hydratedContentText' in msg ? msg.hydratedContentText : ''
|
|
620
730
|
};
|
|
621
731
|
}
|
|
622
732
|
};
|
|
623
|
-
content =
|
|
624
|
-
if (content
|
|
733
|
+
content = normalizeMessageContent(content);
|
|
734
|
+
if (content?.buttonsMessage) {
|
|
625
735
|
return extractFromTemplateMessage(content.buttonsMessage);
|
|
626
736
|
}
|
|
627
|
-
if (
|
|
628
|
-
return extractFromTemplateMessage(
|
|
737
|
+
if (content?.templateMessage?.hydratedFourRowTemplate) {
|
|
738
|
+
return extractFromTemplateMessage(content?.templateMessage?.hydratedFourRowTemplate);
|
|
629
739
|
}
|
|
630
|
-
if (
|
|
631
|
-
return extractFromTemplateMessage(
|
|
740
|
+
if (content?.templateMessage?.hydratedTemplate) {
|
|
741
|
+
return extractFromTemplateMessage(content?.templateMessage?.hydratedTemplate);
|
|
632
742
|
}
|
|
633
|
-
if (
|
|
634
|
-
return extractFromTemplateMessage(
|
|
743
|
+
if (content?.templateMessage?.fourRowTemplate) {
|
|
744
|
+
return extractFromTemplateMessage(content?.templateMessage?.fourRowTemplate);
|
|
635
745
|
}
|
|
636
746
|
return content;
|
|
637
747
|
};
|
|
638
|
-
exports.extractMessageContent = extractMessageContent;
|
|
639
748
|
/**
|
|
640
749
|
* Returns the device predicted by message ID
|
|
641
750
|
*/
|
|
642
|
-
const getDevice = (id) => /^3A.{18}$/.test(id)
|
|
643
|
-
|
|
751
|
+
export const getDevice = (id) => /^3A.{18}$/.test(id)
|
|
752
|
+
? 'ios'
|
|
753
|
+
: /^3E.{20}$/.test(id)
|
|
754
|
+
? 'web'
|
|
755
|
+
: /^(.{21}|.{32})$/.test(id)
|
|
756
|
+
? 'android'
|
|
757
|
+
: /^(3F|.{18}$)/.test(id)
|
|
758
|
+
? 'desktop'
|
|
759
|
+
: 'unknown';
|
|
644
760
|
/** Upserts a receipt in the message */
|
|
645
|
-
const updateMessageWithReceipt = (msg, receipt) => {
|
|
761
|
+
export const updateMessageWithReceipt = (msg, receipt) => {
|
|
646
762
|
msg.userReceipt = msg.userReceipt || [];
|
|
647
763
|
const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
|
|
648
764
|
if (recp) {
|
|
@@ -652,41 +768,36 @@ const updateMessageWithReceipt = (msg, receipt) => {
|
|
|
652
768
|
msg.userReceipt.push(receipt);
|
|
653
769
|
}
|
|
654
770
|
};
|
|
655
|
-
exports.updateMessageWithReceipt = updateMessageWithReceipt;
|
|
656
771
|
/** Update the message with a new reaction */
|
|
657
|
-
const updateMessageWithReaction = (msg, reaction) => {
|
|
658
|
-
const authorID =
|
|
659
|
-
const reactions = (msg.reactions || [])
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
reactions.push(reaction);
|
|
663
|
-
}
|
|
772
|
+
export const updateMessageWithReaction = (msg, reaction) => {
|
|
773
|
+
const authorID = getKeyAuthor(reaction.key);
|
|
774
|
+
const reactions = (msg.reactions || []).filter(r => getKeyAuthor(r.key) !== authorID);
|
|
775
|
+
reaction.text = reaction.text || '';
|
|
776
|
+
reactions.push(reaction);
|
|
664
777
|
msg.reactions = reactions;
|
|
665
778
|
};
|
|
666
|
-
exports.updateMessageWithReaction = updateMessageWithReaction;
|
|
667
779
|
/** Update the message with a new poll update */
|
|
668
|
-
const updateMessageWithPollUpdate = (msg, update) => {
|
|
669
|
-
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
.filter(r => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID);
|
|
673
|
-
if ((_b = (_a = update.vote) === null || _a === void 0 ? void 0 : _a.selectedOptions) === null || _b === void 0 ? void 0 : _b.length) {
|
|
780
|
+
export const updateMessageWithPollUpdate = (msg, update) => {
|
|
781
|
+
const authorID = getKeyAuthor(update.pollUpdateMessageKey);
|
|
782
|
+
const reactions = (msg.pollUpdates || []).filter(r => getKeyAuthor(r.pollUpdateMessageKey) !== authorID);
|
|
783
|
+
if (update.vote?.selectedOptions?.length) {
|
|
674
784
|
reactions.push(update);
|
|
675
785
|
}
|
|
676
786
|
msg.pollUpdates = reactions;
|
|
677
787
|
};
|
|
678
|
-
exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate;
|
|
679
788
|
/**
|
|
680
789
|
* Aggregates all poll updates in a poll.
|
|
681
790
|
* @param msg the poll creation message
|
|
682
791
|
* @param meId your jid
|
|
683
792
|
* @returns A list of options & their voters
|
|
684
793
|
*/
|
|
685
|
-
function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
|
|
686
|
-
|
|
687
|
-
|
|
794
|
+
export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
|
|
795
|
+
const opts = message?.pollCreationMessage?.options ||
|
|
796
|
+
message?.pollCreationMessageV2?.options ||
|
|
797
|
+
message?.pollCreationMessageV3?.options ||
|
|
798
|
+
[];
|
|
688
799
|
const voteHashMap = opts.reduce((acc, opt) => {
|
|
689
|
-
const hash =
|
|
800
|
+
const hash = sha256(Buffer.from(opt.optionName || '')).toString();
|
|
690
801
|
acc[hash] = {
|
|
691
802
|
name: opt.optionName || '',
|
|
692
803
|
voters: []
|
|
@@ -708,14 +819,13 @@ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
|
|
|
708
819
|
};
|
|
709
820
|
data = voteHashMap[hash];
|
|
710
821
|
}
|
|
711
|
-
voteHashMap[hash].voters.push(
|
|
822
|
+
voteHashMap[hash].voters.push(getKeyAuthor(update.pollUpdateMessageKey, meId));
|
|
712
823
|
}
|
|
713
824
|
}
|
|
714
825
|
return Object.values(voteHashMap);
|
|
715
826
|
}
|
|
716
|
-
exports.getAggregateVotesInPollMessage = getAggregateVotesInPollMessage;
|
|
717
827
|
/** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
|
|
718
|
-
const aggregateMessageKeysNotFromMe = (keys) => {
|
|
828
|
+
export const aggregateMessageKeysNotFromMe = (keys) => {
|
|
719
829
|
const keyMap = {};
|
|
720
830
|
for (const { remoteJid, id, participant, fromMe } of keys) {
|
|
721
831
|
if (!fromMe) {
|
|
@@ -732,40 +842,34 @@ const aggregateMessageKeysNotFromMe = (keys) => {
|
|
|
732
842
|
}
|
|
733
843
|
return Object.values(keyMap);
|
|
734
844
|
};
|
|
735
|
-
exports.aggregateMessageKeysNotFromMe = aggregateMessageKeysNotFromMe;
|
|
736
845
|
const REUPLOAD_REQUIRED_STATUS = [410, 404];
|
|
737
846
|
/**
|
|
738
847
|
* Downloads the given message. Throws an error if it's not a media message
|
|
739
848
|
*/
|
|
740
|
-
const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
741
|
-
const result = await downloadMsg()
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
message = await ctx.reuploadRequest(message);
|
|
751
|
-
const result = await downloadMsg();
|
|
752
|
-
return result;
|
|
753
|
-
}
|
|
754
|
-
}
|
|
849
|
+
export const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
850
|
+
const result = await downloadMsg().catch(async (error) => {
|
|
851
|
+
if (ctx &&
|
|
852
|
+
typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
|
|
853
|
+
REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
|
|
854
|
+
ctx.logger.info({ key: message.key }, 'sending reupload media request...');
|
|
855
|
+
// request reupload
|
|
856
|
+
message = await ctx.reuploadRequest(message);
|
|
857
|
+
const result = await downloadMsg();
|
|
858
|
+
return result;
|
|
755
859
|
}
|
|
756
860
|
throw error;
|
|
757
861
|
});
|
|
758
862
|
return result;
|
|
759
863
|
async function downloadMsg() {
|
|
760
|
-
const mContent =
|
|
864
|
+
const mContent = extractMessageContent(message.message);
|
|
761
865
|
if (!mContent) {
|
|
762
|
-
throw new
|
|
866
|
+
throw new Boom('No message present', { statusCode: 400, data: message });
|
|
763
867
|
}
|
|
764
|
-
const contentType =
|
|
765
|
-
let mediaType = contentType
|
|
868
|
+
const contentType = getContentType(mContent);
|
|
869
|
+
let mediaType = contentType?.replace('Message', '');
|
|
766
870
|
const media = mContent[contentType];
|
|
767
871
|
if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
|
|
768
|
-
throw new
|
|
872
|
+
throw new Boom(`"${contentType}" message is not a media message`);
|
|
769
873
|
}
|
|
770
874
|
let download;
|
|
771
875
|
if ('thumbnailDirectPath' in media && !('url' in media)) {
|
|
@@ -778,7 +882,7 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
|
778
882
|
else {
|
|
779
883
|
download = media;
|
|
780
884
|
}
|
|
781
|
-
const stream = await
|
|
885
|
+
const stream = await downloadContentFromMessage(download, mediaType, options);
|
|
782
886
|
if (type === 'buffer') {
|
|
783
887
|
const bufferArray = [];
|
|
784
888
|
for await (const chunk of stream) {
|
|
@@ -789,19 +893,16 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
|
789
893
|
return stream;
|
|
790
894
|
}
|
|
791
895
|
};
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|| (content === null || content === void 0 ? void 0 : content.stickerMessage);
|
|
896
|
+
|
|
897
|
+
export const assertMediaContent = (content) => {
|
|
898
|
+
content = extractMessageContent(content);
|
|
899
|
+
const mediaContent = content?.documentMessage ||
|
|
900
|
+
content?.imageMessage ||
|
|
901
|
+
content?.videoMessage ||
|
|
902
|
+
content?.audioMessage ||
|
|
903
|
+
content?.stickerMessage;
|
|
801
904
|
if (!mediaContent) {
|
|
802
|
-
throw new
|
|
905
|
+
throw new Boom('given message is not a media message', { statusCode: 400, data: content });
|
|
803
906
|
}
|
|
804
907
|
return mediaContent;
|
|
805
908
|
};
|
|
806
|
-
exports.assertMediaContent = assertMediaContent;
|
|
807
|
-
|