@periskope/baileys 7.0.0-alpha-5 → 7.0.0-beta-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 +0 -6
- package/lib/Defaults/index.d.ts +1 -2
- package/lib/Defaults/index.d.ts.map +1 -1
- package/lib/Defaults/index.js +2 -3
- 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/queue-job.d.ts +1 -0
- package/lib/Signal/Group/queue-job.d.ts.map +1 -1
- package/lib/Signal/Group/queue-job.js +3 -0
- package/lib/Signal/Group/queue-job.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 +24 -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 +92 -137
- 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 +7 -8
- package/lib/Socket/business.d.ts.map +1 -1
- package/lib/Socket/chats.d.ts +7 -7
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +19 -15
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +7 -8
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/groups.d.ts +7 -7
- 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 +7 -8
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/messages-recv.d.ts +7 -8
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +254 -357
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +7 -9
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +110 -94
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +10 -9
- 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 +1 -8
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +52 -125
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Socket/usync.d.ts +2 -2
- package/lib/Types/Auth.d.ts +1 -1
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Types/Chat.d.ts +0 -2
- package/lib/Types/Chat.d.ts.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 +6 -7
- 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 +5 -13
- 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 -2
- 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 -8
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +28 -51
- 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.map +1 -1
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +3 -3
- 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 -10
|
@@ -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,34 @@ 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 =
|
|
721
|
-
return retryCount
|
|
480
|
+
const retryCount = msgRetryCache.get(key) || 0;
|
|
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
503
|
if (!ids[i])
|
|
789
504
|
continue;
|
|
790
|
-
if (msg &&
|
|
505
|
+
if (msg && willSendMessageAgain(ids[i], participant)) {
|
|
791
506
|
updateSendMessageAgainCount(ids[i], participant);
|
|
792
507
|
const msgRelayOpts = { messageId: ids[i] };
|
|
793
508
|
if (sendToAll) {
|
|
@@ -835,7 +550,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
835
550
|
if (typeof status !== 'undefined' &&
|
|
836
551
|
// basically, we only want to know when a message from us has been delivered to/read by the other person
|
|
837
552
|
// or another device of ours has read some messages
|
|
838
|
-
status >= proto.WebMessageInfo.Status.SERVER_ACK) {
|
|
553
|
+
(status >= proto.WebMessageInfo.Status.SERVER_ACK)) {
|
|
839
554
|
if (isJidGroup(remoteJid) || isJidStatusBroadcast(remoteJid)) {
|
|
840
555
|
const updateKey = status === proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
|
|
841
556
|
if (attrs.participant) {
|
|
@@ -877,7 +592,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
877
592
|
// correctly set who is asking for the retry
|
|
878
593
|
key.participant = key.participant || attrs.from;
|
|
879
594
|
const retryNode = getBinaryNodeChild(node, 'retry');
|
|
880
|
-
if (ids[0] && key.participant &&
|
|
595
|
+
if (ids[0] && key.participant && willSendMessageAgain(ids[0], key.participant)) {
|
|
881
596
|
if (key.fromMe) {
|
|
882
597
|
try {
|
|
883
598
|
updateSendMessageAgainCount(ids[0], key.participant);
|
|
@@ -946,22 +661,22 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
946
661
|
// TODO: temporary fix for crashes and issues resulting of failed msmsg decryption
|
|
947
662
|
if (encNode && encNode.attrs.type === 'msmsg') {
|
|
948
663
|
logger.debug({ key: node.attrs.key }, 'ignored msmsg');
|
|
949
|
-
await sendMessageAck(node
|
|
664
|
+
await sendMessageAck(node);
|
|
950
665
|
return;
|
|
951
666
|
}
|
|
952
667
|
let response;
|
|
953
668
|
if (getBinaryNodeChild(node, 'unavailable') && !encNode) {
|
|
954
669
|
await sendMessageAck(node);
|
|
955
670
|
const { key } = decodeMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '').fullMessage;
|
|
956
|
-
response = await requestPlaceholderResend(key);
|
|
671
|
+
response = await requestPlaceholderResend(key);
|
|
957
672
|
if (response === 'RESOLVED') {
|
|
958
673
|
return;
|
|
959
674
|
}
|
|
960
675
|
logger.debug('received unavailable message, acked and requested resend from phone');
|
|
961
676
|
}
|
|
962
677
|
else {
|
|
963
|
-
if (
|
|
964
|
-
|
|
678
|
+
if (placeholderResendCache.get(node.attrs.id)) {
|
|
679
|
+
placeholderResendCache.del(node.attrs.id);
|
|
965
680
|
}
|
|
966
681
|
}
|
|
967
682
|
const { fullMessage: msg, category, author, decrypt } = decryptMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
|
|
@@ -970,36 +685,38 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
970
685
|
}
|
|
971
686
|
if (msg.message?.protocolMessage?.type === proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER &&
|
|
972
687
|
node.attrs.sender_pn) {
|
|
973
|
-
|
|
974
|
-
ev.emit('lid-mapping.update', { lid, pn });
|
|
975
|
-
await signalRepository.lidMapping.storeLIDPNMappings([{ lid, pn }]);
|
|
688
|
+
ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
|
|
976
689
|
}
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
690
|
+
if (msg.message?.protocolMessage?.lidMigrationMappingSyncMessage?.encodedMappingPayload) {
|
|
691
|
+
try {
|
|
692
|
+
const payload = msg.message.protocolMessage.lidMigrationMappingSyncMessage.encodedMappingPayload;
|
|
693
|
+
const decoded = proto.LIDMigrationMappingSyncPayload.decode(payload);
|
|
694
|
+
logger.debug({
|
|
695
|
+
mappingCount: decoded.pnToLidMappings?.length || 0,
|
|
696
|
+
timestamp: decoded.chatDbMigrationTimestamp
|
|
697
|
+
}, 'Received LID migration sync message from server');
|
|
698
|
+
const lidMapping = signalRepository.getLIDMappingStore();
|
|
699
|
+
if (decoded.pnToLidMappings && decoded.pnToLidMappings.length > 0) {
|
|
700
|
+
for (const mapping of decoded.pnToLidMappings) {
|
|
701
|
+
const pn = `${mapping.pn}@s.whatsapp.net`;
|
|
702
|
+
// Use latestLid if available, otherwise assignedLid (proper LID refresh)
|
|
703
|
+
const lidValue = mapping.latestLid || mapping.assignedLid;
|
|
704
|
+
const lid = `${lidValue}@lid`;
|
|
705
|
+
await lidMapping.storeLIDPNMapping(lid, pn);
|
|
706
|
+
logger.debug({
|
|
707
|
+
pn,
|
|
708
|
+
lid,
|
|
709
|
+
assignedLid: mapping.assignedLid,
|
|
710
|
+
latestLid: mapping.latestLid,
|
|
711
|
+
usedLatest: !!mapping.latestLid
|
|
712
|
+
}, 'Stored server-provided PN-LID mapping');
|
|
713
|
+
}
|
|
986
714
|
}
|
|
987
715
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
await signalRepository.lidMapping.storeLIDPNMappings([
|
|
991
|
-
{ lid: msg.key.participant || msg.key.remoteJid, pn: alt }
|
|
992
|
-
]);
|
|
993
|
-
}
|
|
716
|
+
catch (error) {
|
|
717
|
+
logger.error({ error }, 'Failed to process LID migration sync message');
|
|
994
718
|
}
|
|
995
719
|
}
|
|
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');
|
|
1002
|
-
}
|
|
1003
720
|
try {
|
|
1004
721
|
await Promise.all([
|
|
1005
722
|
processingMutex.mutex(async () => {
|
|
@@ -1011,7 +728,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1011
728
|
}
|
|
1012
729
|
const errorMessage = msg?.messageStubParameters?.[0] || '';
|
|
1013
730
|
const isPreKeyError = errorMessage.includes('PreKey');
|
|
1014
|
-
|
|
731
|
+
console.debug(`[handleMessage] Attempting retry request for failed decryption`);
|
|
1015
732
|
// Handle both pre-key and normal retries in single mutex
|
|
1016
733
|
retryMutex.mutex(async () => {
|
|
1017
734
|
try {
|
|
@@ -1067,8 +784,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1067
784
|
// message was sent by us from a different device
|
|
1068
785
|
type = 'sender';
|
|
1069
786
|
// need to specially handle this case
|
|
1070
|
-
if (
|
|
1071
|
-
participant = author;
|
|
787
|
+
if (isJidUser(msg.key.remoteJid)) {
|
|
788
|
+
participant = author;
|
|
1072
789
|
}
|
|
1073
790
|
}
|
|
1074
791
|
else if (!sendActiveReceipts) {
|
|
@@ -1092,6 +809,54 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1092
809
|
logger.error({ error, node }, 'error in handling message');
|
|
1093
810
|
}
|
|
1094
811
|
};
|
|
812
|
+
const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
|
|
813
|
+
if (!authState.creds.me?.id) {
|
|
814
|
+
throw new Boom('Not authenticated');
|
|
815
|
+
}
|
|
816
|
+
const pdoMessage = {
|
|
817
|
+
historySyncOnDemandRequest: {
|
|
818
|
+
chatJid: oldestMsgKey.remoteJid,
|
|
819
|
+
oldestMsgFromMe: oldestMsgKey.fromMe,
|
|
820
|
+
oldestMsgId: oldestMsgKey.id,
|
|
821
|
+
oldestMsgTimestampMs: oldestMsgTimestamp,
|
|
822
|
+
onDemandMsgCount: count
|
|
823
|
+
},
|
|
824
|
+
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
|
|
825
|
+
};
|
|
826
|
+
return sendPeerDataOperationMessage(pdoMessage);
|
|
827
|
+
};
|
|
828
|
+
const requestPlaceholderResend = async (messageKey) => {
|
|
829
|
+
if (!authState.creds.me?.id) {
|
|
830
|
+
throw new Boom('Not authenticated');
|
|
831
|
+
}
|
|
832
|
+
if (placeholderResendCache.get(messageKey?.id)) {
|
|
833
|
+
logger.debug({ messageKey }, 'already requested resend');
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
else {
|
|
837
|
+
placeholderResendCache.set(messageKey?.id, true);
|
|
838
|
+
}
|
|
839
|
+
await delay(5000);
|
|
840
|
+
if (!placeholderResendCache.get(messageKey?.id)) {
|
|
841
|
+
logger.debug({ messageKey }, 'message received while resend requested');
|
|
842
|
+
return 'RESOLVED';
|
|
843
|
+
}
|
|
844
|
+
const pdoMessage = {
|
|
845
|
+
placeholderMessageResendRequest: [
|
|
846
|
+
{
|
|
847
|
+
messageKey
|
|
848
|
+
}
|
|
849
|
+
],
|
|
850
|
+
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
|
|
851
|
+
};
|
|
852
|
+
setTimeout(() => {
|
|
853
|
+
if (placeholderResendCache.get(messageKey?.id)) {
|
|
854
|
+
logger.debug({ messageKey }, 'PDO message without response after 15 seconds. Phone possibly offline');
|
|
855
|
+
placeholderResendCache.del(messageKey?.id);
|
|
856
|
+
}
|
|
857
|
+
}, 15000);
|
|
858
|
+
return sendPeerDataOperationMessage(pdoMessage);
|
|
859
|
+
};
|
|
1095
860
|
const handleCall = async (node) => {
|
|
1096
861
|
let status;
|
|
1097
862
|
const { attrs } = node;
|
|
@@ -1103,7 +868,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1103
868
|
const from = infoChild.attrs.from || infoChild.attrs['call-creator'];
|
|
1104
869
|
status = getCallStatusFromNode(infoChild);
|
|
1105
870
|
if (isLidUser(from) && infoChild.tag === 'relaylatency') {
|
|
1106
|
-
const verify =
|
|
871
|
+
const verify = callOfferCache.get(callId);
|
|
1107
872
|
if (!verify) {
|
|
1108
873
|
status = 'offer';
|
|
1109
874
|
const callLid = {
|
|
@@ -1114,7 +879,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1114
879
|
offline: !!attrs.offline,
|
|
1115
880
|
status
|
|
1116
881
|
};
|
|
1117
|
-
|
|
882
|
+
callOfferCache.set(callId, callLid);
|
|
1118
883
|
}
|
|
1119
884
|
}
|
|
1120
885
|
const call = {
|
|
@@ -1129,9 +894,9 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1129
894
|
call.isVideo = !!getBinaryNodeChild(infoChild, 'video');
|
|
1130
895
|
call.isGroup = infoChild.attrs.type === 'group' || !!infoChild.attrs['group-jid'];
|
|
1131
896
|
call.groupJid = infoChild.attrs['group-jid'];
|
|
1132
|
-
|
|
897
|
+
callOfferCache.set(call.id, call);
|
|
1133
898
|
}
|
|
1134
|
-
const existingCall =
|
|
899
|
+
const existingCall = callOfferCache.get(call.id);
|
|
1135
900
|
// use existing call info to populate this event
|
|
1136
901
|
if (existingCall) {
|
|
1137
902
|
call.isVideo = existingCall.isVideo;
|
|
@@ -1139,7 +904,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1139
904
|
}
|
|
1140
905
|
// delete data once call has ended
|
|
1141
906
|
if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
|
|
1142
|
-
|
|
907
|
+
callOfferCache.del(call.id);
|
|
1143
908
|
}
|
|
1144
909
|
ev.emit('call', [call]);
|
|
1145
910
|
await sendMessageAck(node);
|
|
@@ -1225,6 +990,139 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1225
990
|
processNodeWithBuffer(node, identifier, exec);
|
|
1226
991
|
}
|
|
1227
992
|
};
|
|
993
|
+
// Handles newsletter notifications
|
|
994
|
+
async function handleNewsletterNotification(node) {
|
|
995
|
+
const from = node.attrs.from;
|
|
996
|
+
const child = getAllBinaryNodeChildren(node)[0];
|
|
997
|
+
const author = node.attrs.participant;
|
|
998
|
+
logger.info({ from, child }, 'got newsletter notification');
|
|
999
|
+
switch (child.tag) {
|
|
1000
|
+
case 'reaction':
|
|
1001
|
+
const reactionUpdate = {
|
|
1002
|
+
id: from,
|
|
1003
|
+
server_id: child.attrs.message_id,
|
|
1004
|
+
reaction: {
|
|
1005
|
+
code: getBinaryNodeChildString(child, 'reaction'),
|
|
1006
|
+
count: 1
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
1009
|
+
ev.emit('newsletter.reaction', reactionUpdate);
|
|
1010
|
+
break;
|
|
1011
|
+
case 'view':
|
|
1012
|
+
const viewUpdate = {
|
|
1013
|
+
id: from,
|
|
1014
|
+
server_id: child.attrs.message_id,
|
|
1015
|
+
count: parseInt(child.content?.toString() || '0', 10)
|
|
1016
|
+
};
|
|
1017
|
+
ev.emit('newsletter.view', viewUpdate);
|
|
1018
|
+
break;
|
|
1019
|
+
case 'participant':
|
|
1020
|
+
const participantUpdate = {
|
|
1021
|
+
id: from,
|
|
1022
|
+
author,
|
|
1023
|
+
user: child.attrs.jid,
|
|
1024
|
+
action: child.attrs.action,
|
|
1025
|
+
new_role: child.attrs.role
|
|
1026
|
+
};
|
|
1027
|
+
ev.emit('newsletter-participants.update', participantUpdate);
|
|
1028
|
+
break;
|
|
1029
|
+
case 'update':
|
|
1030
|
+
const settingsNode = getBinaryNodeChild(child, 'settings');
|
|
1031
|
+
if (settingsNode) {
|
|
1032
|
+
const update = {};
|
|
1033
|
+
const nameNode = getBinaryNodeChild(settingsNode, 'name');
|
|
1034
|
+
if (nameNode?.content)
|
|
1035
|
+
update.name = nameNode.content.toString();
|
|
1036
|
+
const descriptionNode = getBinaryNodeChild(settingsNode, 'description');
|
|
1037
|
+
if (descriptionNode?.content)
|
|
1038
|
+
update.description = descriptionNode.content.toString();
|
|
1039
|
+
ev.emit('newsletter-settings.update', {
|
|
1040
|
+
id: from,
|
|
1041
|
+
update
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
break;
|
|
1045
|
+
case 'message':
|
|
1046
|
+
const plaintextNode = getBinaryNodeChild(child, 'plaintext');
|
|
1047
|
+
if (plaintextNode?.content) {
|
|
1048
|
+
try {
|
|
1049
|
+
const contentBuf = typeof plaintextNode.content === 'string'
|
|
1050
|
+
? Buffer.from(plaintextNode.content, 'binary')
|
|
1051
|
+
: Buffer.from(plaintextNode.content);
|
|
1052
|
+
const messageProto = proto.Message.decode(contentBuf);
|
|
1053
|
+
const fullMessage = proto.WebMessageInfo.create({
|
|
1054
|
+
key: {
|
|
1055
|
+
remoteJid: from,
|
|
1056
|
+
id: child.attrs.message_id || child.attrs.server_id,
|
|
1057
|
+
fromMe: false
|
|
1058
|
+
},
|
|
1059
|
+
message: messageProto,
|
|
1060
|
+
messageTimestamp: +child.attrs.t
|
|
1061
|
+
});
|
|
1062
|
+
await upsertMessage(fullMessage, 'append');
|
|
1063
|
+
logger.info('Processed plaintext newsletter message');
|
|
1064
|
+
}
|
|
1065
|
+
catch (error) {
|
|
1066
|
+
logger.error({ error }, 'Failed to decode plaintext newsletter message');
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
break;
|
|
1070
|
+
default:
|
|
1071
|
+
logger.warn({ node }, 'Unknown newsletter notification');
|
|
1072
|
+
break;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
// Handles mex newsletter notifications
|
|
1076
|
+
async function handleMexNewsletterNotification(node) {
|
|
1077
|
+
const mexNode = getBinaryNodeChild(node, 'mex');
|
|
1078
|
+
if (!mexNode?.content) {
|
|
1079
|
+
logger.warn({ node }, 'Invalid mex newsletter notification');
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
let data;
|
|
1083
|
+
try {
|
|
1084
|
+
data = JSON.parse(mexNode.content.toString());
|
|
1085
|
+
}
|
|
1086
|
+
catch (error) {
|
|
1087
|
+
logger.error({ err: error, node }, 'Failed to parse mex newsletter notification');
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
const operation = data?.operation;
|
|
1091
|
+
const updates = data?.updates;
|
|
1092
|
+
if (!updates || !operation) {
|
|
1093
|
+
logger.warn({ data }, 'Invalid mex newsletter notification content');
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
logger.info({ operation, updates }, 'got mex newsletter notification');
|
|
1097
|
+
switch (operation) {
|
|
1098
|
+
case 'NotificationNewsletterUpdate':
|
|
1099
|
+
for (const update of updates) {
|
|
1100
|
+
if (update.jid && update.settings && Object.keys(update.settings).length > 0) {
|
|
1101
|
+
ev.emit('newsletter-settings.update', {
|
|
1102
|
+
id: update.jid,
|
|
1103
|
+
update: update.settings
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
break;
|
|
1108
|
+
case 'NotificationNewsletterAdminPromote':
|
|
1109
|
+
for (const update of updates) {
|
|
1110
|
+
if (update.jid && update.user) {
|
|
1111
|
+
ev.emit('newsletter-participants.update', {
|
|
1112
|
+
id: update.jid,
|
|
1113
|
+
author: node.attrs.from,
|
|
1114
|
+
user: update.user,
|
|
1115
|
+
new_role: 'ADMIN',
|
|
1116
|
+
action: 'promote'
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
break;
|
|
1121
|
+
default:
|
|
1122
|
+
logger.info({ operation, data }, 'Unhandled mex newsletter notification');
|
|
1123
|
+
break;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1228
1126
|
// recv a message
|
|
1229
1127
|
ws.on('CB:message', (node) => {
|
|
1230
1128
|
processNode('message', node, 'processing message', handleMessage);
|
|
@@ -1284,8 +1182,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1284
1182
|
sendRetryRequest,
|
|
1285
1183
|
rejectCall,
|
|
1286
1184
|
fetchMessageHistory,
|
|
1287
|
-
requestPlaceholderResend
|
|
1288
|
-
messageRetryManager
|
|
1185
|
+
requestPlaceholderResend
|
|
1289
1186
|
};
|
|
1290
1187
|
};
|
|
1291
1188
|
//# sourceMappingURL=messages-recv.js.map
|