@periskope/baileys 6.7.19 → 7.0.0-alpha-1
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 +6 -0
- package/WAProto/GenerateStatics.sh +2 -2
- package/WAProto/index.d.ts +2793 -45578
- package/WAProto/index.js +19344 -147065
- package/lib/Defaults/index.d.ts +7 -1
- package/lib/Defaults/index.d.ts.map +1 -1
- package/lib/Defaults/index.js +11 -4
- package/lib/Defaults/index.js.map +1 -1
- package/lib/Signal/Group/group_cipher.d.ts +0 -1
- package/lib/Signal/Group/group_cipher.d.ts.map +1 -1
- package/lib/Signal/Group/group_cipher.js +28 -36
- package/lib/Signal/Group/group_cipher.js.map +1 -1
- package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +1 -1
- package/lib/Signal/Group/sender-key-distribution-message.js +1 -1
- package/lib/Signal/Group/sender-key-distribution-message.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 -1
- package/lib/Signal/Group/sender-key-message.js.map +1 -1
- package/lib/Signal/Group/sender-key-state.d.ts.map +1 -1
- package/lib/Signal/Group/sender-key-state.js +6 -1
- package/lib/Signal/Group/sender-key-state.js.map +1 -1
- package/lib/Signal/libsignal.d.ts +5 -1
- package/lib/Signal/libsignal.d.ts.map +1 -1
- package/lib/Signal/libsignal.js +211 -38
- package/lib/Signal/libsignal.js.map +1 -1
- package/lib/Signal/lid-mapping.d.ts +14 -3
- package/lib/Signal/lid-mapping.d.ts.map +1 -0
- package/lib/Signal/lid-mapping.js +53 -65
- package/lib/Signal/lid-mapping.js.map +1 -0
- package/lib/Socket/business.d.ts +25 -13
- package/lib/Socket/business.d.ts.map +1 -1
- package/lib/Socket/business.js +122 -1
- package/lib/Socket/business.js.map +1 -1
- package/lib/Socket/chats.d.ts +14 -8
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +54 -21
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +24 -10
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/communities.js +45 -1
- package/lib/Socket/communities.js.map +1 -1
- package/lib/Socket/groups.d.ts +13 -8
- package/lib/Socket/groups.d.ts.map +1 -1
- package/lib/Socket/groups.js +12 -11
- package/lib/Socket/groups.js.map +1 -1
- package/lib/Socket/index.d.ts +24 -10
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/messages-recv.d.ts +18 -10
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +383 -220
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +19 -10
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +454 -62
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +15 -11
- package/lib/Socket/newsletter.d.ts.map +1 -1
- package/lib/Socket/newsletter.js +3 -1
- package/lib/Socket/newsletter.js.map +1 -1
- package/lib/Socket/socket.d.ts +9 -2
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +266 -70
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +2 -1
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Types/Bussines.d.ts +25 -0
- package/lib/Types/Bussines.d.ts.map +1 -0
- package/lib/Types/Bussines.js +2 -0
- package/lib/Types/Bussines.js.map +1 -0
- package/lib/Types/Chat.d.ts +5 -0
- 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 +6 -4
- package/lib/Types/GroupMetadata.d.ts.map +1 -1
- package/lib/Types/Message.d.ts +28 -7
- package/lib/Types/Message.d.ts.map +1 -1
- package/lib/Types/Message.js +5 -1
- package/lib/Types/Message.js.map +1 -1
- package/lib/Types/Signal.d.ts +24 -0
- package/lib/Types/Signal.d.ts.map +1 -1
- package/lib/Types/Socket.d.ts +9 -1
- 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 +362 -78
- 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 +20 -3
- package/lib/Utils/chat-utils.js.map +1 -1
- package/lib/Utils/decode-wa-message.d.ts +10 -0
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +84 -13
- package/lib/Utils/decode-wa-message.js.map +1 -1
- package/lib/Utils/event-buffer.d.ts +0 -1
- package/lib/Utils/event-buffer.d.ts.map +1 -1
- package/lib/Utils/event-buffer.js +48 -4
- package/lib/Utils/event-buffer.js.map +1 -1
- package/lib/Utils/generics.d.ts.map +1 -1
- package/lib/Utils/generics.js +17 -8
- package/lib/Utils/generics.js.map +1 -1
- package/lib/Utils/history.d.ts.map +1 -1
- package/lib/Utils/history.js +1 -2
- package/lib/Utils/history.js.map +1 -1
- package/lib/Utils/index.d.ts +1 -0
- package/lib/Utils/index.d.ts.map +1 -1
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/index.js.map +1 -1
- package/lib/Utils/message-retry-manager.d.ts +82 -0
- package/lib/Utils/message-retry-manager.d.ts.map +1 -0
- package/lib/Utils/message-retry-manager.js +149 -0
- package/lib/Utils/message-retry-manager.js.map +1 -0
- package/lib/Utils/messages-media.d.ts +3 -2
- package/lib/Utils/messages-media.d.ts.map +1 -1
- package/lib/Utils/messages-media.js +4 -1
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +35 -15
- package/lib/Utils/messages.js.map +1 -1
- package/lib/Utils/process-message.d.ts +3 -2
- package/lib/Utils/process-message.d.ts.map +1 -1
- package/lib/Utils/process-message.js +13 -2
- package/lib/Utils/process-message.js.map +1 -1
- package/lib/Utils/use-multi-file-auth-state.js +1 -1
- package/lib/Utils/use-multi-file-auth-state.js.map +1 -1
- package/lib/Utils/validate-connection.d.ts.map +1 -1
- package/lib/Utils/validate-connection.js +5 -4
- package/lib/Utils/validate-connection.js.map +1 -1
- package/lib/WABinary/jid-utils.d.ts +6 -5
- package/lib/WABinary/jid-utils.d.ts.map +1 -1
- package/lib/WABinary/jid-utils.js +11 -5
- package/lib/WABinary/jid-utils.js.map +1 -1
- package/lib/WAM/encode.d.ts.map +1 -1
- package/lib/WAM/encode.js +0 -1
- package/lib/WAM/encode.js.map +1 -1
- package/package.json +12 -8
|
@@ -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,
|
|
10
|
+
import { areJidsSameUser, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString, isJidGroup, isJidStatusBroadcast, 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 } = config;
|
|
14
|
+
const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid, enableAutoSessionRecreation } = config;
|
|
15
15
|
const sock = makeMessagesSocket(config);
|
|
16
|
-
const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage } = sock;
|
|
16
|
+
const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage, messageRetryManager } = 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,6 +32,187 @@ 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
|
+
};
|
|
35
216
|
const sendMessageAck = async ({ tag, attrs, content }, errorCode) => {
|
|
36
217
|
const stanza = {
|
|
37
218
|
tag: 'ack',
|
|
@@ -107,20 +288,76 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
107
288
|
const { fullMessage } = decodeMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '');
|
|
108
289
|
const { key: msgKey } = fullMessage;
|
|
109
290
|
const msgId = msgKey.id;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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);
|
|
116
303
|
}
|
|
117
|
-
|
|
118
|
-
|
|
304
|
+
else {
|
|
305
|
+
// Fallback to old system
|
|
306
|
+
const key = `${msgId}:${msgKey?.participant}`;
|
|
307
|
+
let retryCount = 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
|
+
msgRetryCache.set(key, retryCount);
|
|
315
|
+
}
|
|
316
|
+
const key = `${msgId}:${msgKey?.participant}`;
|
|
317
|
+
const retryCount = msgRetryCache.get(key) || 1;
|
|
119
318
|
const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
319
|
+
const fromJid = node.attrs.from;
|
|
320
|
+
// Check if we should recreate the session
|
|
321
|
+
let shouldRecreateSession = false;
|
|
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
|
+
}
|
|
341
|
+
}
|
|
342
|
+
if (retryCount <= 2) {
|
|
343
|
+
// Use new retry manager for phone requests if available
|
|
344
|
+
if (messageRetryManager) {
|
|
345
|
+
// Schedule phone request with delay (like whatsmeow)
|
|
346
|
+
messageRetryManager.schedulePhoneRequest(msgId, async () => {
|
|
347
|
+
try {
|
|
348
|
+
const msgId = await requestPlaceholderResend(msgKey);
|
|
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
|
+
}
|
|
124
361
|
}
|
|
125
362
|
const deviceIdentity = encodeSignedDeviceIdentity(account, true);
|
|
126
363
|
await authState.keys.transaction(async () => {
|
|
@@ -154,7 +391,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
154
391
|
if (node.attrs.participant) {
|
|
155
392
|
receipt.attrs.participant = node.attrs.participant;
|
|
156
393
|
}
|
|
157
|
-
if (retryCount > 1 || forceIncludeKeys) {
|
|
394
|
+
if (retryCount > 1 || forceIncludeKeys || shouldRecreateSession) {
|
|
158
395
|
const { update, preKeys } = await getNextPreKeys(authState, 1);
|
|
159
396
|
const [keyId] = Object.keys(preKeys);
|
|
160
397
|
const key = preKeys[+keyId];
|
|
@@ -174,7 +411,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
174
411
|
}
|
|
175
412
|
await sendNode(receipt);
|
|
176
413
|
logger.info({ msgAttrs: node.attrs, retryCount }, 'sent retry receipt');
|
|
177
|
-
});
|
|
414
|
+
}, authState?.creds?.me?.id || 'sendRetryRequest');
|
|
178
415
|
};
|
|
179
416
|
const handleEncryptNotification = async (node) => {
|
|
180
417
|
const from = node.attrs.from;
|
|
@@ -201,6 +438,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
201
438
|
};
|
|
202
439
|
const handleGroupNotification = (participant, child, msg) => {
|
|
203
440
|
const participantJid = getBinaryNodeChild(child, 'participant')?.attrs?.jid || participant;
|
|
441
|
+
// TODO: Add participant LID
|
|
204
442
|
switch (child?.tag) {
|
|
205
443
|
case 'create':
|
|
206
444
|
const metadata = extractGroupMetadata(child);
|
|
@@ -337,10 +575,12 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
337
575
|
break;
|
|
338
576
|
case 'devices':
|
|
339
577
|
const devices = getBinaryNodeChildren(child, 'device');
|
|
340
|
-
if (areJidsSameUser(child.attrs.jid, authState.creds.me.id)
|
|
341
|
-
|
|
342
|
-
|
|
578
|
+
if (areJidsSameUser(child.attrs.jid, authState.creds.me.id) ||
|
|
579
|
+
areJidsSameUser(child.attrs.lid, authState.creds.me.lid)) {
|
|
580
|
+
const deviceData = devices.map(d => ({ id: d.attrs.jid, lid: d.attrs.lid }));
|
|
581
|
+
logger.info({ deviceData }, 'my own devices changed');
|
|
343
582
|
}
|
|
583
|
+
//TODO: drop a new event, add hashes
|
|
344
584
|
break;
|
|
345
585
|
case 'server_sync':
|
|
346
586
|
const update = getBinaryNodeChild(node, 'collection');
|
|
@@ -478,7 +718,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
478
718
|
const willSendMessageAgain = (id, participant) => {
|
|
479
719
|
const key = `${id}:${participant}`;
|
|
480
720
|
const retryCount = msgRetryCache.get(key) || 0;
|
|
481
|
-
return retryCount
|
|
721
|
+
return retryCount <= maxMsgRetryCount;
|
|
482
722
|
};
|
|
483
723
|
const updateSendMessageAgainCount = (id, participant) => {
|
|
484
724
|
const key = `${id}:${participant}`;
|
|
@@ -486,21 +726,68 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
486
726
|
msgRetryCache.set(key, newValue);
|
|
487
727
|
};
|
|
488
728
|
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 })));
|
|
491
729
|
const remoteJid = key.remoteJid;
|
|
492
730
|
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
|
+
}
|
|
493
759
|
// if it's the primary jid sending the request
|
|
494
760
|
// just re-send the message to everyone
|
|
495
761
|
// prevents the first message decryption failure
|
|
496
762
|
const sendToAll = !jidDecode(participant)?.device;
|
|
497
|
-
|
|
763
|
+
// Check if we should recreate session for this retry
|
|
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);
|
|
498
783
|
if (isJidGroup(remoteJid)) {
|
|
499
784
|
await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } });
|
|
500
785
|
}
|
|
501
|
-
logger.debug({ participant, sendToAll }, 'forced new session for retry recp');
|
|
786
|
+
logger.debug({ participant, sendToAll, shouldRecreateSession, recreateReason }, 'forced new session for retry recp');
|
|
502
787
|
for (const [i, msg] of msgs.entries()) {
|
|
503
|
-
if (
|
|
788
|
+
if (!ids[i])
|
|
789
|
+
continue;
|
|
790
|
+
if (msg && willSendMessageAgain(ids[i], participant)) {
|
|
504
791
|
updateSendMessageAgainCount(ids[i], participant);
|
|
505
792
|
const msgRelayOpts = { messageId: ids[i] };
|
|
506
793
|
if (sendToAll) {
|
|
@@ -548,7 +835,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
548
835
|
if (typeof status !== 'undefined' &&
|
|
549
836
|
// basically, we only want to know when a message from us has been delivered to/read by the other person
|
|
550
837
|
// or another device of ours has read some messages
|
|
551
|
-
|
|
838
|
+
status >= proto.WebMessageInfo.Status.SERVER_ACK) {
|
|
552
839
|
if (isJidGroup(remoteJid) || isJidStatusBroadcast(remoteJid)) {
|
|
553
840
|
const updateKey = status === proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
|
|
554
841
|
if (attrs.participant) {
|
|
@@ -590,15 +877,16 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
590
877
|
// correctly set who is asking for the retry
|
|
591
878
|
key.participant = key.participant || attrs.from;
|
|
592
879
|
const retryNode = getBinaryNodeChild(node, 'retry');
|
|
593
|
-
if (willSendMessageAgain(ids[0], key.participant)) {
|
|
880
|
+
if (ids[0] && key.participant && willSendMessageAgain(ids[0], key.participant)) {
|
|
594
881
|
if (key.fromMe) {
|
|
595
882
|
try {
|
|
883
|
+
updateSendMessageAgainCount(ids[0], key.participant);
|
|
596
884
|
logger.debug({ attrs, key }, 'recv retry request');
|
|
597
885
|
await sendMessagesAgain(key, ids, retryNode);
|
|
598
886
|
ev.emit('messages.retry', { key, ids, retryNode });
|
|
599
887
|
}
|
|
600
888
|
catch (error) {
|
|
601
|
-
logger.error({ key, ids, trace: error.stack }, 'error in sending message again');
|
|
889
|
+
logger.error({ key, ids, trace: error instanceof Error ? error.stack : 'Unknown error' }, 'error in sending message again');
|
|
602
890
|
}
|
|
603
891
|
}
|
|
604
892
|
else {
|
|
@@ -638,7 +926,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
638
926
|
};
|
|
639
927
|
msg.participant ?? (msg.participant = node.attrs.participant);
|
|
640
928
|
msg.messageTimestamp = +node.attrs.t;
|
|
641
|
-
const fullMsg = proto.WebMessageInfo.
|
|
929
|
+
const fullMsg = proto.WebMessageInfo.create(msg);
|
|
642
930
|
await upsertMessage(fullMsg, 'append');
|
|
643
931
|
}
|
|
644
932
|
})
|
|
@@ -658,7 +946,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
658
946
|
// TODO: temporary fix for crashes and issues resulting of failed msmsg decryption
|
|
659
947
|
if (encNode && encNode.attrs.type === 'msmsg') {
|
|
660
948
|
logger.debug({ key: node.attrs.key }, 'ignored msmsg');
|
|
661
|
-
await sendMessageAck(node);
|
|
949
|
+
await sendMessageAck(node, NACK_REASONS.MissingMessageSecret);
|
|
662
950
|
return;
|
|
663
951
|
}
|
|
664
952
|
let response;
|
|
@@ -682,7 +970,32 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
682
970
|
}
|
|
683
971
|
if (msg.message?.protocolMessage?.type === proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER &&
|
|
684
972
|
node.attrs.sender_pn) {
|
|
685
|
-
|
|
973
|
+
const lid = jidNormalizedUser(node.attrs.from), pn = jidNormalizedUser(node.attrs.sender_pn);
|
|
974
|
+
ev.emit('lid-mapping.update', { lid, pn });
|
|
975
|
+
await signalRepository.storeLIDPNMapping(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
|
+
const lidMapping = signalRepository.getLIDMappingStore();
|
|
982
|
+
if (altServer === 'lid') {
|
|
983
|
+
if (!(await lidMapping.getPNForLID(alt))) {
|
|
984
|
+
await lidMapping.storeLIDPNMapping(alt, msg.key.participant || msg.key.remoteJid);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
if (!(await lidMapping.getLIDForPN(alt))) {
|
|
989
|
+
await lidMapping.storeLIDPNMapping(msg.key.participant || msg.key.remoteJid, alt);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
if (msg.key?.remoteJid && msg.key?.id && messageRetryManager) {
|
|
994
|
+
messageRetryManager.addRecentMessage(msg.key.remoteJid, msg.key.id, msg.message);
|
|
995
|
+
logger.debug({
|
|
996
|
+
jid: msg.key.remoteJid,
|
|
997
|
+
id: msg.key.id
|
|
998
|
+
}, 'Added message to recent cache for retry receipts');
|
|
686
999
|
}
|
|
687
1000
|
try {
|
|
688
1001
|
await Promise.all([
|
|
@@ -693,19 +1006,49 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
693
1006
|
if (msg?.messageStubParameters?.[0] === MISSING_KEYS_ERROR_TEXT) {
|
|
694
1007
|
return sendMessageAck(node, NACK_REASONS.ParsingError);
|
|
695
1008
|
}
|
|
1009
|
+
const errorMessage = msg?.messageStubParameters?.[0] || '';
|
|
1010
|
+
const isPreKeyError = errorMessage.includes('PreKey');
|
|
1011
|
+
logger.debug(`[handleMessage] Attempting retry request for failed decryption`);
|
|
1012
|
+
// Handle both pre-key and normal retries in single mutex
|
|
696
1013
|
retryMutex.mutex(async () => {
|
|
697
|
-
|
|
1014
|
+
try {
|
|
1015
|
+
if (!ws.isOpen) {
|
|
1016
|
+
logger.debug({ node }, 'Connection closed, skipping retry');
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
698
1019
|
if (getBinaryNodeChild(node, 'unavailable')) {
|
|
1020
|
+
logger.debug('Message unavailable, skipping retry');
|
|
699
1021
|
return;
|
|
700
1022
|
}
|
|
1023
|
+
// Handle pre-key errors with upload and delay
|
|
1024
|
+
if (isPreKeyError) {
|
|
1025
|
+
logger.info({ error: errorMessage }, 'PreKey error detected, uploading and retrying');
|
|
1026
|
+
try {
|
|
1027
|
+
logger.debug('Uploading pre-keys for error recovery');
|
|
1028
|
+
await uploadPreKeys(5);
|
|
1029
|
+
logger.debug('Waiting for server to process new pre-keys');
|
|
1030
|
+
await delay(1000);
|
|
1031
|
+
}
|
|
1032
|
+
catch (uploadErr) {
|
|
1033
|
+
logger.error({ uploadErr }, 'Pre-key upload failed, proceeding with retry anyway');
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
701
1036
|
const encNode = getBinaryNodeChild(node, 'enc');
|
|
702
1037
|
await sendRetryRequest(node, !encNode);
|
|
703
1038
|
if (retryRequestDelayMs) {
|
|
704
1039
|
await delay(retryRequestDelayMs);
|
|
705
1040
|
}
|
|
706
1041
|
}
|
|
707
|
-
|
|
708
|
-
logger.
|
|
1042
|
+
catch (err) {
|
|
1043
|
+
logger.error({ err, isPreKeyError }, 'Failed to handle retry, attempting basic retry');
|
|
1044
|
+
// Still attempt retry even if pre-key upload failed
|
|
1045
|
+
try {
|
|
1046
|
+
const encNode = getBinaryNodeChild(node, 'enc');
|
|
1047
|
+
await sendRetryRequest(node, !encNode);
|
|
1048
|
+
}
|
|
1049
|
+
catch (retryErr) {
|
|
1050
|
+
logger.error({ retryErr }, 'Failed to send retry after error handling');
|
|
1051
|
+
}
|
|
709
1052
|
}
|
|
710
1053
|
});
|
|
711
1054
|
}
|
|
@@ -721,8 +1064,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
721
1064
|
// message was sent by us from a different device
|
|
722
1065
|
type = 'sender';
|
|
723
1066
|
// need to specially handle this case
|
|
724
|
-
if (
|
|
725
|
-
participant = author;
|
|
1067
|
+
if (isLidUser(msg.key.remoteJid) || isLidUser(msg.key.remoteJidAlt)) {
|
|
1068
|
+
participant = author; // TODO: investigate sending receipts to LIDs and not PNs
|
|
726
1069
|
}
|
|
727
1070
|
}
|
|
728
1071
|
else if (!sendActiveReceipts) {
|
|
@@ -746,54 +1089,6 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
746
1089
|
logger.error({ error, node }, 'error in handling message');
|
|
747
1090
|
}
|
|
748
1091
|
};
|
|
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
|
-
};
|
|
797
1092
|
const handleCall = async (node) => {
|
|
798
1093
|
let status;
|
|
799
1094
|
const { attrs } = node;
|
|
@@ -927,139 +1222,6 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
927
1222
|
processNodeWithBuffer(node, identifier, exec);
|
|
928
1223
|
}
|
|
929
1224
|
};
|
|
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.fromObject({
|
|
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
|
-
}
|
|
1063
1225
|
// recv a message
|
|
1064
1226
|
ws.on('CB:message', (node) => {
|
|
1065
1227
|
processNode('message', node, 'processing message', handleMessage);
|
|
@@ -1103,7 +1265,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1103
1265
|
else {
|
|
1104
1266
|
msg.message = { call: { callKey: Buffer.from(call.id) } };
|
|
1105
1267
|
}
|
|
1106
|
-
const protoMsg = proto.WebMessageInfo.
|
|
1268
|
+
const protoMsg = proto.WebMessageInfo.create(msg);
|
|
1107
1269
|
upsertMessage(protoMsg, call.offline ? 'append' : 'notify');
|
|
1108
1270
|
}
|
|
1109
1271
|
});
|
|
@@ -1119,7 +1281,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1119
1281
|
sendRetryRequest,
|
|
1120
1282
|
rejectCall,
|
|
1121
1283
|
fetchMessageHistory,
|
|
1122
|
-
requestPlaceholderResend
|
|
1284
|
+
requestPlaceholderResend,
|
|
1285
|
+
messageRetryManager
|
|
1123
1286
|
};
|
|
1124
1287
|
};
|
|
1125
1288
|
//# sourceMappingURL=messages-recv.js.map
|