@periskope/baileys 7.0.0-alpha-5 → 7.0.0-beta-2
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/README.md +0 -6
- package/lib/Defaults/index.d.ts +1 -7
- package/lib/Defaults/index.d.ts.map +1 -1
- package/lib/Defaults/index.js +4 -11
- package/lib/Defaults/index.js.map +1 -1
- package/lib/Signal/Group/group_cipher.d.ts +1 -0
- package/lib/Signal/Group/group_cipher.d.ts.map +1 -1
- package/lib/Signal/Group/group_cipher.js +37 -28
- package/lib/Signal/Group/group_cipher.js.map +1 -1
- package/lib/Signal/Group/keyhelper.d.ts.map +1 -1
- package/lib/Signal/Group/keyhelper.js +1 -0
- package/lib/Signal/Group/keyhelper.js.map +1 -1
- package/lib/Signal/Group/sender-chain-key.d.ts +1 -1
- package/lib/Signal/Group/sender-chain-key.d.ts.map +1 -1
- package/lib/Signal/Group/sender-chain-key.js +3 -9
- package/lib/Signal/Group/sender-chain-key.js.map +1 -1
- package/lib/Signal/Group/sender-key-message.d.ts.map +1 -1
- package/lib/Signal/Group/sender-key-message.js +1 -0
- package/lib/Signal/Group/sender-key-message.js.map +1 -1
- package/lib/Signal/Group/sender-key-state.d.ts +4 -4
- package/lib/Signal/Group/sender-key-state.d.ts.map +1 -1
- package/lib/Signal/Group/sender-key-state.js +19 -47
- package/lib/Signal/Group/sender-key-state.js.map +1 -1
- package/lib/Signal/Group/sender-message-key.d.ts.map +1 -1
- package/lib/Signal/Group/sender-message-key.js +1 -0
- package/lib/Signal/Group/sender-message-key.js.map +1 -1
- package/lib/Signal/libsignal.d.ts +2 -6
- package/lib/Signal/libsignal.d.ts.map +1 -1
- package/lib/Signal/libsignal.js +41 -224
- package/lib/Signal/libsignal.js.map +1 -1
- package/lib/Signal/lid-mapping.d.ts +2 -11
- package/lib/Signal/lid-mapping.d.ts.map +1 -1
- package/lib/Signal/lid-mapping.js +34 -91
- package/lib/Signal/lid-mapping.js.map +1 -1
- package/lib/Socket/business.d.ts +14 -26
- package/lib/Socket/business.d.ts.map +1 -1
- package/lib/Socket/business.js +1 -122
- package/lib/Socket/business.js.map +1 -1
- package/lib/Socket/chats.d.ts +9 -15
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +20 -53
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +11 -25
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/communities.js +0 -44
- package/lib/Socket/communities.js.map +1 -1
- package/lib/Socket/groups.d.ts +9 -14
- package/lib/Socket/groups.d.ts.map +1 -1
- package/lib/Socket/groups.js +10 -12
- package/lib/Socket/groups.js.map +1 -1
- package/lib/Socket/index.d.ts +11 -25
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/messages-recv.d.ts +11 -19
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +230 -396
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +11 -20
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +71 -443
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +12 -16
- package/lib/Socket/newsletter.d.ts.map +1 -1
- package/lib/Socket/newsletter.js +1 -3
- package/lib/Socket/newsletter.js.map +1 -1
- package/lib/Socket/socket.d.ts +3 -10
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +69 -264
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +1 -2
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Types/Chat.d.ts +0 -5
- package/lib/Types/Chat.d.ts.map +1 -1
- package/lib/Types/Chat.js.map +1 -1
- package/lib/Types/Contact.d.ts +4 -4
- package/lib/Types/Contact.d.ts.map +1 -1
- package/lib/Types/Events.d.ts +2 -2
- package/lib/Types/Events.d.ts.map +1 -1
- package/lib/Types/GroupMetadata.d.ts +4 -6
- package/lib/Types/GroupMetadata.d.ts.map +1 -1
- package/lib/Types/Message.d.ts +7 -28
- package/lib/Types/Message.d.ts.map +1 -1
- package/lib/Types/Message.js +1 -5
- package/lib/Types/Message.js.map +1 -1
- package/lib/Types/Signal.d.ts +0 -28
- package/lib/Types/Signal.d.ts.map +1 -1
- package/lib/Types/Socket.d.ts +7 -23
- package/lib/Types/Socket.d.ts.map +1 -1
- package/lib/Utils/auth-utils.d.ts.map +1 -1
- package/lib/Utils/auth-utils.js +79 -363
- package/lib/Utils/auth-utils.js.map +1 -1
- package/lib/Utils/chat-utils.d.ts +2 -2
- package/lib/Utils/chat-utils.d.ts.map +1 -1
- package/lib/Utils/chat-utils.js +2 -19
- package/lib/Utils/chat-utils.js.map +1 -1
- package/lib/Utils/crypto.d.ts +3 -3
- package/lib/Utils/crypto.d.ts.map +1 -1
- package/lib/Utils/crypto.js +12 -16
- package/lib/Utils/crypto.js.map +1 -1
- package/lib/Utils/decode-wa-message.d.ts +2 -13
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +13 -84
- package/lib/Utils/decode-wa-message.js.map +1 -1
- package/lib/Utils/event-buffer.d.ts +1 -0
- package/lib/Utils/event-buffer.d.ts.map +1 -1
- package/lib/Utils/event-buffer.js +4 -48
- package/lib/Utils/event-buffer.js.map +1 -1
- package/lib/Utils/generics.d.ts +0 -1
- package/lib/Utils/generics.d.ts.map +1 -1
- package/lib/Utils/generics.js +8 -24
- package/lib/Utils/generics.js.map +1 -1
- package/lib/Utils/history.d.ts.map +1 -1
- package/lib/Utils/history.js +2 -1
- package/lib/Utils/history.js.map +1 -1
- package/lib/Utils/index.d.ts +0 -1
- package/lib/Utils/index.d.ts.map +1 -1
- package/lib/Utils/index.js +0 -1
- package/lib/Utils/index.js.map +1 -1
- package/lib/Utils/messages-media.d.ts +2 -3
- package/lib/Utils/messages-media.d.ts.map +1 -1
- package/lib/Utils/messages-media.js +1 -4
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +4 -24
- package/lib/Utils/messages.js.map +1 -1
- package/lib/Utils/process-message.d.ts +2 -3
- package/lib/Utils/process-message.d.ts.map +1 -1
- package/lib/Utils/process-message.js +3 -13
- package/lib/Utils/process-message.js.map +1 -1
- package/lib/Utils/signal.d.ts +2 -2
- package/lib/Utils/signal.d.ts.map +1 -1
- package/lib/Utils/signal.js.map +1 -1
- package/lib/Utils/validate-connection.d.ts.map +1 -1
- package/lib/Utils/validate-connection.js +2 -3
- package/lib/Utils/validate-connection.js.map +1 -1
- package/lib/WABinary/jid-utils.d.ts +5 -6
- package/lib/WABinary/jid-utils.d.ts.map +1 -1
- package/lib/WABinary/jid-utils.js +5 -11
- package/lib/WABinary/jid-utils.js.map +1 -1
- package/lib/WAM/encode.d.ts.map +1 -1
- package/lib/WAM/encode.js +1 -0
- package/lib/WAM/encode.js.map +1 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +1 -2
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +1 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +2 -10
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +1 -1
- package/package.json +8 -12
|
@@ -7,13 +7,13 @@ import { DEFAULT_CACHE_TTLS, KEY_BUNDLE_TYPE, MIN_PREKEY_COUNT } from '../Defaul
|
|
|
7
7
|
import { WAMessageStatus, WAMessageStubType } from '../Types/index.js';
|
|
8
8
|
import { aesDecryptCTR, aesEncryptGCM, cleanMessage, Curve, decodeMediaRetryNode, decodeMessageNode, decryptMessageNode, delay, derivePairingCodeKey, encodeBigEndian, encodeSignedDeviceIdentity, getCallStatusFromNode, getHistoryMsg, getNextPreKeys, getStatusFromReceiptType, hkdf, MISSING_KEYS_ERROR_TEXT, NACK_REASONS, NO_MESSAGE_FOUND_ERROR_TEXT, unixTimestampSeconds, xmppPreKey, xmppSignedPreKey } from '../Utils/index.js';
|
|
9
9
|
import { makeMutex } from '../Utils/make-mutex.js';
|
|
10
|
-
import { areJidsSameUser, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString, isJidGroup, isJidStatusBroadcast, isLidUser, jidDecode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
10
|
+
import { areJidsSameUser, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString, isJidGroup, isJidStatusBroadcast, isJidUser, isLidUser, jidDecode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
11
11
|
import { extractGroupMetadata } from './groups.js';
|
|
12
12
|
import { makeMessagesSocket } from './messages-send.js';
|
|
13
13
|
export const makeMessagesRecvSocket = (config) => {
|
|
14
|
-
const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid
|
|
14
|
+
const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid } = config;
|
|
15
15
|
const sock = makeMessagesSocket(config);
|
|
16
|
-
const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage
|
|
16
|
+
const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage } = sock;
|
|
17
17
|
/** this mutex ensures that each retryRequest will wait for the previous one to finish */
|
|
18
18
|
const retryMutex = makeMutex();
|
|
19
19
|
const msgRetryCache = config.msgRetryCounterCache ||
|
|
@@ -32,187 +32,6 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
32
32
|
useClones: false
|
|
33
33
|
});
|
|
34
34
|
let sendActiveReceipts = false;
|
|
35
|
-
const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
|
|
36
|
-
if (!authState.creds.me?.id) {
|
|
37
|
-
throw new Boom('Not authenticated');
|
|
38
|
-
}
|
|
39
|
-
const pdoMessage = {
|
|
40
|
-
historySyncOnDemandRequest: {
|
|
41
|
-
chatJid: oldestMsgKey.remoteJid,
|
|
42
|
-
oldestMsgFromMe: oldestMsgKey.fromMe,
|
|
43
|
-
oldestMsgId: oldestMsgKey.id,
|
|
44
|
-
oldestMsgTimestampMs: oldestMsgTimestamp,
|
|
45
|
-
onDemandMsgCount: count
|
|
46
|
-
},
|
|
47
|
-
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
|
|
48
|
-
};
|
|
49
|
-
return sendPeerDataOperationMessage(pdoMessage);
|
|
50
|
-
};
|
|
51
|
-
const requestPlaceholderResend = async (messageKey) => {
|
|
52
|
-
if (!authState.creds.me?.id) {
|
|
53
|
-
throw new Boom('Not authenticated');
|
|
54
|
-
}
|
|
55
|
-
if (placeholderResendCache.get(messageKey?.id)) {
|
|
56
|
-
logger.debug({ messageKey }, 'already requested resend');
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
placeholderResendCache.set(messageKey?.id, true);
|
|
61
|
-
}
|
|
62
|
-
await delay(5000);
|
|
63
|
-
if (!placeholderResendCache.get(messageKey?.id)) {
|
|
64
|
-
logger.debug({ messageKey }, 'message received while resend requested');
|
|
65
|
-
return 'RESOLVED';
|
|
66
|
-
}
|
|
67
|
-
const pdoMessage = {
|
|
68
|
-
placeholderMessageResendRequest: [
|
|
69
|
-
{
|
|
70
|
-
messageKey
|
|
71
|
-
}
|
|
72
|
-
],
|
|
73
|
-
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
|
|
74
|
-
};
|
|
75
|
-
setTimeout(() => {
|
|
76
|
-
if (placeholderResendCache.get(messageKey?.id)) {
|
|
77
|
-
logger.debug({ messageKey }, 'PDO message without response after 15 seconds. Phone possibly offline');
|
|
78
|
-
placeholderResendCache.del(messageKey?.id);
|
|
79
|
-
}
|
|
80
|
-
}, 15000);
|
|
81
|
-
return sendPeerDataOperationMessage(pdoMessage);
|
|
82
|
-
};
|
|
83
|
-
// Handles mex newsletter notifications
|
|
84
|
-
const handleMexNewsletterNotification = async (node) => {
|
|
85
|
-
const mexNode = getBinaryNodeChild(node, 'mex');
|
|
86
|
-
if (!mexNode?.content) {
|
|
87
|
-
logger.warn({ node }, 'Invalid mex newsletter notification');
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
let data;
|
|
91
|
-
try {
|
|
92
|
-
data = JSON.parse(mexNode.content.toString());
|
|
93
|
-
}
|
|
94
|
-
catch (error) {
|
|
95
|
-
logger.error({ err: error, node }, 'Failed to parse mex newsletter notification');
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
const operation = data?.operation;
|
|
99
|
-
const updates = data?.updates;
|
|
100
|
-
if (!updates || !operation) {
|
|
101
|
-
logger.warn({ data }, 'Invalid mex newsletter notification content');
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
logger.info({ operation, updates }, 'got mex newsletter notification');
|
|
105
|
-
switch (operation) {
|
|
106
|
-
case 'NotificationNewsletterUpdate':
|
|
107
|
-
for (const update of updates) {
|
|
108
|
-
if (update.jid && update.settings && Object.keys(update.settings).length > 0) {
|
|
109
|
-
ev.emit('newsletter-settings.update', {
|
|
110
|
-
id: update.jid,
|
|
111
|
-
update: update.settings
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
break;
|
|
116
|
-
case 'NotificationNewsletterAdminPromote':
|
|
117
|
-
for (const update of updates) {
|
|
118
|
-
if (update.jid && update.user) {
|
|
119
|
-
ev.emit('newsletter-participants.update', {
|
|
120
|
-
id: update.jid,
|
|
121
|
-
author: node.attrs.from,
|
|
122
|
-
user: update.user,
|
|
123
|
-
new_role: 'ADMIN',
|
|
124
|
-
action: 'promote'
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
break;
|
|
129
|
-
default:
|
|
130
|
-
logger.info({ operation, data }, 'Unhandled mex newsletter notification');
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
// Handles newsletter notifications
|
|
135
|
-
const handleNewsletterNotification = async (node) => {
|
|
136
|
-
const from = node.attrs.from;
|
|
137
|
-
const child = getAllBinaryNodeChildren(node)[0];
|
|
138
|
-
const author = node.attrs.participant;
|
|
139
|
-
logger.info({ from, child }, 'got newsletter notification');
|
|
140
|
-
switch (child.tag) {
|
|
141
|
-
case 'reaction':
|
|
142
|
-
const reactionUpdate = {
|
|
143
|
-
id: from,
|
|
144
|
-
server_id: child.attrs.message_id,
|
|
145
|
-
reaction: {
|
|
146
|
-
code: getBinaryNodeChildString(child, 'reaction'),
|
|
147
|
-
count: 1
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
ev.emit('newsletter.reaction', reactionUpdate);
|
|
151
|
-
break;
|
|
152
|
-
case 'view':
|
|
153
|
-
const viewUpdate = {
|
|
154
|
-
id: from,
|
|
155
|
-
server_id: child.attrs.message_id,
|
|
156
|
-
count: parseInt(child.content?.toString() || '0', 10)
|
|
157
|
-
};
|
|
158
|
-
ev.emit('newsletter.view', viewUpdate);
|
|
159
|
-
break;
|
|
160
|
-
case 'participant':
|
|
161
|
-
const participantUpdate = {
|
|
162
|
-
id: from,
|
|
163
|
-
author,
|
|
164
|
-
user: child.attrs.jid,
|
|
165
|
-
action: child.attrs.action,
|
|
166
|
-
new_role: child.attrs.role
|
|
167
|
-
};
|
|
168
|
-
ev.emit('newsletter-participants.update', participantUpdate);
|
|
169
|
-
break;
|
|
170
|
-
case 'update':
|
|
171
|
-
const settingsNode = getBinaryNodeChild(child, 'settings');
|
|
172
|
-
if (settingsNode) {
|
|
173
|
-
const update = {};
|
|
174
|
-
const nameNode = getBinaryNodeChild(settingsNode, 'name');
|
|
175
|
-
if (nameNode?.content)
|
|
176
|
-
update.name = nameNode.content.toString();
|
|
177
|
-
const descriptionNode = getBinaryNodeChild(settingsNode, 'description');
|
|
178
|
-
if (descriptionNode?.content)
|
|
179
|
-
update.description = descriptionNode.content.toString();
|
|
180
|
-
ev.emit('newsletter-settings.update', {
|
|
181
|
-
id: from,
|
|
182
|
-
update
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
break;
|
|
186
|
-
case 'message':
|
|
187
|
-
const plaintextNode = getBinaryNodeChild(child, 'plaintext');
|
|
188
|
-
if (plaintextNode?.content) {
|
|
189
|
-
try {
|
|
190
|
-
const contentBuf = typeof plaintextNode.content === 'string'
|
|
191
|
-
? Buffer.from(plaintextNode.content, 'binary')
|
|
192
|
-
: Buffer.from(plaintextNode.content);
|
|
193
|
-
const messageProto = proto.Message.decode(contentBuf);
|
|
194
|
-
const fullMessage = proto.WebMessageInfo.create({
|
|
195
|
-
key: {
|
|
196
|
-
remoteJid: from,
|
|
197
|
-
id: child.attrs.message_id || child.attrs.server_id,
|
|
198
|
-
fromMe: false
|
|
199
|
-
},
|
|
200
|
-
message: messageProto,
|
|
201
|
-
messageTimestamp: +child.attrs.t
|
|
202
|
-
});
|
|
203
|
-
await upsertMessage(fullMessage, 'append');
|
|
204
|
-
logger.info('Processed plaintext newsletter message');
|
|
205
|
-
}
|
|
206
|
-
catch (error) {
|
|
207
|
-
logger.error({ error }, 'Failed to decode plaintext newsletter message');
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
break;
|
|
211
|
-
default:
|
|
212
|
-
logger.warn({ node }, 'Unknown newsletter notification');
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
35
|
const sendMessageAck = async ({ tag, attrs, content }, errorCode) => {
|
|
217
36
|
const stanza = {
|
|
218
37
|
tag: 'ack',
|
|
@@ -288,76 +107,20 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
288
107
|
const { fullMessage } = decodeMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '');
|
|
289
108
|
const { key: msgKey } = fullMessage;
|
|
290
109
|
const msgId = msgKey.id;
|
|
291
|
-
if (messageRetryManager) {
|
|
292
|
-
// Check if we've exceeded max retries using the new system
|
|
293
|
-
if (messageRetryManager.hasExceededMaxRetries(msgId)) {
|
|
294
|
-
logger.debug({ msgId }, 'reached retry limit with new retry manager, clearing');
|
|
295
|
-
messageRetryManager.markRetryFailed(msgId);
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
// Increment retry count using new system
|
|
299
|
-
const retryCount = messageRetryManager.incrementRetryCount(msgId);
|
|
300
|
-
// Use the new retry count for the rest of the logic
|
|
301
|
-
const key = `${msgId}:${msgKey?.participant}`;
|
|
302
|
-
msgRetryCache.set(key, retryCount);
|
|
303
|
-
}
|
|
304
|
-
else {
|
|
305
|
-
// Fallback to old system
|
|
306
|
-
const key = `${msgId}:${msgKey?.participant}`;
|
|
307
|
-
let retryCount = (await msgRetryCache.get(key)) || 0;
|
|
308
|
-
if (retryCount >= maxMsgRetryCount) {
|
|
309
|
-
logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
|
|
310
|
-
msgRetryCache.del(key);
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
retryCount += 1;
|
|
314
|
-
await msgRetryCache.set(key, retryCount);
|
|
315
|
-
}
|
|
316
110
|
const key = `${msgId}:${msgKey?.participant}`;
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
let recreateReason = '';
|
|
323
|
-
if (enableAutoSessionRecreation && messageRetryManager) {
|
|
324
|
-
try {
|
|
325
|
-
// Check if we have a session with this JID
|
|
326
|
-
const sessionId = signalRepository.jidToSignalProtocolAddress(fromJid);
|
|
327
|
-
const hasSession = await signalRepository.validateSession(fromJid);
|
|
328
|
-
const result = messageRetryManager.shouldRecreateSession(fromJid, retryCount, hasSession.exists);
|
|
329
|
-
shouldRecreateSession = result.recreate;
|
|
330
|
-
recreateReason = result.reason;
|
|
331
|
-
if (shouldRecreateSession) {
|
|
332
|
-
logger.info({ fromJid, retryCount, reason: recreateReason }, 'recreating session for retry');
|
|
333
|
-
// Delete existing session to force recreation
|
|
334
|
-
await authState.keys.set({ session: { [sessionId]: null } });
|
|
335
|
-
forceIncludeKeys = true;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
catch (error) {
|
|
339
|
-
logger.warn({ error, fromJid }, 'failed to check session recreation');
|
|
340
|
-
}
|
|
111
|
+
let retryCount = msgRetryCache.get(key) || 0;
|
|
112
|
+
if (retryCount >= maxMsgRetryCount) {
|
|
113
|
+
logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
|
|
114
|
+
msgRetryCache.del(key);
|
|
115
|
+
return;
|
|
341
116
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId} (scheduled)`);
|
|
350
|
-
}
|
|
351
|
-
catch (error) {
|
|
352
|
-
logger.warn({ error, msgId }, 'failed to send scheduled phone request');
|
|
353
|
-
}
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
else {
|
|
357
|
-
// Fallback to immediate request
|
|
358
|
-
const msgId = await requestPlaceholderResend(msgKey);
|
|
359
|
-
logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId}`);
|
|
360
|
-
}
|
|
117
|
+
retryCount += 1;
|
|
118
|
+
msgRetryCache.set(key, retryCount);
|
|
119
|
+
const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds;
|
|
120
|
+
if (retryCount === 1) {
|
|
121
|
+
//request a resend via phone
|
|
122
|
+
const msgId = await requestPlaceholderResend(msgKey);
|
|
123
|
+
logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId}`);
|
|
361
124
|
}
|
|
362
125
|
const deviceIdentity = encodeSignedDeviceIdentity(account, true);
|
|
363
126
|
await authState.keys.transaction(async () => {
|
|
@@ -391,7 +154,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
391
154
|
if (node.attrs.participant) {
|
|
392
155
|
receipt.attrs.participant = node.attrs.participant;
|
|
393
156
|
}
|
|
394
|
-
if (retryCount > 1 || forceIncludeKeys
|
|
157
|
+
if (retryCount > 1 || forceIncludeKeys) {
|
|
395
158
|
const { update, preKeys } = await getNextPreKeys(authState, 1);
|
|
396
159
|
const [keyId] = Object.keys(preKeys);
|
|
397
160
|
const key = preKeys[+keyId];
|
|
@@ -411,7 +174,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
411
174
|
}
|
|
412
175
|
await sendNode(receipt);
|
|
413
176
|
logger.info({ msgAttrs: node.attrs, retryCount }, 'sent retry receipt');
|
|
414
|
-
}
|
|
177
|
+
});
|
|
415
178
|
};
|
|
416
179
|
const handleEncryptNotification = async (node) => {
|
|
417
180
|
const from = node.attrs.from;
|
|
@@ -438,7 +201,6 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
438
201
|
};
|
|
439
202
|
const handleGroupNotification = (participant, child, msg) => {
|
|
440
203
|
const participantJid = getBinaryNodeChild(child, 'participant')?.attrs?.jid || participant;
|
|
441
|
-
// TODO: Add participant LID
|
|
442
204
|
switch (child?.tag) {
|
|
443
205
|
case 'create':
|
|
444
206
|
const metadata = extractGroupMetadata(child);
|
|
@@ -575,12 +337,10 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
575
337
|
break;
|
|
576
338
|
case 'devices':
|
|
577
339
|
const devices = getBinaryNodeChildren(child, 'device');
|
|
578
|
-
if (areJidsSameUser(child.attrs.jid, authState.creds.me.id)
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
logger.info({ deviceData }, 'my own devices changed');
|
|
340
|
+
if (areJidsSameUser(child.attrs.jid, authState.creds.me.id)) {
|
|
341
|
+
const deviceJids = devices.map(d => d.attrs.jid);
|
|
342
|
+
logger.info({ deviceJids }, 'got my own devices');
|
|
582
343
|
}
|
|
583
|
-
//TODO: drop a new event, add hashes
|
|
584
344
|
break;
|
|
585
345
|
case 'server_sync':
|
|
586
346
|
const update = getBinaryNodeChild(node, 'collection');
|
|
@@ -715,79 +475,32 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
715
475
|
}
|
|
716
476
|
return data instanceof Buffer ? data : Buffer.from(data);
|
|
717
477
|
}
|
|
718
|
-
const willSendMessageAgain =
|
|
478
|
+
const willSendMessageAgain = (id, participant) => {
|
|
719
479
|
const key = `${id}:${participant}`;
|
|
720
|
-
const retryCount =
|
|
480
|
+
const retryCount = msgRetryCache.get(key) || 0;
|
|
721
481
|
return retryCount < maxMsgRetryCount;
|
|
722
482
|
};
|
|
723
|
-
const updateSendMessageAgainCount =
|
|
483
|
+
const updateSendMessageAgainCount = (id, participant) => {
|
|
724
484
|
const key = `${id}:${participant}`;
|
|
725
|
-
const newValue = (
|
|
726
|
-
|
|
485
|
+
const newValue = (msgRetryCache.get(key) || 0) + 1;
|
|
486
|
+
msgRetryCache.set(key, newValue);
|
|
727
487
|
};
|
|
728
488
|
const sendMessagesAgain = async (key, ids, retryNode) => {
|
|
489
|
+
// todo: implement a cache to store the last 256 sent messages (copy whatsmeow)
|
|
490
|
+
const msgs = await Promise.all(ids.map(id => getMessage({ ...key, id })));
|
|
729
491
|
const remoteJid = key.remoteJid;
|
|
730
492
|
const participant = key.participant || remoteJid;
|
|
731
|
-
const retryCount = +retryNode.attrs.count || 1;
|
|
732
|
-
// Try to get messages from cache first, then fallback to getMessage
|
|
733
|
-
const msgs = [];
|
|
734
|
-
for (const id of ids) {
|
|
735
|
-
let msg;
|
|
736
|
-
// Try to get from retry cache first if enabled
|
|
737
|
-
if (messageRetryManager) {
|
|
738
|
-
const cachedMsg = messageRetryManager.getRecentMessage(remoteJid, id);
|
|
739
|
-
if (cachedMsg) {
|
|
740
|
-
msg = cachedMsg.message;
|
|
741
|
-
logger.debug({ jid: remoteJid, id }, 'found message in retry cache');
|
|
742
|
-
// Mark retry as successful since we found the message
|
|
743
|
-
messageRetryManager.markRetrySuccess(id);
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
// Fallback to getMessage if not found in cache
|
|
747
|
-
if (!msg) {
|
|
748
|
-
msg = await getMessage({ ...key, id });
|
|
749
|
-
if (msg) {
|
|
750
|
-
logger.debug({ jid: remoteJid, id }, 'found message via getMessage');
|
|
751
|
-
// Also mark as successful if found via getMessage
|
|
752
|
-
if (messageRetryManager) {
|
|
753
|
-
messageRetryManager.markRetrySuccess(id);
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
msgs.push(msg);
|
|
758
|
-
}
|
|
759
493
|
// if it's the primary jid sending the request
|
|
760
494
|
// just re-send the message to everyone
|
|
761
495
|
// prevents the first message decryption failure
|
|
762
496
|
const sendToAll = !jidDecode(participant)?.device;
|
|
763
|
-
|
|
764
|
-
let shouldRecreateSession = false;
|
|
765
|
-
let recreateReason = '';
|
|
766
|
-
if (enableAutoSessionRecreation && messageRetryManager) {
|
|
767
|
-
try {
|
|
768
|
-
const sessionId = signalRepository.jidToSignalProtocolAddress(participant);
|
|
769
|
-
const hasSession = await signalRepository.validateSession(participant);
|
|
770
|
-
const result = messageRetryManager.shouldRecreateSession(participant, retryCount, hasSession.exists);
|
|
771
|
-
shouldRecreateSession = result.recreate;
|
|
772
|
-
recreateReason = result.reason;
|
|
773
|
-
if (shouldRecreateSession) {
|
|
774
|
-
logger.info({ participant, retryCount, reason: recreateReason }, 'recreating session for outgoing retry');
|
|
775
|
-
await authState.keys.set({ session: { [sessionId]: null } });
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
catch (error) {
|
|
779
|
-
logger.warn({ error, participant }, 'failed to check session recreation for outgoing retry');
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
await assertSessions([participant], shouldRecreateSession);
|
|
497
|
+
await assertSessions([participant], true);
|
|
783
498
|
if (isJidGroup(remoteJid)) {
|
|
784
499
|
await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } });
|
|
785
500
|
}
|
|
786
|
-
logger.debug({ participant, sendToAll
|
|
501
|
+
logger.debug({ participant, sendToAll }, 'forced new session for retry recp');
|
|
787
502
|
for (const [i, msg] of msgs.entries()) {
|
|
788
|
-
if (
|
|
789
|
-
continue;
|
|
790
|
-
if (msg && (await willSendMessageAgain(ids[i], participant))) {
|
|
503
|
+
if (msg) {
|
|
791
504
|
updateSendMessageAgainCount(ids[i], participant);
|
|
792
505
|
const msgRelayOpts = { messageId: ids[i] };
|
|
793
506
|
if (sendToAll) {
|
|
@@ -835,7 +548,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
835
548
|
if (typeof status !== 'undefined' &&
|
|
836
549
|
// basically, we only want to know when a message from us has been delivered to/read by the other person
|
|
837
550
|
// or another device of ours has read some messages
|
|
838
|
-
status >= proto.WebMessageInfo.Status.SERVER_ACK) {
|
|
551
|
+
(status >= proto.WebMessageInfo.Status.SERVER_ACK)) {
|
|
839
552
|
if (isJidGroup(remoteJid) || isJidStatusBroadcast(remoteJid)) {
|
|
840
553
|
const updateKey = status === proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
|
|
841
554
|
if (attrs.participant) {
|
|
@@ -877,16 +590,15 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
877
590
|
// correctly set who is asking for the retry
|
|
878
591
|
key.participant = key.participant || attrs.from;
|
|
879
592
|
const retryNode = getBinaryNodeChild(node, 'retry');
|
|
880
|
-
if (
|
|
593
|
+
if (willSendMessageAgain(ids[0], key.participant)) {
|
|
881
594
|
if (key.fromMe) {
|
|
882
595
|
try {
|
|
883
|
-
updateSendMessageAgainCount(ids[0], key.participant);
|
|
884
596
|
logger.debug({ attrs, key }, 'recv retry request');
|
|
885
597
|
await sendMessagesAgain(key, ids, retryNode);
|
|
886
598
|
ev.emit('messages.retry', { key, ids, retryNode });
|
|
887
599
|
}
|
|
888
600
|
catch (error) {
|
|
889
|
-
logger.error({ key, ids, trace: error
|
|
601
|
+
logger.error({ key, ids, trace: error.stack }, 'error in sending message again');
|
|
890
602
|
}
|
|
891
603
|
}
|
|
892
604
|
else {
|
|
@@ -946,22 +658,22 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
946
658
|
// TODO: temporary fix for crashes and issues resulting of failed msmsg decryption
|
|
947
659
|
if (encNode && encNode.attrs.type === 'msmsg') {
|
|
948
660
|
logger.debug({ key: node.attrs.key }, 'ignored msmsg');
|
|
949
|
-
await sendMessageAck(node
|
|
661
|
+
await sendMessageAck(node);
|
|
950
662
|
return;
|
|
951
663
|
}
|
|
952
664
|
let response;
|
|
953
665
|
if (getBinaryNodeChild(node, 'unavailable') && !encNode) {
|
|
954
666
|
await sendMessageAck(node);
|
|
955
667
|
const { key } = decodeMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '').fullMessage;
|
|
956
|
-
response = await requestPlaceholderResend(key);
|
|
668
|
+
response = await requestPlaceholderResend(key);
|
|
957
669
|
if (response === 'RESOLVED') {
|
|
958
670
|
return;
|
|
959
671
|
}
|
|
960
672
|
logger.debug('received unavailable message, acked and requested resend from phone');
|
|
961
673
|
}
|
|
962
674
|
else {
|
|
963
|
-
if (
|
|
964
|
-
|
|
675
|
+
if (placeholderResendCache.get(node.attrs.id)) {
|
|
676
|
+
placeholderResendCache.del(node.attrs.id);
|
|
965
677
|
}
|
|
966
678
|
}
|
|
967
679
|
const { fullMessage: msg, category, author, decrypt } = decryptMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
|
|
@@ -970,35 +682,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
970
682
|
}
|
|
971
683
|
if (msg.message?.protocolMessage?.type === proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER &&
|
|
972
684
|
node.attrs.sender_pn) {
|
|
973
|
-
|
|
974
|
-
ev.emit('lid-mapping.update', { lid, pn });
|
|
975
|
-
await signalRepository.lidMapping.storeLIDPNMappings([{ lid, pn }]);
|
|
976
|
-
}
|
|
977
|
-
const alt = msg.key.participantAlt || msg.key.remoteJidAlt;
|
|
978
|
-
// store new mappings we didn't have before
|
|
979
|
-
if (!!alt) {
|
|
980
|
-
const altServer = jidDecode(alt)?.server;
|
|
981
|
-
if (altServer === 'lid') {
|
|
982
|
-
if (typeof (await signalRepository.lidMapping.getPNForLID(alt)) === 'string') {
|
|
983
|
-
await signalRepository.lidMapping.storeLIDPNMappings([
|
|
984
|
-
{ lid: alt, pn: msg.key.participant || msg.key.remoteJid }
|
|
985
|
-
]);
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
else {
|
|
989
|
-
if (typeof (await signalRepository.lidMapping.getLIDForPN(alt)) === 'string') {
|
|
990
|
-
await signalRepository.lidMapping.storeLIDPNMappings([
|
|
991
|
-
{ lid: msg.key.participant || msg.key.remoteJid, pn: alt }
|
|
992
|
-
]);
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
if (msg.key?.remoteJid && msg.key?.id && messageRetryManager) {
|
|
997
|
-
messageRetryManager.addRecentMessage(msg.key.remoteJid, msg.key.id, msg.message);
|
|
998
|
-
logger.debug({
|
|
999
|
-
jid: msg.key.remoteJid,
|
|
1000
|
-
id: msg.key.id
|
|
1001
|
-
}, 'Added message to recent cache for retry receipts');
|
|
685
|
+
ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
|
|
1002
686
|
}
|
|
1003
687
|
try {
|
|
1004
688
|
await Promise.all([
|
|
@@ -1009,49 +693,19 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1009
693
|
if (msg?.messageStubParameters?.[0] === MISSING_KEYS_ERROR_TEXT) {
|
|
1010
694
|
return sendMessageAck(node, NACK_REASONS.ParsingError);
|
|
1011
695
|
}
|
|
1012
|
-
const errorMessage = msg?.messageStubParameters?.[0] || '';
|
|
1013
|
-
const isPreKeyError = errorMessage.includes('PreKey');
|
|
1014
|
-
logger.debug(`[handleMessage] Attempting retry request for failed decryption`);
|
|
1015
|
-
// Handle both pre-key and normal retries in single mutex
|
|
1016
696
|
retryMutex.mutex(async () => {
|
|
1017
|
-
|
|
1018
|
-
if (!ws.isOpen) {
|
|
1019
|
-
logger.debug({ node }, 'Connection closed, skipping retry');
|
|
1020
|
-
return;
|
|
1021
|
-
}
|
|
697
|
+
if (ws.isOpen) {
|
|
1022
698
|
if (getBinaryNodeChild(node, 'unavailable')) {
|
|
1023
|
-
logger.debug('Message unavailable, skipping retry');
|
|
1024
699
|
return;
|
|
1025
700
|
}
|
|
1026
|
-
// Handle pre-key errors with upload and delay
|
|
1027
|
-
if (isPreKeyError) {
|
|
1028
|
-
logger.info({ error: errorMessage }, 'PreKey error detected, uploading and retrying');
|
|
1029
|
-
try {
|
|
1030
|
-
logger.debug('Uploading pre-keys for error recovery');
|
|
1031
|
-
await uploadPreKeys(5);
|
|
1032
|
-
logger.debug('Waiting for server to process new pre-keys');
|
|
1033
|
-
await delay(1000);
|
|
1034
|
-
}
|
|
1035
|
-
catch (uploadErr) {
|
|
1036
|
-
logger.error({ uploadErr }, 'Pre-key upload failed, proceeding with retry anyway');
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
701
|
const encNode = getBinaryNodeChild(node, 'enc');
|
|
1040
702
|
await sendRetryRequest(node, !encNode);
|
|
1041
703
|
if (retryRequestDelayMs) {
|
|
1042
704
|
await delay(retryRequestDelayMs);
|
|
1043
705
|
}
|
|
1044
706
|
}
|
|
1045
|
-
|
|
1046
|
-
logger.
|
|
1047
|
-
// Still attempt retry even if pre-key upload failed
|
|
1048
|
-
try {
|
|
1049
|
-
const encNode = getBinaryNodeChild(node, 'enc');
|
|
1050
|
-
await sendRetryRequest(node, !encNode);
|
|
1051
|
-
}
|
|
1052
|
-
catch (retryErr) {
|
|
1053
|
-
logger.error({ retryErr }, 'Failed to send retry after error handling');
|
|
1054
|
-
}
|
|
707
|
+
else {
|
|
708
|
+
logger.debug({ node }, 'connection closed, ignoring retry req');
|
|
1055
709
|
}
|
|
1056
710
|
});
|
|
1057
711
|
}
|
|
@@ -1067,8 +721,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1067
721
|
// message was sent by us from a different device
|
|
1068
722
|
type = 'sender';
|
|
1069
723
|
// need to specially handle this case
|
|
1070
|
-
if (
|
|
1071
|
-
participant = author;
|
|
724
|
+
if (isJidUser(msg.key.remoteJid)) {
|
|
725
|
+
participant = author;
|
|
1072
726
|
}
|
|
1073
727
|
}
|
|
1074
728
|
else if (!sendActiveReceipts) {
|
|
@@ -1092,6 +746,54 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1092
746
|
logger.error({ error, node }, 'error in handling message');
|
|
1093
747
|
}
|
|
1094
748
|
};
|
|
749
|
+
const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
|
|
750
|
+
if (!authState.creds.me?.id) {
|
|
751
|
+
throw new Boom('Not authenticated');
|
|
752
|
+
}
|
|
753
|
+
const pdoMessage = {
|
|
754
|
+
historySyncOnDemandRequest: {
|
|
755
|
+
chatJid: oldestMsgKey.remoteJid,
|
|
756
|
+
oldestMsgFromMe: oldestMsgKey.fromMe,
|
|
757
|
+
oldestMsgId: oldestMsgKey.id,
|
|
758
|
+
oldestMsgTimestampMs: oldestMsgTimestamp,
|
|
759
|
+
onDemandMsgCount: count
|
|
760
|
+
},
|
|
761
|
+
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
|
|
762
|
+
};
|
|
763
|
+
return sendPeerDataOperationMessage(pdoMessage);
|
|
764
|
+
};
|
|
765
|
+
const requestPlaceholderResend = async (messageKey) => {
|
|
766
|
+
if (!authState.creds.me?.id) {
|
|
767
|
+
throw new Boom('Not authenticated');
|
|
768
|
+
}
|
|
769
|
+
if (placeholderResendCache.get(messageKey?.id)) {
|
|
770
|
+
logger.debug({ messageKey }, 'already requested resend');
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
placeholderResendCache.set(messageKey?.id, true);
|
|
775
|
+
}
|
|
776
|
+
await delay(5000);
|
|
777
|
+
if (!placeholderResendCache.get(messageKey?.id)) {
|
|
778
|
+
logger.debug({ messageKey }, 'message received while resend requested');
|
|
779
|
+
return 'RESOLVED';
|
|
780
|
+
}
|
|
781
|
+
const pdoMessage = {
|
|
782
|
+
placeholderMessageResendRequest: [
|
|
783
|
+
{
|
|
784
|
+
messageKey
|
|
785
|
+
}
|
|
786
|
+
],
|
|
787
|
+
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
|
|
788
|
+
};
|
|
789
|
+
setTimeout(() => {
|
|
790
|
+
if (placeholderResendCache.get(messageKey?.id)) {
|
|
791
|
+
logger.debug({ messageKey }, 'PDO message without response after 15 seconds. Phone possibly offline');
|
|
792
|
+
placeholderResendCache.del(messageKey?.id);
|
|
793
|
+
}
|
|
794
|
+
}, 15000);
|
|
795
|
+
return sendPeerDataOperationMessage(pdoMessage);
|
|
796
|
+
};
|
|
1095
797
|
const handleCall = async (node) => {
|
|
1096
798
|
let status;
|
|
1097
799
|
const { attrs } = node;
|
|
@@ -1103,7 +805,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1103
805
|
const from = infoChild.attrs.from || infoChild.attrs['call-creator'];
|
|
1104
806
|
status = getCallStatusFromNode(infoChild);
|
|
1105
807
|
if (isLidUser(from) && infoChild.tag === 'relaylatency') {
|
|
1106
|
-
const verify =
|
|
808
|
+
const verify = callOfferCache.get(callId);
|
|
1107
809
|
if (!verify) {
|
|
1108
810
|
status = 'offer';
|
|
1109
811
|
const callLid = {
|
|
@@ -1114,7 +816,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1114
816
|
offline: !!attrs.offline,
|
|
1115
817
|
status
|
|
1116
818
|
};
|
|
1117
|
-
|
|
819
|
+
callOfferCache.set(callId, callLid);
|
|
1118
820
|
}
|
|
1119
821
|
}
|
|
1120
822
|
const call = {
|
|
@@ -1129,9 +831,9 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1129
831
|
call.isVideo = !!getBinaryNodeChild(infoChild, 'video');
|
|
1130
832
|
call.isGroup = infoChild.attrs.type === 'group' || !!infoChild.attrs['group-jid'];
|
|
1131
833
|
call.groupJid = infoChild.attrs['group-jid'];
|
|
1132
|
-
|
|
834
|
+
callOfferCache.set(call.id, call);
|
|
1133
835
|
}
|
|
1134
|
-
const existingCall =
|
|
836
|
+
const existingCall = callOfferCache.get(call.id);
|
|
1135
837
|
// use existing call info to populate this event
|
|
1136
838
|
if (existingCall) {
|
|
1137
839
|
call.isVideo = existingCall.isVideo;
|
|
@@ -1139,7 +841,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1139
841
|
}
|
|
1140
842
|
// delete data once call has ended
|
|
1141
843
|
if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
|
|
1142
|
-
|
|
844
|
+
callOfferCache.del(call.id);
|
|
1143
845
|
}
|
|
1144
846
|
ev.emit('call', [call]);
|
|
1145
847
|
await sendMessageAck(node);
|
|
@@ -1225,6 +927,139 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1225
927
|
processNodeWithBuffer(node, identifier, exec);
|
|
1226
928
|
}
|
|
1227
929
|
};
|
|
930
|
+
// Handles newsletter notifications
|
|
931
|
+
async function handleNewsletterNotification(node) {
|
|
932
|
+
const from = node.attrs.from;
|
|
933
|
+
const child = getAllBinaryNodeChildren(node)[0];
|
|
934
|
+
const author = node.attrs.participant;
|
|
935
|
+
logger.info({ from, child }, 'got newsletter notification');
|
|
936
|
+
switch (child.tag) {
|
|
937
|
+
case 'reaction':
|
|
938
|
+
const reactionUpdate = {
|
|
939
|
+
id: from,
|
|
940
|
+
server_id: child.attrs.message_id,
|
|
941
|
+
reaction: {
|
|
942
|
+
code: getBinaryNodeChildString(child, 'reaction'),
|
|
943
|
+
count: 1
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
ev.emit('newsletter.reaction', reactionUpdate);
|
|
947
|
+
break;
|
|
948
|
+
case 'view':
|
|
949
|
+
const viewUpdate = {
|
|
950
|
+
id: from,
|
|
951
|
+
server_id: child.attrs.message_id,
|
|
952
|
+
count: parseInt(child.content?.toString() || '0', 10)
|
|
953
|
+
};
|
|
954
|
+
ev.emit('newsletter.view', viewUpdate);
|
|
955
|
+
break;
|
|
956
|
+
case 'participant':
|
|
957
|
+
const participantUpdate = {
|
|
958
|
+
id: from,
|
|
959
|
+
author,
|
|
960
|
+
user: child.attrs.jid,
|
|
961
|
+
action: child.attrs.action,
|
|
962
|
+
new_role: child.attrs.role
|
|
963
|
+
};
|
|
964
|
+
ev.emit('newsletter-participants.update', participantUpdate);
|
|
965
|
+
break;
|
|
966
|
+
case 'update':
|
|
967
|
+
const settingsNode = getBinaryNodeChild(child, 'settings');
|
|
968
|
+
if (settingsNode) {
|
|
969
|
+
const update = {};
|
|
970
|
+
const nameNode = getBinaryNodeChild(settingsNode, 'name');
|
|
971
|
+
if (nameNode?.content)
|
|
972
|
+
update.name = nameNode.content.toString();
|
|
973
|
+
const descriptionNode = getBinaryNodeChild(settingsNode, 'description');
|
|
974
|
+
if (descriptionNode?.content)
|
|
975
|
+
update.description = descriptionNode.content.toString();
|
|
976
|
+
ev.emit('newsletter-settings.update', {
|
|
977
|
+
id: from,
|
|
978
|
+
update
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
break;
|
|
982
|
+
case 'message':
|
|
983
|
+
const plaintextNode = getBinaryNodeChild(child, 'plaintext');
|
|
984
|
+
if (plaintextNode?.content) {
|
|
985
|
+
try {
|
|
986
|
+
const contentBuf = typeof plaintextNode.content === 'string'
|
|
987
|
+
? Buffer.from(plaintextNode.content, 'binary')
|
|
988
|
+
: Buffer.from(plaintextNode.content);
|
|
989
|
+
const messageProto = proto.Message.decode(contentBuf);
|
|
990
|
+
const fullMessage = proto.WebMessageInfo.create({
|
|
991
|
+
key: {
|
|
992
|
+
remoteJid: from,
|
|
993
|
+
id: child.attrs.message_id || child.attrs.server_id,
|
|
994
|
+
fromMe: false
|
|
995
|
+
},
|
|
996
|
+
message: messageProto,
|
|
997
|
+
messageTimestamp: +child.attrs.t
|
|
998
|
+
});
|
|
999
|
+
await upsertMessage(fullMessage, 'append');
|
|
1000
|
+
logger.info('Processed plaintext newsletter message');
|
|
1001
|
+
}
|
|
1002
|
+
catch (error) {
|
|
1003
|
+
logger.error({ error }, 'Failed to decode plaintext newsletter message');
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
break;
|
|
1007
|
+
default:
|
|
1008
|
+
logger.warn({ node }, 'Unknown newsletter notification');
|
|
1009
|
+
break;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
// Handles mex newsletter notifications
|
|
1013
|
+
async function handleMexNewsletterNotification(node) {
|
|
1014
|
+
const mexNode = getBinaryNodeChild(node, 'mex');
|
|
1015
|
+
if (!mexNode?.content) {
|
|
1016
|
+
logger.warn({ node }, 'Invalid mex newsletter notification');
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
let data;
|
|
1020
|
+
try {
|
|
1021
|
+
data = JSON.parse(mexNode.content.toString());
|
|
1022
|
+
}
|
|
1023
|
+
catch (error) {
|
|
1024
|
+
logger.error({ err: error, node }, 'Failed to parse mex newsletter notification');
|
|
1025
|
+
return;
|
|
1026
|
+
}
|
|
1027
|
+
const operation = data?.operation;
|
|
1028
|
+
const updates = data?.updates;
|
|
1029
|
+
if (!updates || !operation) {
|
|
1030
|
+
logger.warn({ data }, 'Invalid mex newsletter notification content');
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
logger.info({ operation, updates }, 'got mex newsletter notification');
|
|
1034
|
+
switch (operation) {
|
|
1035
|
+
case 'NotificationNewsletterUpdate':
|
|
1036
|
+
for (const update of updates) {
|
|
1037
|
+
if (update.jid && update.settings && Object.keys(update.settings).length > 0) {
|
|
1038
|
+
ev.emit('newsletter-settings.update', {
|
|
1039
|
+
id: update.jid,
|
|
1040
|
+
update: update.settings
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
break;
|
|
1045
|
+
case 'NotificationNewsletterAdminPromote':
|
|
1046
|
+
for (const update of updates) {
|
|
1047
|
+
if (update.jid && update.user) {
|
|
1048
|
+
ev.emit('newsletter-participants.update', {
|
|
1049
|
+
id: update.jid,
|
|
1050
|
+
author: node.attrs.from,
|
|
1051
|
+
user: update.user,
|
|
1052
|
+
new_role: 'ADMIN',
|
|
1053
|
+
action: 'promote'
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
break;
|
|
1058
|
+
default:
|
|
1059
|
+
logger.info({ operation, data }, 'Unhandled mex newsletter notification');
|
|
1060
|
+
break;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1228
1063
|
// recv a message
|
|
1229
1064
|
ws.on('CB:message', (node) => {
|
|
1230
1065
|
processNode('message', node, 'processing message', handleMessage);
|
|
@@ -1284,8 +1119,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1284
1119
|
sendRetryRequest,
|
|
1285
1120
|
rejectCall,
|
|
1286
1121
|
fetchMessageHistory,
|
|
1287
|
-
requestPlaceholderResend
|
|
1288
|
-
messageRetryManager
|
|
1122
|
+
requestPlaceholderResend
|
|
1289
1123
|
};
|
|
1290
1124
|
};
|
|
1291
1125
|
//# sourceMappingURL=messages-recv.js.map
|