Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jajbshjahavahh
GitHub Repository: jajbshjahavahh/Gojo-Satoru
Path: blob/master/node_modules/@adiwajshing/baileys/lib/Socket/messages-recv.js
2593 views
1
"use strict";
2
Object.defineProperty(exports, "__esModule", { value: true });
3
exports.makeMessagesRecvSocket = void 0;
4
const WAProto_1 = require("../../WAProto");
5
const Defaults_1 = require("../Defaults");
6
const Types_1 = require("../Types");
7
const Utils_1 = require("../Utils");
8
const make_mutex_1 = require("../Utils/make-mutex");
9
const WABinary_1 = require("../WABinary");
10
const chats_1 = require("./chats");
11
const groups_1 = require("./groups");
12
const STATUS_MAP = {
13
'played': WAProto_1.proto.WebMessageInfo.WebMessageInfoStatus.PLAYED,
14
'read': WAProto_1.proto.WebMessageInfo.WebMessageInfoStatus.READ,
15
'read-self': WAProto_1.proto.WebMessageInfo.WebMessageInfoStatus.READ
16
};
17
const getStatusFromReceiptType = (type) => {
18
const status = STATUS_MAP[type];
19
if (typeof type === 'undefined') {
20
return WAProto_1.proto.WebMessageInfo.WebMessageInfoStatus.DELIVERY_ACK;
21
}
22
return status;
23
};
24
const makeMessagesRecvSocket = (config) => {
25
const { logger } = config;
26
const sock = chats_1.makeChatsSocket(config);
27
const { ev, authState, ws, assertSessions, assertingPreKeys, sendNode, relayMessage, sendReceipt, resyncMainAppState, } = sock;
28
/** this mutex ensures that the notifications (receipts, messages etc.) are processed in order */
29
const processingMutex = make_mutex_1.makeKeyedMutex();
30
/** this mutex ensures that each retryRequest will wait for the previous one to finish */
31
const retryMutex = make_mutex_1.makeMutex();
32
const msgRetryMap = config.msgRetryCounterMap || {};
33
const historyCache = new Set();
34
const sendMessageAck = async ({ tag, attrs }, extraAttrs) => {
35
const stanza = {
36
tag: 'ack',
37
attrs: {
38
id: attrs.id,
39
to: attrs.from,
40
...extraAttrs,
41
}
42
};
43
if (!!attrs.participant) {
44
stanza.attrs.participant = attrs.participant;
45
}
46
logger.debug({ recv: attrs, sent: stanza.attrs }, `sent "${tag}" ack`);
47
await sendNode(stanza);
48
};
49
const sendRetryRequest = async (node) => {
50
const msgId = node.attrs.id;
51
const retryCount = msgRetryMap[msgId] || 1;
52
if (retryCount >= 5) {
53
logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
54
delete msgRetryMap[msgId];
55
return;
56
}
57
msgRetryMap[msgId] = retryCount + 1;
58
const isGroup = !!node.attrs.participant;
59
const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds;
60
const deviceIdentity = WAProto_1.proto.ADVSignedDeviceIdentity.encode(account).finish();
61
await assertingPreKeys(1, async (preKeys) => {
62
const [keyId] = Object.keys(preKeys);
63
const key = preKeys[+keyId];
64
const decFrom = node.attrs.from ? WABinary_1.jidDecode(node.attrs.from) : undefined;
65
const receipt = {
66
tag: 'receipt',
67
attrs: {
68
id: msgId,
69
type: 'retry',
70
to: isGroup ? node.attrs.from : WABinary_1.jidEncode(decFrom.user, 's.whatsapp.net', decFrom.device, 0)
71
},
72
content: [
73
{
74
tag: 'retry',
75
attrs: {
76
count: retryCount.toString(),
77
id: node.attrs.id,
78
t: node.attrs.t,
79
v: '1'
80
}
81
},
82
{
83
tag: 'registration',
84
attrs: {},
85
content: Utils_1.encodeBigEndian(authState.creds.registrationId)
86
}
87
]
88
};
89
if (node.attrs.recipient) {
90
receipt.attrs.recipient = node.attrs.recipient;
91
}
92
if (node.attrs.participant) {
93
receipt.attrs.participant = node.attrs.participant;
94
}
95
if (retryCount > 1) {
96
const exec = Utils_1.generateSignalPubKey(Buffer.from(Defaults_1.KEY_BUNDLE_TYPE)).slice(0, 1);
97
receipt.content.push({
98
tag: 'keys',
99
attrs: {},
100
content: [
101
{ tag: 'type', attrs: {}, content: exec },
102
{ tag: 'identity', attrs: {}, content: identityKey.public },
103
Utils_1.xmppPreKey(key, +keyId),
104
Utils_1.xmppSignedPreKey(signedPreKey),
105
{ tag: 'device-identity', attrs: {}, content: deviceIdentity }
106
]
107
});
108
}
109
await sendNode(receipt);
110
logger.info({ msgAttrs: node.attrs, retryCount }, 'sent retry receipt');
111
});
112
};
113
const processMessage = async (message, chatUpdate) => {
114
var _a;
115
const protocolMsg = (_a = message.message) === null || _a === void 0 ? void 0 : _a.protocolMessage;
116
if (protocolMsg) {
117
switch (protocolMsg.type) {
118
case WAProto_1.proto.ProtocolMessage.ProtocolMessageType.HISTORY_SYNC_NOTIFICATION:
119
const histNotification = protocolMsg.historySyncNotification;
120
logger.info({ histNotification, id: message.key.id }, 'got history notification');
121
const { chats, contacts, messages, isLatest } = await Utils_1.downloadAndProcessHistorySyncNotification(histNotification, historyCache);
122
const meJid = authState.creds.me.id;
123
await sendNode({
124
tag: 'receipt',
125
attrs: {
126
id: message.key.id,
127
type: 'hist_sync',
128
to: WABinary_1.jidEncode(WABinary_1.jidDecode(meJid).user, 'c.us')
129
}
130
});
131
if (chats.length) {
132
ev.emit('chats.set', { chats, isLatest });
133
}
134
if (messages.length) {
135
ev.emit('messages.set', { messages, isLatest });
136
}
137
if (contacts.length) {
138
ev.emit('contacts.set', { contacts });
139
}
140
break;
141
case WAProto_1.proto.ProtocolMessage.ProtocolMessageType.APP_STATE_SYNC_KEY_SHARE:
142
const keys = protocolMsg.appStateSyncKeyShare.keys;
143
if (keys === null || keys === void 0 ? void 0 : keys.length) {
144
let newAppStateSyncKeyId = '';
145
for (const { keyData, keyId } of keys) {
146
const strKeyId = Buffer.from(keyId.keyId).toString('base64');
147
logger.info({ strKeyId }, 'injecting new app state sync key');
148
await authState.keys.set({ 'app-state-sync-key': { [strKeyId]: keyData } });
149
newAppStateSyncKeyId = strKeyId;
150
}
151
ev.emit('creds.update', { myAppStateKeyId: newAppStateSyncKeyId });
152
resyncMainAppState();
153
}
154
else {
155
[
156
logger.info({ protocolMsg }, 'recv app state sync with 0 keys')
157
];
158
}
159
break;
160
case WAProto_1.proto.ProtocolMessage.ProtocolMessageType.REVOKE:
161
ev.emit('messages.update', [
162
{
163
key: {
164
...message.key,
165
id: protocolMsg.key.id
166
},
167
update: { message: null, messageStubType: Types_1.WAMessageStubType.REVOKE, key: message.key }
168
}
169
]);
170
break;
171
case WAProto_1.proto.ProtocolMessage.ProtocolMessageType.EPHEMERAL_SETTING:
172
chatUpdate.ephemeralSettingTimestamp = Utils_1.toNumber(message.messageTimestamp);
173
chatUpdate.ephemeralExpiration = protocolMsg.ephemeralExpiration || null;
174
break;
175
}
176
}
177
else if (message.messageStubType) {
178
const meJid = authState.creds.me.id;
179
const jid = message.key.remoteJid;
180
//let actor = whatsappID (message.participant)
181
let participants;
182
const emitParticipantsUpdate = (action) => (ev.emit('group-participants.update', { id: jid, participants, action }));
183
const emitGroupUpdate = (update) => {
184
ev.emit('groups.update', [{ id: jid, ...update }]);
185
};
186
switch (message.messageStubType) {
187
case Types_1.WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
188
case Types_1.WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
189
participants = message.messageStubParameters;
190
emitParticipantsUpdate('remove');
191
// mark the chat read only if you left the group
192
if (participants.includes(meJid)) {
193
chatUpdate.readOnly = true;
194
}
195
break;
196
case Types_1.WAMessageStubType.GROUP_PARTICIPANT_ADD:
197
case Types_1.WAMessageStubType.GROUP_PARTICIPANT_INVITE:
198
case Types_1.WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
199
participants = message.messageStubParameters;
200
if (participants.includes(meJid)) {
201
chatUpdate.readOnly = false;
202
}
203
emitParticipantsUpdate('add');
204
break;
205
case Types_1.WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
206
const announceValue = message.messageStubParameters[0];
207
emitGroupUpdate({ announce: announceValue === 'true' || announceValue === 'on' });
208
break;
209
case Types_1.WAMessageStubType.GROUP_CHANGE_RESTRICT:
210
const restrictValue = message.messageStubParameters[0];
211
emitGroupUpdate({ restrict: restrictValue === 'true' || restrictValue === 'on' });
212
break;
213
case Types_1.WAMessageStubType.GROUP_CHANGE_SUBJECT:
214
chatUpdate.name = message.messageStubParameters[0];
215
emitGroupUpdate({ subject: chatUpdate.name });
216
break;
217
}
218
}
219
};
220
const processNotification = (node) => {
221
const result = {};
222
const [child] = WABinary_1.getAllBinaryNodeChildren(node);
223
if (node.attrs.type === 'w:gp2') {
224
switch (child === null || child === void 0 ? void 0 : child.tag) {
225
case 'create':
226
const metadata = groups_1.extractGroupMetadata(child);
227
result.messageStubType = Types_1.WAMessageStubType.GROUP_CREATE;
228
result.messageStubParameters = [metadata.subject];
229
result.key = { participant: metadata.owner };
230
ev.emit('chats.upsert', [{
231
id: metadata.id,
232
name: metadata.subject,
233
conversationTimestamp: metadata.creation,
234
}]);
235
ev.emit('groups.upsert', [metadata]);
236
break;
237
case 'ephemeral':
238
case 'not_ephemeral':
239
result.message = {
240
protocolMessage: {
241
type: WAProto_1.proto.ProtocolMessage.ProtocolMessageType.EPHEMERAL_SETTING,
242
ephemeralExpiration: +(child.attrs.expiration || 0)
243
}
244
};
245
break;
246
case 'promote':
247
case 'demote':
248
case 'remove':
249
case 'add':
250
case 'leave':
251
const stubType = `GROUP_PARTICIPANT_${child.tag.toUpperCase()}`;
252
result.messageStubType = Types_1.WAMessageStubType[stubType];
253
const participants = WABinary_1.getBinaryNodeChildren(child, 'participant').map(p => p.attrs.jid);
254
if (participants.length === 1 &&
255
// if recv. "remove" message and sender removed themselves
256
// mark as left
257
WABinary_1.areJidsSameUser(participants[0], node.attrs.participant) &&
258
child.tag === 'remove') {
259
result.messageStubType = Types_1.WAMessageStubType.GROUP_PARTICIPANT_LEAVE;
260
}
261
result.messageStubParameters = participants;
262
break;
263
case 'subject':
264
result.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_SUBJECT;
265
result.messageStubParameters = [child.attrs.subject];
266
break;
267
case 'announcement':
268
case 'not_announcement':
269
result.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_ANNOUNCE;
270
result.messageStubParameters = [(child.tag === 'announcement') ? 'on' : 'off'];
271
break;
272
case 'locked':
273
case 'unlocked':
274
result.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_RESTRICT;
275
result.messageStubParameters = [(child.tag === 'locked') ? 'on' : 'off'];
276
break;
277
}
278
}
279
else {
280
switch (child.tag) {
281
case 'devices':
282
const devices = WABinary_1.getBinaryNodeChildren(child, 'device');
283
if (WABinary_1.areJidsSameUser(child.attrs.jid, authState.creds.me.id)) {
284
const deviceJids = devices.map(d => d.attrs.jid);
285
logger.info({ deviceJids }, 'got my own devices');
286
}
287
break;
288
}
289
}
290
if (Object.keys(result).length) {
291
return result;
292
}
293
};
294
// recv a message
295
ws.on('CB:message', (stanza) => {
296
const { fullMessage: msg, decryptionTask } = Utils_1.decodeMessageStanza(stanza, authState);
297
processingMutex.mutex(msg.key.remoteJid, async () => {
298
await decryptionTask;
299
// message failed to decrypt
300
if (msg.messageStubType === WAProto_1.proto.WebMessageInfo.WebMessageInfoStubType.CIPHERTEXT) {
301
logger.error({ msgId: msg.key.id, params: msg.messageStubParameters }, 'failure in decrypting message');
302
retryMutex.mutex(async () => await sendRetryRequest(stanza));
303
}
304
else {
305
await sendMessageAck(stanza, { class: 'receipt' });
306
// no type in the receipt => message delivered
307
await sendReceipt(msg.key.remoteJid, msg.key.participant, [msg.key.id], undefined);
308
logger.debug({ msg: msg.key }, 'sent delivery receipt');
309
}
310
msg.key.remoteJid = WABinary_1.jidNormalizedUser(msg.key.remoteJid);
311
ev.emit('messages.upsert', { messages: [msg], type: stanza.attrs.offline ? 'append' : 'notify' });
312
});
313
});
314
ws.on('CB:ack,class:message', async (node) => {
315
await sendNode({
316
tag: 'ack',
317
attrs: {
318
class: 'receipt',
319
id: node.attrs.id,
320
from: node.attrs.from
321
}
322
});
323
logger.debug({ attrs: node.attrs }, 'sending receipt for ack');
324
});
325
ws.on('CB:call', async (node) => {
326
logger.info({ node }, 'recv call');
327
const [child] = WABinary_1.getAllBinaryNodeChildren(node);
328
if (!!(child === null || child === void 0 ? void 0 : child.tag)) {
329
await sendMessageAck(node, { class: 'call', type: child.tag });
330
}
331
});
332
const sendMessagesAgain = async (key, ids) => {
333
const msgs = await Promise.all(ids.map(id => (config.getMessage({ ...key, id }))));
334
const participant = key.participant || key.remoteJid;
335
await assertSessions([participant], true);
336
if (WABinary_1.isJidGroup(key.remoteJid)) {
337
await authState.keys.set({ 'sender-key-memory': { [key.remoteJid]: null } });
338
}
339
logger.debug({ participant }, 'forced new session for retry recp');
340
for (let i = 0; i < msgs.length; i++) {
341
if (msgs[i]) {
342
await relayMessage(key.remoteJid, msgs[i], {
343
messageId: ids[i],
344
participant
345
});
346
}
347
else {
348
logger.debug({ jid: key.remoteJid, id: ids[i] }, 'recv retry request, but message not available');
349
}
350
}
351
};
352
const handleReceipt = async (node) => {
353
var _a;
354
let shouldAck = true;
355
const { attrs, content } = node;
356
const isNodeFromMe = WABinary_1.areJidsSameUser(attrs.participant || attrs.from, (_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id);
357
const remoteJid = !isNodeFromMe || WABinary_1.isJidGroup(attrs.from) ? attrs.from : attrs.recipient;
358
const fromMe = !attrs.recipient;
359
const ids = [attrs.id];
360
if (Array.isArray(content)) {
361
const items = WABinary_1.getBinaryNodeChildren(content[0], 'item');
362
ids.push(...items.map(i => i.attrs.id));
363
}
364
const key = {
365
remoteJid,
366
id: '',
367
fromMe,
368
participant: attrs.participant
369
};
370
await processingMutex.mutex(remoteJid, async () => {
371
const status = getStatusFromReceiptType(attrs.type);
372
if (typeof status !== 'undefined' &&
373
(
374
// basically, we only want to know when a message from us has been delivered to/read by the other person
375
// or another device of ours has read some messages
376
status > WAProto_1.proto.WebMessageInfo.WebMessageInfoStatus.DELIVERY_ACK ||
377
!isNodeFromMe)) {
378
if (WABinary_1.isJidGroup(remoteJid)) {
379
const updateKey = status === WAProto_1.proto.WebMessageInfo.WebMessageInfoStatus.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
380
ev.emit('message-receipt.update', ids.map(id => ({
381
key: { ...key, id },
382
receipt: {
383
userJid: WABinary_1.jidNormalizedUser(attrs.participant),
384
[updateKey]: +attrs.t
385
}
386
})));
387
}
388
else {
389
ev.emit('messages.update', ids.map(id => ({
390
key: { ...key, id },
391
update: { status }
392
})));
393
}
394
}
395
if (attrs.type === 'retry') {
396
// correctly set who is asking for the retry
397
key.participant = key.participant || attrs.from;
398
if (key.fromMe) {
399
try {
400
logger.debug({ attrs }, 'recv retry request');
401
await sendMessagesAgain(key, ids);
402
}
403
catch (error) {
404
logger.error({ key, ids, trace: error.stack }, 'error in sending message again');
405
shouldAck = false;
406
}
407
}
408
else {
409
logger.info({ attrs, key }, 'recv retry for not fromMe message');
410
}
411
}
412
if (shouldAck) {
413
await sendMessageAck(node, { class: 'receipt', type: attrs.type });
414
}
415
});
416
};
417
ws.on('CB:receipt', handleReceipt);
418
ws.on('CB:notification', async (node) => {
419
const remoteJid = node.attrs.from;
420
processingMutex.mutex(remoteJid, () => {
421
const msg = processNotification(node);
422
if (msg) {
423
const fromMe = WABinary_1.areJidsSameUser(node.attrs.participant || node.attrs.from, authState.creds.me.id);
424
msg.key = {
425
remoteJid: node.attrs.from,
426
fromMe,
427
participant: node.attrs.participant,
428
id: node.attrs.id,
429
...(msg.key || {})
430
};
431
msg.messageTimestamp = +node.attrs.t;
432
const fullMsg = WAProto_1.proto.WebMessageInfo.fromObject(msg);
433
ev.emit('messages.upsert', { messages: [fullMsg], type: 'append' });
434
}
435
});
436
await sendMessageAck(node, { class: 'notification', type: node.attrs.type });
437
});
438
ev.on('messages.upsert', async ({ messages, type }) => {
439
var _a;
440
if (type === 'notify' || type === 'append') {
441
const chat = { id: messages[0].key.remoteJid };
442
const contactNameUpdates = {};
443
for (const msg of messages) {
444
if (!!msg.pushName) {
445
const jid = msg.key.fromMe ? WABinary_1.jidNormalizedUser(authState.creds.me.id) : (msg.key.participant || msg.key.remoteJid);
446
contactNameUpdates[jid] = msg.pushName;
447
// update our pushname too
448
if (msg.key.fromMe && ((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.name) !== msg.pushName) {
449
ev.emit('creds.update', { me: { ...authState.creds.me, name: msg.pushName } });
450
}
451
}
452
await processingMutex.mutex('p-' + chat.id, () => processMessage(msg, chat));
453
if (!!msg.message && !msg.message.protocolMessage) {
454
chat.conversationTimestamp = Utils_1.toNumber(msg.messageTimestamp);
455
if (!msg.key.fromMe) {
456
chat.unreadCount = (chat.unreadCount || 0) + 1;
457
}
458
}
459
}
460
if (Object.keys(chat).length > 1) {
461
ev.emit('chats.update', [chat]);
462
}
463
if (Object.keys(contactNameUpdates).length) {
464
ev.emit('contacts.update', Object.keys(contactNameUpdates).map(id => ({ id, notify: contactNameUpdates[id] })));
465
}
466
}
467
});
468
return { ...sock, processMessage, sendMessageAck, sendRetryRequest };
469
};
470
exports.makeMessagesRecvSocket = makeMessagesRecvSocket;
471
472