@d0v3riz/baileys 6.7.25 → 7.0.0-rc.8
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 +53 -50
- package/WAProto/GenerateStatics.sh +2 -2
- package/WAProto/WAProto.proto +1339 -493
- package/WAProto/fix-imports.js +1 -1
- package/WAProto/index.d.ts +4585 -44041
- package/WAProto/index.js +80831 -148208
- package/lib/Defaults/index.d.ts +13 -3
- package/lib/Defaults/index.d.ts.map +1 -1
- package/lib/Defaults/index.js +27 -13
- package/lib/Defaults/index.js.map +1 -1
- package/lib/Signal/Group/group_cipher.d.ts +1 -2
- package/lib/Signal/Group/group_cipher.d.ts.map +1 -1
- package/lib/Signal/Group/group_cipher.js +29 -41
- 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 +0 -1
- 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 +1 -7
- package/lib/Signal/Group/sender-chain-key.js.map +1 -1
- package/lib/Signal/Group/sender-key-distribution-message.js +2 -2
- 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 +0 -1
- package/lib/Signal/Group/sender-key-message.js.map +1 -1
- package/lib/Signal/Group/sender-key-record.d.ts +1 -1
- package/lib/Signal/Group/sender-key-record.d.ts.map +1 -1
- package/lib/Signal/Group/sender-key-record.js +2 -11
- package/lib/Signal/Group/sender-key-record.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 +21 -33
- 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 +0 -1
- package/lib/Signal/Group/sender-message-key.js.map +1 -1
- package/lib/Signal/libsignal.d.ts +4 -3
- package/lib/Signal/libsignal.d.ts.map +1 -1
- package/lib/Signal/libsignal.js +243 -42
- package/lib/Signal/libsignal.js.map +1 -1
- package/lib/Signal/lid-mapping.d.ts +23 -0
- package/lib/Signal/lid-mapping.d.ts.map +1 -0
- package/lib/Signal/lid-mapping.js +171 -0
- package/lib/Signal/lid-mapping.js.map +1 -0
- package/lib/Socket/Client/types.d.ts +2 -2
- package/lib/Socket/Client/types.d.ts.map +1 -1
- package/lib/Socket/Client/websocket.d.ts +2 -2
- package/lib/Socket/Client/websocket.d.ts.map +1 -1
- package/lib/Socket/Client/websocket.js +2 -2
- package/lib/Socket/Client/websocket.js.map +1 -1
- package/lib/Socket/business.d.ts +31 -17
- 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 +17 -9
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +54 -23
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +41 -14
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/communities.js +83 -3
- package/lib/Socket/communities.js.map +1 -1
- package/lib/Socket/groups.d.ts +16 -9
- package/lib/Socket/groups.d.ts.map +1 -1
- package/lib/Socket/groups.js +14 -11
- package/lib/Socket/groups.js.map +1 -1
- package/lib/Socket/index.d.ts +41 -14
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/index.js +1 -0
- package/lib/Socket/index.js.map +1 -1
- package/lib/Socket/messages-recv.d.ts +26 -16
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +512 -311
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +27 -16
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +394 -133
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +18 -12
- 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 +13 -3
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +353 -78
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +12 -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 +8 -5
- package/lib/Types/Events.d.ts.map +1 -1
- package/lib/Types/GroupMetadata.d.ts +7 -4
- package/lib/Types/GroupMetadata.d.ts.map +1 -1
- package/lib/Types/Message.d.ts +38 -12
- 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 +18 -0
- package/lib/Types/Signal.d.ts.map +1 -1
- package/lib/Types/Socket.d.ts +24 -13
- package/lib/Types/Socket.d.ts.map +1 -1
- package/lib/Types/Socket.js.map +1 -1
- package/lib/Utils/auth-utils.d.ts +2 -2
- package/lib/Utils/auth-utils.d.ts.map +1 -1
- package/lib/Utils/auth-utils.js +178 -111
- package/lib/Utils/auth-utils.js.map +1 -1
- package/lib/Utils/browser-utils.d.ts +4 -0
- package/lib/Utils/browser-utils.d.ts.map +1 -0
- package/lib/Utils/browser-utils.js +28 -0
- package/lib/Utils/browser-utils.js.map +1 -0
- package/lib/Utils/chat-utils.d.ts +6 -7
- package/lib/Utils/chat-utils.d.ts.map +1 -1
- package/lib/Utils/chat-utils.js +19 -2
- package/lib/Utils/chat-utils.js.map +1 -1
- package/lib/Utils/crypto.d.ts +6 -6
- package/lib/Utils/crypto.d.ts.map +1 -1
- package/lib/Utils/crypto.js +16 -12
- package/lib/Utils/crypto.js.map +1 -1
- package/lib/Utils/decode-wa-message.d.ts +14 -2
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +104 -15
- 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 +65 -20
- package/lib/Utils/event-buffer.js.map +1 -1
- package/lib/Utils/generics.d.ts +5 -7
- package/lib/Utils/generics.d.ts.map +1 -1
- package/lib/Utils/generics.js +59 -51
- package/lib/Utils/generics.js.map +1 -1
- package/lib/Utils/history.d.ts +8 -9
- package/lib/Utils/history.d.ts.map +1 -1
- package/lib/Utils/history.js +8 -3
- package/lib/Utils/history.js.map +1 -1
- package/lib/Utils/index.d.ts +2 -1
- package/lib/Utils/index.d.ts.map +1 -1
- package/lib/Utils/index.js +2 -1
- package/lib/Utils/index.js.map +1 -1
- package/lib/Utils/link-preview.d.ts +1 -2
- package/lib/Utils/link-preview.d.ts.map +1 -1
- package/lib/Utils/link-preview.js +1 -1
- package/lib/Utils/link-preview.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 +172 -0
- package/lib/Utils/message-retry-manager.js.map +1 -0
- package/lib/Utils/messages-media.d.ts +14 -12
- package/lib/Utils/messages-media.d.ts.map +1 -1
- package/lib/Utils/messages-media.js +48 -24
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts +17 -4
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +85 -21
- package/lib/Utils/messages.js.map +1 -1
- package/lib/Utils/noise-handler.js +2 -1
- package/lib/Utils/noise-handler.js.map +1 -1
- package/lib/Utils/pre-key-manager.d.ts +28 -0
- package/lib/Utils/pre-key-manager.d.ts.map +1 -0
- package/lib/Utils/pre-key-manager.js +106 -0
- package/lib/Utils/pre-key-manager.js.map +1 -0
- package/lib/Utils/process-message.d.ts +26 -8
- package/lib/Utils/process-message.d.ts.map +1 -1
- package/lib/Utils/process-message.js +141 -24
- package/lib/Utils/process-message.js.map +1 -1
- package/lib/Utils/signal.d.ts +4 -4
- package/lib/Utils/signal.d.ts.map +1 -1
- package/lib/Utils/signal.js +21 -12
- package/lib/Utils/signal.js.map +1 -1
- package/lib/Utils/validate-connection.d.ts.map +1 -1
- package/lib/Utils/validate-connection.js +50 -14
- package/lib/Utils/validate-connection.js.map +1 -1
- package/lib/WABinary/decode.d.ts.map +1 -1
- package/lib/WABinary/decode.js +12 -2
- package/lib/WABinary/decode.js.map +1 -1
- package/lib/WABinary/generic-utils.js +1 -1
- package/lib/WABinary/generic-utils.js.map +1 -1
- package/lib/WABinary/jid-utils.d.ts +18 -6
- package/lib/WABinary/jid-utils.d.ts.map +1 -1
- package/lib/WABinary/jid-utils.js +52 -8
- package/lib/WABinary/jid-utils.js.map +1 -1
- package/lib/WAM/constants.d.ts +1 -1
- package/lib/WAM/constants.d.ts.map +1 -1
- package/lib/WAM/constants.js +18516 -10904
- package/lib/WAM/constants.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/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +2 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +1 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +10 -2
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +1 -1
- package/lib/WAUSync/USyncQuery.d.ts +1 -1
- package/lib/WAUSync/USyncQuery.d.ts.map +1 -1
- package/lib/WAUSync/USyncQuery.js +23 -20
- package/lib/WAUSync/USyncQuery.js.map +1 -1
- package/package.json +16 -11
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Signal/Group/queue-job.d.ts +0 -2
- package/lib/Signal/Group/queue-job.d.ts.map +0 -1
- package/lib/Signal/Group/queue-job.js +0 -54
- package/lib/Signal/Group/queue-job.js.map +0 -1
- package/lib/Socket/usync.d.ts +0 -37
- package/lib/Socket/usync.d.ts.map +0 -1
- package/lib/Socket/usync.js +0 -63
- package/lib/Socket/usync.js.map +0 -1
- package/lib/Utils/baileys-event-stream.d.ts +0 -17
- package/lib/Utils/baileys-event-stream.d.ts.map +0 -1
- package/lib/Utils/baileys-event-stream.js +0 -56
- package/lib/Utils/baileys-event-stream.js.map +0 -1
|
@@ -5,15 +5,15 @@ import Long from 'long';
|
|
|
5
5
|
import { proto } from '../../WAProto/index.js';
|
|
6
6
|
import { DEFAULT_CACHE_TTLS, KEY_BUNDLE_TYPE, MIN_PREKEY_COUNT } from '../Defaults/index.js';
|
|
7
7
|
import { WAMessageStatus, WAMessageStubType } from '../Types/index.js';
|
|
8
|
-
import { aesDecryptCTR, aesEncryptGCM, cleanMessage, Curve, decodeMediaRetryNode, decodeMessageNode, decryptMessageNode, delay, derivePairingCodeKey, encodeBigEndian, encodeSignedDeviceIdentity, getCallStatusFromNode, getHistoryMsg, getNextPreKeys, getStatusFromReceiptType, hkdf, MISSING_KEYS_ERROR_TEXT, NACK_REASONS,
|
|
8
|
+
import { aesDecryptCTR, aesEncryptGCM, cleanMessage, Curve, decodeMediaRetryNode, decodeMessageNode, decryptMessageNode, delay, derivePairingCodeKey, encodeBigEndian, encodeSignedDeviceIdentity, extractAddressingContext, getCallStatusFromNode, getHistoryMsg, getNextPreKeys, getStatusFromReceiptType, hkdf, MISSING_KEYS_ERROR_TEXT, NACK_REASONS, 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,
|
|
10
|
+
import { areJidsSameUser, binaryNodeToString, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString, isJidGroup, isJidNewsletter, isJidStatusBroadcast, isLidUser, isPnUser, 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 ||
|
|
@@ -31,7 +31,190 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
31
31
|
stdTTL: DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
|
|
32
32
|
useClones: false
|
|
33
33
|
});
|
|
34
|
+
// Debounce identity-change session refreshes per JID to avoid bursts
|
|
35
|
+
const identityAssertDebounce = new NodeCache({ stdTTL: 5, useClones: false });
|
|
34
36
|
let sendActiveReceipts = false;
|
|
37
|
+
const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
|
|
38
|
+
if (!authState.creds.me?.id) {
|
|
39
|
+
throw new Boom('Not authenticated');
|
|
40
|
+
}
|
|
41
|
+
const pdoMessage = {
|
|
42
|
+
historySyncOnDemandRequest: {
|
|
43
|
+
chatJid: oldestMsgKey.remoteJid,
|
|
44
|
+
oldestMsgFromMe: oldestMsgKey.fromMe,
|
|
45
|
+
oldestMsgId: oldestMsgKey.id,
|
|
46
|
+
oldestMsgTimestampMs: oldestMsgTimestamp,
|
|
47
|
+
onDemandMsgCount: count
|
|
48
|
+
},
|
|
49
|
+
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
|
|
50
|
+
};
|
|
51
|
+
return sendPeerDataOperationMessage(pdoMessage);
|
|
52
|
+
};
|
|
53
|
+
const requestPlaceholderResend = async (messageKey) => {
|
|
54
|
+
if (!authState.creds.me?.id) {
|
|
55
|
+
throw new Boom('Not authenticated');
|
|
56
|
+
}
|
|
57
|
+
if (placeholderResendCache.get(messageKey?.id)) {
|
|
58
|
+
logger.debug({ messageKey }, 'already requested resend');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
await placeholderResendCache.set(messageKey?.id, true);
|
|
63
|
+
}
|
|
64
|
+
await delay(5000);
|
|
65
|
+
if (!placeholderResendCache.get(messageKey?.id)) {
|
|
66
|
+
logger.debug({ messageKey }, 'message received while resend requested');
|
|
67
|
+
return 'RESOLVED';
|
|
68
|
+
}
|
|
69
|
+
const pdoMessage = {
|
|
70
|
+
placeholderMessageResendRequest: [
|
|
71
|
+
{
|
|
72
|
+
messageKey
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
|
|
76
|
+
};
|
|
77
|
+
setTimeout(async () => {
|
|
78
|
+
if (placeholderResendCache.get(messageKey?.id)) {
|
|
79
|
+
logger.debug({ messageKey }, 'PDO message without response after 15 seconds. Phone possibly offline');
|
|
80
|
+
await placeholderResendCache.del(messageKey?.id);
|
|
81
|
+
}
|
|
82
|
+
}, 15000);
|
|
83
|
+
return sendPeerDataOperationMessage(pdoMessage);
|
|
84
|
+
};
|
|
85
|
+
// Handles mex newsletter notifications
|
|
86
|
+
const handleMexNewsletterNotification = async (node) => {
|
|
87
|
+
const mexNode = getBinaryNodeChild(node, 'mex');
|
|
88
|
+
if (!mexNode?.content) {
|
|
89
|
+
logger.warn({ node }, 'Invalid mex newsletter notification');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
let data;
|
|
93
|
+
try {
|
|
94
|
+
data = JSON.parse(mexNode.content.toString());
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
logger.error({ err: error, node }, 'Failed to parse mex newsletter notification');
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const operation = data?.operation;
|
|
101
|
+
const updates = data?.updates;
|
|
102
|
+
if (!updates || !operation) {
|
|
103
|
+
logger.warn({ data }, 'Invalid mex newsletter notification content');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
logger.info({ operation, updates }, 'got mex newsletter notification');
|
|
107
|
+
switch (operation) {
|
|
108
|
+
case 'NotificationNewsletterUpdate':
|
|
109
|
+
for (const update of updates) {
|
|
110
|
+
if (update.jid && update.settings && Object.keys(update.settings).length > 0) {
|
|
111
|
+
ev.emit('newsletter-settings.update', {
|
|
112
|
+
id: update.jid,
|
|
113
|
+
update: update.settings
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
case 'NotificationNewsletterAdminPromote':
|
|
119
|
+
for (const update of updates) {
|
|
120
|
+
if (update.jid && update.user) {
|
|
121
|
+
ev.emit('newsletter-participants.update', {
|
|
122
|
+
id: update.jid,
|
|
123
|
+
author: node.attrs.from,
|
|
124
|
+
user: update.user,
|
|
125
|
+
new_role: 'ADMIN',
|
|
126
|
+
action: 'promote'
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
default:
|
|
132
|
+
logger.info({ operation, data }, 'Unhandled mex newsletter notification');
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
// Handles newsletter notifications
|
|
137
|
+
const handleNewsletterNotification = async (node) => {
|
|
138
|
+
const from = node.attrs.from;
|
|
139
|
+
const child = getAllBinaryNodeChildren(node)[0];
|
|
140
|
+
const author = node.attrs.participant;
|
|
141
|
+
logger.info({ from, child }, 'got newsletter notification');
|
|
142
|
+
switch (child.tag) {
|
|
143
|
+
case 'reaction':
|
|
144
|
+
const reactionUpdate = {
|
|
145
|
+
id: from,
|
|
146
|
+
server_id: child.attrs.message_id,
|
|
147
|
+
reaction: {
|
|
148
|
+
code: getBinaryNodeChildString(child, 'reaction'),
|
|
149
|
+
count: 1
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
ev.emit('newsletter.reaction', reactionUpdate);
|
|
153
|
+
break;
|
|
154
|
+
case 'view':
|
|
155
|
+
const viewUpdate = {
|
|
156
|
+
id: from,
|
|
157
|
+
server_id: child.attrs.message_id,
|
|
158
|
+
count: parseInt(child.content?.toString() || '0', 10)
|
|
159
|
+
};
|
|
160
|
+
ev.emit('newsletter.view', viewUpdate);
|
|
161
|
+
break;
|
|
162
|
+
case 'participant':
|
|
163
|
+
const participantUpdate = {
|
|
164
|
+
id: from,
|
|
165
|
+
author,
|
|
166
|
+
user: child.attrs.jid,
|
|
167
|
+
action: child.attrs.action,
|
|
168
|
+
new_role: child.attrs.role
|
|
169
|
+
};
|
|
170
|
+
ev.emit('newsletter-participants.update', participantUpdate);
|
|
171
|
+
break;
|
|
172
|
+
case 'update':
|
|
173
|
+
const settingsNode = getBinaryNodeChild(child, 'settings');
|
|
174
|
+
if (settingsNode) {
|
|
175
|
+
const update = {};
|
|
176
|
+
const nameNode = getBinaryNodeChild(settingsNode, 'name');
|
|
177
|
+
if (nameNode?.content)
|
|
178
|
+
update.name = nameNode.content.toString();
|
|
179
|
+
const descriptionNode = getBinaryNodeChild(settingsNode, 'description');
|
|
180
|
+
if (descriptionNode?.content)
|
|
181
|
+
update.description = descriptionNode.content.toString();
|
|
182
|
+
ev.emit('newsletter-settings.update', {
|
|
183
|
+
id: from,
|
|
184
|
+
update
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
break;
|
|
188
|
+
case 'message':
|
|
189
|
+
const plaintextNode = getBinaryNodeChild(child, 'plaintext');
|
|
190
|
+
if (plaintextNode?.content) {
|
|
191
|
+
try {
|
|
192
|
+
const contentBuf = typeof plaintextNode.content === 'string'
|
|
193
|
+
? Buffer.from(plaintextNode.content, 'binary')
|
|
194
|
+
: Buffer.from(plaintextNode.content);
|
|
195
|
+
const messageProto = proto.Message.decode(contentBuf).toJSON();
|
|
196
|
+
const fullMessage = proto.WebMessageInfo.fromObject({
|
|
197
|
+
key: {
|
|
198
|
+
remoteJid: from,
|
|
199
|
+
id: child.attrs.message_id || child.attrs.server_id,
|
|
200
|
+
fromMe: false // TODO: is this really true though
|
|
201
|
+
},
|
|
202
|
+
message: messageProto,
|
|
203
|
+
messageTimestamp: +child.attrs.t
|
|
204
|
+
}).toJSON();
|
|
205
|
+
await upsertMessage(fullMessage, 'append');
|
|
206
|
+
logger.info('Processed plaintext newsletter message');
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
logger.error({ error }, 'Failed to decode plaintext newsletter message');
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
213
|
+
default:
|
|
214
|
+
logger.warn({ node }, 'Unknown newsletter notification');
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
35
218
|
const sendMessageAck = async ({ tag, attrs, content }, errorCode) => {
|
|
36
219
|
const stanza = {
|
|
37
220
|
tag: 'ack',
|
|
@@ -85,20 +268,76 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
85
268
|
const { fullMessage } = decodeMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '');
|
|
86
269
|
const { key: msgKey } = fullMessage;
|
|
87
270
|
const msgId = msgKey.id;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
271
|
+
if (messageRetryManager) {
|
|
272
|
+
// Check if we've exceeded max retries using the new system
|
|
273
|
+
if (messageRetryManager.hasExceededMaxRetries(msgId)) {
|
|
274
|
+
logger.debug({ msgId }, 'reached retry limit with new retry manager, clearing');
|
|
275
|
+
messageRetryManager.markRetryFailed(msgId);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
// Increment retry count using new system
|
|
279
|
+
const retryCount = messageRetryManager.incrementRetryCount(msgId);
|
|
280
|
+
// Use the new retry count for the rest of the logic
|
|
281
|
+
const key = `${msgId}:${msgKey?.participant}`;
|
|
282
|
+
await msgRetryCache.set(key, retryCount);
|
|
94
283
|
}
|
|
95
|
-
|
|
96
|
-
|
|
284
|
+
else {
|
|
285
|
+
// Fallback to old system
|
|
286
|
+
const key = `${msgId}:${msgKey?.participant}`;
|
|
287
|
+
let retryCount = (await msgRetryCache.get(key)) || 0;
|
|
288
|
+
if (retryCount >= maxMsgRetryCount) {
|
|
289
|
+
logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
|
|
290
|
+
await msgRetryCache.del(key);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
retryCount += 1;
|
|
294
|
+
await msgRetryCache.set(key, retryCount);
|
|
295
|
+
}
|
|
296
|
+
const key = `${msgId}:${msgKey?.participant}`;
|
|
297
|
+
const retryCount = (await msgRetryCache.get(key)) || 1;
|
|
97
298
|
const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
299
|
+
const fromJid = node.attrs.from;
|
|
300
|
+
// Check if we should recreate the session
|
|
301
|
+
let shouldRecreateSession = false;
|
|
302
|
+
let recreateReason = '';
|
|
303
|
+
if (enableAutoSessionRecreation && messageRetryManager) {
|
|
304
|
+
try {
|
|
305
|
+
// Check if we have a session with this JID
|
|
306
|
+
const sessionId = signalRepository.jidToSignalProtocolAddress(fromJid);
|
|
307
|
+
const hasSession = await signalRepository.validateSession(fromJid);
|
|
308
|
+
const result = messageRetryManager.shouldRecreateSession(fromJid, retryCount, hasSession.exists);
|
|
309
|
+
shouldRecreateSession = result.recreate;
|
|
310
|
+
recreateReason = result.reason;
|
|
311
|
+
if (shouldRecreateSession) {
|
|
312
|
+
logger.debug({ fromJid, retryCount, reason: recreateReason }, 'recreating session for retry');
|
|
313
|
+
// Delete existing session to force recreation
|
|
314
|
+
await authState.keys.set({ session: { [sessionId]: null } });
|
|
315
|
+
forceIncludeKeys = true;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
logger.warn({ error, fromJid }, 'failed to check session recreation');
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (retryCount <= 2) {
|
|
323
|
+
// Use new retry manager for phone requests if available
|
|
324
|
+
if (messageRetryManager) {
|
|
325
|
+
// Schedule phone request with delay (like whatsmeow)
|
|
326
|
+
messageRetryManager.schedulePhoneRequest(msgId, async () => {
|
|
327
|
+
try {
|
|
328
|
+
const requestId = await requestPlaceholderResend(msgKey);
|
|
329
|
+
logger.debug(`sendRetryRequest: requested placeholder resend (${requestId}) for message ${msgId} (scheduled)`);
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
logger.warn({ error, msgId }, 'failed to send scheduled phone request');
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
// Fallback to immediate request
|
|
338
|
+
const msgId = await requestPlaceholderResend(msgKey);
|
|
339
|
+
logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId}`);
|
|
340
|
+
}
|
|
102
341
|
}
|
|
103
342
|
const deviceIdentity = encodeSignedDeviceIdentity(account, true);
|
|
104
343
|
await authState.keys.transaction(async () => {
|
|
@@ -116,7 +355,9 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
116
355
|
count: retryCount.toString(),
|
|
117
356
|
id: node.attrs.id,
|
|
118
357
|
t: node.attrs.t,
|
|
119
|
-
v: '1'
|
|
358
|
+
v: '1',
|
|
359
|
+
// ADD ERROR FIELD
|
|
360
|
+
error: '0'
|
|
120
361
|
}
|
|
121
362
|
},
|
|
122
363
|
{
|
|
@@ -132,7 +373,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
132
373
|
if (node.attrs.participant) {
|
|
133
374
|
receipt.attrs.participant = node.attrs.participant;
|
|
134
375
|
}
|
|
135
|
-
if (retryCount > 1 || forceIncludeKeys) {
|
|
376
|
+
if (retryCount > 1 || forceIncludeKeys || shouldRecreateSession) {
|
|
136
377
|
const { update, preKeys } = await getNextPreKeys(authState, 1);
|
|
137
378
|
const [keyId] = Object.keys(preKeys);
|
|
138
379
|
const key = preKeys[+keyId];
|
|
@@ -152,7 +393,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
152
393
|
}
|
|
153
394
|
await sendNode(receipt);
|
|
154
395
|
logger.info({ msgAttrs: node.attrs, retryCount }, 'sent retry receipt');
|
|
155
|
-
});
|
|
396
|
+
}, authState?.creds?.me?.id || 'sendRetryRequest');
|
|
156
397
|
};
|
|
157
398
|
const handleEncryptNotification = async (node) => {
|
|
158
399
|
const from = node.attrs.from;
|
|
@@ -169,22 +410,35 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
169
410
|
const identityNode = getBinaryNodeChild(node, 'identity');
|
|
170
411
|
if (identityNode) {
|
|
171
412
|
logger.info({ jid: from }, 'identity changed');
|
|
172
|
-
|
|
173
|
-
|
|
413
|
+
if (identityAssertDebounce.get(from)) {
|
|
414
|
+
logger.debug({ jid: from }, 'skipping identity assert (debounced)');
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
identityAssertDebounce.set(from, true);
|
|
418
|
+
try {
|
|
419
|
+
await assertSessions([from], true);
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
logger.warn({ error, jid: from }, 'failed to assert sessions after identity change');
|
|
423
|
+
}
|
|
174
424
|
}
|
|
175
425
|
else {
|
|
176
426
|
logger.info({ node }, 'unknown encrypt notification');
|
|
177
427
|
}
|
|
178
428
|
}
|
|
179
429
|
};
|
|
180
|
-
const handleGroupNotification = (
|
|
181
|
-
|
|
430
|
+
const handleGroupNotification = (fullNode, child, msg) => {
|
|
431
|
+
// TODO: Support PN/LID (Here is only LID now)
|
|
432
|
+
const actingParticipantLid = fullNode.attrs.participant;
|
|
433
|
+
const actingParticipantPn = fullNode.attrs.participant_pn;
|
|
434
|
+
const affectedParticipantLid = getBinaryNodeChild(child, 'participant')?.attrs?.jid || actingParticipantLid;
|
|
435
|
+
const affectedParticipantPn = getBinaryNodeChild(child, 'participant')?.attrs?.phone_number || actingParticipantPn;
|
|
182
436
|
switch (child?.tag) {
|
|
183
437
|
case 'create':
|
|
184
438
|
const metadata = extractGroupMetadata(child);
|
|
185
439
|
msg.messageStubType = WAMessageStubType.GROUP_CREATE;
|
|
186
440
|
msg.messageStubParameters = [metadata.subject];
|
|
187
|
-
msg.key = { participant: metadata.owner };
|
|
441
|
+
msg.key = { participant: metadata.owner, participantAlt: metadata.ownerPn };
|
|
188
442
|
ev.emit('chats.upsert', [
|
|
189
443
|
{
|
|
190
444
|
id: metadata.id,
|
|
@@ -195,7 +449,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
195
449
|
ev.emit('groups.upsert', [
|
|
196
450
|
{
|
|
197
451
|
...metadata,
|
|
198
|
-
author:
|
|
452
|
+
author: actingParticipantLid,
|
|
453
|
+
authorPn: actingParticipantPn
|
|
199
454
|
}
|
|
200
455
|
]);
|
|
201
456
|
break;
|
|
@@ -220,15 +475,24 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
220
475
|
case 'leave':
|
|
221
476
|
const stubType = `GROUP_PARTICIPANT_${child.tag.toUpperCase()}`;
|
|
222
477
|
msg.messageStubType = WAMessageStubType[stubType];
|
|
223
|
-
const participants = getBinaryNodeChildren(child, 'participant').map(
|
|
478
|
+
const participants = getBinaryNodeChildren(child, 'participant').map(({ attrs }) => {
|
|
479
|
+
// TODO: Store LID MAPPINGS
|
|
480
|
+
return {
|
|
481
|
+
id: attrs.jid,
|
|
482
|
+
phoneNumber: isLidUser(attrs.jid) && isPnUser(attrs.phone_number) ? attrs.phone_number : undefined,
|
|
483
|
+
lid: isPnUser(attrs.jid) && isLidUser(attrs.lid) ? attrs.lid : undefined,
|
|
484
|
+
admin: (attrs.type || null)
|
|
485
|
+
};
|
|
486
|
+
});
|
|
224
487
|
if (participants.length === 1 &&
|
|
225
488
|
// if recv. "remove" message and sender removed themselves
|
|
226
489
|
// mark as left
|
|
227
|
-
areJidsSameUser(participants[0],
|
|
490
|
+
(areJidsSameUser(participants[0].id, actingParticipantLid) ||
|
|
491
|
+
areJidsSameUser(participants[0].id, actingParticipantPn)) &&
|
|
228
492
|
child.tag === 'remove') {
|
|
229
493
|
msg.messageStubType = WAMessageStubType.GROUP_PARTICIPANT_LEAVE;
|
|
230
494
|
}
|
|
231
|
-
msg.messageStubParameters = participants;
|
|
495
|
+
msg.messageStubParameters = participants.map(a => JSON.stringify(a));
|
|
232
496
|
break;
|
|
233
497
|
case 'subject':
|
|
234
498
|
msg.messageStubType = WAMessageStubType.GROUP_CHANGE_SUBJECT;
|
|
@@ -269,12 +533,20 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
269
533
|
break;
|
|
270
534
|
case 'created_membership_requests':
|
|
271
535
|
msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
|
|
272
|
-
msg.messageStubParameters = [
|
|
536
|
+
msg.messageStubParameters = [
|
|
537
|
+
JSON.stringify({ lid: affectedParticipantLid, pn: affectedParticipantPn }),
|
|
538
|
+
'created',
|
|
539
|
+
child.attrs.request_method
|
|
540
|
+
];
|
|
273
541
|
break;
|
|
274
542
|
case 'revoked_membership_requests':
|
|
275
|
-
const isDenied = areJidsSameUser(
|
|
543
|
+
const isDenied = areJidsSameUser(affectedParticipantLid, actingParticipantLid);
|
|
544
|
+
// TODO: LIDMAPPING SUPPORT
|
|
276
545
|
msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
|
|
277
|
-
msg.messageStubParameters = [
|
|
546
|
+
msg.messageStubParameters = [
|
|
547
|
+
JSON.stringify({ lid: affectedParticipantLid, pn: affectedParticipantPn }),
|
|
548
|
+
isDenied ? 'revoked' : 'rejected'
|
|
549
|
+
];
|
|
278
550
|
break;
|
|
279
551
|
}
|
|
280
552
|
};
|
|
@@ -304,7 +576,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
304
576
|
await handleMexNewsletterNotification(node);
|
|
305
577
|
break;
|
|
306
578
|
case 'w:gp2':
|
|
307
|
-
|
|
579
|
+
// TODO: HANDLE PARTICIPANT_PN
|
|
580
|
+
handleGroupNotification(node, child, result);
|
|
308
581
|
break;
|
|
309
582
|
case 'mediaretry':
|
|
310
583
|
const event = decodeMediaRetryNode(node);
|
|
@@ -315,10 +588,12 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
315
588
|
break;
|
|
316
589
|
case 'devices':
|
|
317
590
|
const devices = getBinaryNodeChildren(child, 'device');
|
|
318
|
-
if (areJidsSameUser(child.attrs.jid, authState.creds.me.id)
|
|
319
|
-
|
|
320
|
-
|
|
591
|
+
if (areJidsSameUser(child.attrs.jid, authState.creds.me.id) ||
|
|
592
|
+
areJidsSameUser(child.attrs.lid, authState.creds.me.lid)) {
|
|
593
|
+
const deviceData = devices.map(d => ({ id: d.attrs.jid, lid: d.attrs.lid }));
|
|
594
|
+
logger.info({ deviceData }, 'my own devices changed');
|
|
321
595
|
}
|
|
596
|
+
//TODO: drop a new event, add hashes
|
|
322
597
|
break;
|
|
323
598
|
case 'server_sync':
|
|
324
599
|
const update = getBinaryNodeChild(node, 'collection');
|
|
@@ -434,11 +709,37 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
434
709
|
});
|
|
435
710
|
authState.creds.registered = true;
|
|
436
711
|
ev.emit('creds.update', authState.creds);
|
|
712
|
+
break;
|
|
713
|
+
case 'privacy_token':
|
|
714
|
+
await handlePrivacyTokenNotification(node);
|
|
715
|
+
break;
|
|
437
716
|
}
|
|
438
717
|
if (Object.keys(result).length) {
|
|
439
718
|
return result;
|
|
440
719
|
}
|
|
441
720
|
};
|
|
721
|
+
const handlePrivacyTokenNotification = async (node) => {
|
|
722
|
+
const tokensNode = getBinaryNodeChild(node, 'tokens');
|
|
723
|
+
const from = jidNormalizedUser(node.attrs.from);
|
|
724
|
+
if (!tokensNode)
|
|
725
|
+
return;
|
|
726
|
+
const tokenNodes = getBinaryNodeChildren(tokensNode, 'token');
|
|
727
|
+
for (const tokenNode of tokenNodes) {
|
|
728
|
+
const { attrs, content } = tokenNode;
|
|
729
|
+
const type = attrs.type;
|
|
730
|
+
const timestamp = attrs.t;
|
|
731
|
+
if (type === 'trusted_contact' && content instanceof Buffer) {
|
|
732
|
+
logger.debug({
|
|
733
|
+
from,
|
|
734
|
+
timestamp,
|
|
735
|
+
tcToken: content
|
|
736
|
+
}, 'received trusted contact token');
|
|
737
|
+
await authState.keys.set({
|
|
738
|
+
tctoken: { [from]: { token: content, timestamp } }
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
};
|
|
442
743
|
async function decipherLinkPublicKey(data) {
|
|
443
744
|
const buffer = toRequiredBuffer(data);
|
|
444
745
|
const salt = buffer.slice(0, 32);
|
|
@@ -453,33 +754,80 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
453
754
|
}
|
|
454
755
|
return data instanceof Buffer ? data : Buffer.from(data);
|
|
455
756
|
}
|
|
456
|
-
const willSendMessageAgain = (id, participant) => {
|
|
757
|
+
const willSendMessageAgain = async (id, participant) => {
|
|
457
758
|
const key = `${id}:${participant}`;
|
|
458
|
-
const retryCount = msgRetryCache.get(key) || 0;
|
|
759
|
+
const retryCount = (await msgRetryCache.get(key)) || 0;
|
|
459
760
|
return retryCount < maxMsgRetryCount;
|
|
460
761
|
};
|
|
461
|
-
const updateSendMessageAgainCount = (id, participant) => {
|
|
762
|
+
const updateSendMessageAgainCount = async (id, participant) => {
|
|
462
763
|
const key = `${id}:${participant}`;
|
|
463
|
-
const newValue = (msgRetryCache.get(key) || 0) + 1;
|
|
464
|
-
msgRetryCache.set(key, newValue);
|
|
764
|
+
const newValue = ((await msgRetryCache.get(key)) || 0) + 1;
|
|
765
|
+
await msgRetryCache.set(key, newValue);
|
|
465
766
|
};
|
|
466
767
|
const sendMessagesAgain = async (key, ids, retryNode) => {
|
|
467
|
-
// todo: implement a cache to store the last 256 sent messages (copy whatsmeow)
|
|
468
|
-
const msgs = await Promise.all(ids.map(id => getMessage({ ...key, id })));
|
|
469
768
|
const remoteJid = key.remoteJid;
|
|
470
769
|
const participant = key.participant || remoteJid;
|
|
770
|
+
const retryCount = +retryNode.attrs.count || 1;
|
|
771
|
+
// Try to get messages from cache first, then fallback to getMessage
|
|
772
|
+
const msgs = [];
|
|
773
|
+
for (const id of ids) {
|
|
774
|
+
let msg;
|
|
775
|
+
// Try to get from retry cache first if enabled
|
|
776
|
+
if (messageRetryManager) {
|
|
777
|
+
const cachedMsg = messageRetryManager.getRecentMessage(remoteJid, id);
|
|
778
|
+
if (cachedMsg) {
|
|
779
|
+
msg = cachedMsg.message;
|
|
780
|
+
logger.debug({ jid: remoteJid, id }, 'found message in retry cache');
|
|
781
|
+
// Mark retry as successful since we found the message
|
|
782
|
+
messageRetryManager.markRetrySuccess(id);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
// Fallback to getMessage if not found in cache
|
|
786
|
+
if (!msg) {
|
|
787
|
+
msg = await getMessage({ ...key, id });
|
|
788
|
+
if (msg) {
|
|
789
|
+
logger.debug({ jid: remoteJid, id }, 'found message via getMessage');
|
|
790
|
+
// Also mark as successful if found via getMessage
|
|
791
|
+
if (messageRetryManager) {
|
|
792
|
+
messageRetryManager.markRetrySuccess(id);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
msgs.push(msg);
|
|
797
|
+
}
|
|
471
798
|
// if it's the primary jid sending the request
|
|
472
799
|
// just re-send the message to everyone
|
|
473
800
|
// prevents the first message decryption failure
|
|
474
801
|
const sendToAll = !jidDecode(participant)?.device;
|
|
802
|
+
// Check if we should recreate session for this retry
|
|
803
|
+
let shouldRecreateSession = false;
|
|
804
|
+
let recreateReason = '';
|
|
805
|
+
if (enableAutoSessionRecreation && messageRetryManager) {
|
|
806
|
+
try {
|
|
807
|
+
const sessionId = signalRepository.jidToSignalProtocolAddress(participant);
|
|
808
|
+
const hasSession = await signalRepository.validateSession(participant);
|
|
809
|
+
const result = messageRetryManager.shouldRecreateSession(participant, retryCount, hasSession.exists);
|
|
810
|
+
shouldRecreateSession = result.recreate;
|
|
811
|
+
recreateReason = result.reason;
|
|
812
|
+
if (shouldRecreateSession) {
|
|
813
|
+
logger.debug({ participant, retryCount, reason: recreateReason }, 'recreating session for outgoing retry');
|
|
814
|
+
await authState.keys.set({ session: { [sessionId]: null } });
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
catch (error) {
|
|
818
|
+
logger.warn({ error, participant }, 'failed to check session recreation for outgoing retry');
|
|
819
|
+
}
|
|
820
|
+
}
|
|
475
821
|
await assertSessions([participant], true);
|
|
476
822
|
if (isJidGroup(remoteJid)) {
|
|
477
823
|
await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } });
|
|
478
824
|
}
|
|
479
|
-
logger.debug({ participant, sendToAll }, 'forced new session for retry recp');
|
|
825
|
+
logger.debug({ participant, sendToAll, shouldRecreateSession, recreateReason }, 'forced new session for retry recp');
|
|
480
826
|
for (const [i, msg] of msgs.entries()) {
|
|
481
|
-
if (
|
|
482
|
-
|
|
827
|
+
if (!ids[i])
|
|
828
|
+
continue;
|
|
829
|
+
if (msg && (await willSendMessageAgain(ids[i], participant))) {
|
|
830
|
+
await updateSendMessageAgainCount(ids[i], participant);
|
|
483
831
|
const msgRelayOpts = { messageId: ids[i] };
|
|
484
832
|
if (sendToAll) {
|
|
485
833
|
msgRelayOpts.useUserDevicesCache = false;
|
|
@@ -509,7 +857,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
509
857
|
fromMe,
|
|
510
858
|
participant: attrs.participant
|
|
511
859
|
};
|
|
512
|
-
if (shouldIgnoreJid(remoteJid) && remoteJid !==
|
|
860
|
+
if (shouldIgnoreJid(remoteJid) && remoteJid !== S_WHATSAPP_NET) {
|
|
513
861
|
logger.debug({ remoteJid }, 'ignoring receipt from jid');
|
|
514
862
|
await sendMessageAck(node);
|
|
515
863
|
return;
|
|
@@ -550,14 +898,15 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
550
898
|
// correctly set who is asking for the retry
|
|
551
899
|
key.participant = key.participant || attrs.from;
|
|
552
900
|
const retryNode = getBinaryNodeChild(node, 'retry');
|
|
553
|
-
if (willSendMessageAgain(ids[0], key.participant)) {
|
|
901
|
+
if (ids[0] && key.participant && (await willSendMessageAgain(ids[0], key.participant))) {
|
|
554
902
|
if (key.fromMe) {
|
|
555
903
|
try {
|
|
904
|
+
await updateSendMessageAgainCount(ids[0], key.participant);
|
|
556
905
|
logger.debug({ attrs, key }, 'recv retry request');
|
|
557
906
|
await sendMessagesAgain(key, ids, retryNode);
|
|
558
907
|
}
|
|
559
908
|
catch (error) {
|
|
560
|
-
logger.error({ key, ids, trace: error.stack }, 'error in sending message again');
|
|
909
|
+
logger.error({ key, ids, trace: error instanceof Error ? error.stack : 'Unknown error' }, 'error in sending message again');
|
|
561
910
|
}
|
|
562
911
|
}
|
|
563
912
|
else {
|
|
@@ -577,7 +926,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
577
926
|
};
|
|
578
927
|
const handleNotification = async (node) => {
|
|
579
928
|
const remoteJid = node.attrs.from;
|
|
580
|
-
if (shouldIgnoreJid(remoteJid) && remoteJid !==
|
|
929
|
+
if (shouldIgnoreJid(remoteJid) && remoteJid !== S_WHATSAPP_NET) {
|
|
581
930
|
logger.debug({ remoteJid, id: node.attrs.id }, 'ignored notification');
|
|
582
931
|
await sendMessageAck(node);
|
|
583
932
|
return;
|
|
@@ -588,10 +937,13 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
588
937
|
const msg = await processNotification(node);
|
|
589
938
|
if (msg) {
|
|
590
939
|
const fromMe = areJidsSameUser(node.attrs.participant || remoteJid, authState.creds.me.id);
|
|
940
|
+
const { senderAlt: participantAlt, addressingMode } = extractAddressingContext(node);
|
|
591
941
|
msg.key = {
|
|
592
942
|
remoteJid,
|
|
593
943
|
fromMe,
|
|
594
944
|
participant: node.attrs.participant,
|
|
945
|
+
participantAlt,
|
|
946
|
+
addressingMode,
|
|
595
947
|
id: node.attrs.id,
|
|
596
948
|
...(msg.key || {})
|
|
597
949
|
};
|
|
@@ -608,67 +960,97 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
608
960
|
}
|
|
609
961
|
};
|
|
610
962
|
const handleMessage = async (node) => {
|
|
611
|
-
if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !==
|
|
963
|
+
if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !== S_WHATSAPP_NET) {
|
|
612
964
|
logger.debug({ key: node.attrs.key }, 'ignored message');
|
|
613
|
-
await sendMessageAck(node);
|
|
965
|
+
await sendMessageAck(node, NACK_REASONS.UnhandledError);
|
|
614
966
|
return;
|
|
615
967
|
}
|
|
616
968
|
const encNode = getBinaryNodeChild(node, 'enc');
|
|
617
969
|
// TODO: temporary fix for crashes and issues resulting of failed msmsg decryption
|
|
618
970
|
if (encNode && encNode.attrs.type === 'msmsg') {
|
|
619
971
|
logger.debug({ key: node.attrs.key }, 'ignored msmsg');
|
|
620
|
-
await sendMessageAck(node);
|
|
972
|
+
await sendMessageAck(node, NACK_REASONS.MissingMessageSecret);
|
|
621
973
|
return;
|
|
622
974
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
975
|
+
const { fullMessage: msg, category, author, decrypt } = decryptMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
|
|
976
|
+
const alt = msg.key.participantAlt || msg.key.remoteJidAlt;
|
|
977
|
+
// store new mappings we didn't have before
|
|
978
|
+
if (!!alt) {
|
|
979
|
+
const altServer = jidDecode(alt)?.server;
|
|
980
|
+
const primaryJid = msg.key.participant || msg.key.remoteJid;
|
|
981
|
+
if (altServer === 'lid') {
|
|
982
|
+
if (!(await signalRepository.lidMapping.getPNForLID(alt))) {
|
|
983
|
+
await signalRepository.lidMapping.storeLIDPNMappings([{ lid: alt, pn: primaryJid }]);
|
|
984
|
+
await signalRepository.migrateSession(primaryJid, alt);
|
|
985
|
+
}
|
|
630
986
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (placeholderResendCache.get(node.attrs.id)) {
|
|
635
|
-
placeholderResendCache.del(node.attrs.id);
|
|
987
|
+
else {
|
|
988
|
+
await signalRepository.lidMapping.storeLIDPNMappings([{ lid: primaryJid, pn: alt }]);
|
|
989
|
+
await signalRepository.migrateSession(alt, primaryJid);
|
|
636
990
|
}
|
|
637
991
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
|
|
992
|
+
if (msg.key?.remoteJid && msg.key?.id && messageRetryManager) {
|
|
993
|
+
messageRetryManager.addRecentMessage(msg.key.remoteJid, msg.key.id, msg.message);
|
|
994
|
+
logger.debug({
|
|
995
|
+
jid: msg.key.remoteJid,
|
|
996
|
+
id: msg.key.id
|
|
997
|
+
}, 'Added message to recent cache for retry receipts');
|
|
645
998
|
}
|
|
646
999
|
try {
|
|
647
|
-
await
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
if (msg
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
1000
|
+
await processingMutex.mutex(async () => {
|
|
1001
|
+
await decrypt();
|
|
1002
|
+
// message failed to decrypt
|
|
1003
|
+
if (msg.messageStubType === proto.WebMessageInfo.StubType.CIPHERTEXT && msg.category !== 'peer') {
|
|
1004
|
+
if (msg?.messageStubParameters?.[0] === MISSING_KEYS_ERROR_TEXT) {
|
|
1005
|
+
return sendMessageAck(node, NACK_REASONS.ParsingError);
|
|
1006
|
+
}
|
|
1007
|
+
const errorMessage = msg?.messageStubParameters?.[0] || '';
|
|
1008
|
+
const isPreKeyError = errorMessage.includes('PreKey');
|
|
1009
|
+
logger.debug(`[handleMessage] Attempting retry request for failed decryption`);
|
|
1010
|
+
// Handle both pre-key and normal retries in single mutex
|
|
1011
|
+
await retryMutex.mutex(async () => {
|
|
1012
|
+
try {
|
|
1013
|
+
if (!ws.isOpen) {
|
|
1014
|
+
logger.debug({ node }, 'Connection closed, skipping retry');
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
// Handle pre-key errors with upload and delay
|
|
1018
|
+
if (isPreKeyError) {
|
|
1019
|
+
logger.info({ error: errorMessage }, 'PreKey error detected, uploading and retrying');
|
|
1020
|
+
try {
|
|
1021
|
+
logger.debug('Uploading pre-keys for error recovery');
|
|
1022
|
+
await uploadPreKeys(5);
|
|
1023
|
+
logger.debug('Waiting for server to process new pre-keys');
|
|
1024
|
+
await delay(1000);
|
|
1025
|
+
}
|
|
1026
|
+
catch (uploadErr) {
|
|
1027
|
+
logger.error({ uploadErr }, 'Pre-key upload failed, proceeding with retry anyway');
|
|
659
1028
|
}
|
|
1029
|
+
}
|
|
1030
|
+
const encNode = getBinaryNodeChild(node, 'enc');
|
|
1031
|
+
await sendRetryRequest(node, !encNode);
|
|
1032
|
+
if (retryRequestDelayMs) {
|
|
1033
|
+
await delay(retryRequestDelayMs);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
catch (err) {
|
|
1037
|
+
logger.error({ err, isPreKeyError }, 'Failed to handle retry, attempting basic retry');
|
|
1038
|
+
// Still attempt retry even if pre-key upload failed
|
|
1039
|
+
try {
|
|
660
1040
|
const encNode = getBinaryNodeChild(node, 'enc');
|
|
661
1041
|
await sendRetryRequest(node, !encNode);
|
|
662
|
-
if (retryRequestDelayMs) {
|
|
663
|
-
await delay(retryRequestDelayMs);
|
|
664
|
-
}
|
|
665
1042
|
}
|
|
666
|
-
|
|
667
|
-
logger.
|
|
1043
|
+
catch (retryErr) {
|
|
1044
|
+
logger.error({ retryErr }, 'Failed to send retry after error handling');
|
|
668
1045
|
}
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
|
|
1046
|
+
}
|
|
1047
|
+
await sendMessageAck(node, NACK_REASONS.UnhandledError);
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
else {
|
|
1051
|
+
await sendMessageAck(node);
|
|
1052
|
+
const isNewsletter = isJidNewsletter(msg.key.remoteJid);
|
|
1053
|
+
if (!isNewsletter) {
|
|
672
1054
|
// no type in the receipt => message delivered
|
|
673
1055
|
let type = undefined;
|
|
674
1056
|
let participant = msg.key.participant;
|
|
@@ -680,8 +1062,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
680
1062
|
// message was sent by us from a different device
|
|
681
1063
|
type = 'sender';
|
|
682
1064
|
// need to specially handle this case
|
|
683
|
-
if (
|
|
684
|
-
participant = author;
|
|
1065
|
+
if (isLidUser(msg.key.remoteJid) || isLidUser(msg.key.remoteJidAlt)) {
|
|
1066
|
+
participant = author; // TODO: investigate sending receipts to LIDs and not PNs
|
|
685
1067
|
}
|
|
686
1068
|
}
|
|
687
1069
|
else if (!sendActiveReceipts) {
|
|
@@ -695,89 +1077,27 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
695
1077
|
await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync');
|
|
696
1078
|
}
|
|
697
1079
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
}
|
|
702
|
-
|
|
1080
|
+
else {
|
|
1081
|
+
logger.debug({ key: msg.key }, 'processed newsletter message without receipts');
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
cleanMessage(msg, authState.creds.me.id, authState.creds.me.lid);
|
|
1085
|
+
await upsertMessage(msg, node.attrs.offline ? 'append' : 'notify');
|
|
1086
|
+
});
|
|
703
1087
|
}
|
|
704
1088
|
catch (error) {
|
|
705
|
-
logger.error({ error, node }, 'error in handling message');
|
|
1089
|
+
logger.error({ error, node: binaryNodeToString(node) }, 'error in handling message');
|
|
706
1090
|
}
|
|
707
1091
|
};
|
|
708
|
-
const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
|
|
709
|
-
if (!authState.creds.me?.id) {
|
|
710
|
-
throw new Boom('Not authenticated');
|
|
711
|
-
}
|
|
712
|
-
const pdoMessage = {
|
|
713
|
-
historySyncOnDemandRequest: {
|
|
714
|
-
chatJid: oldestMsgKey.remoteJid,
|
|
715
|
-
oldestMsgFromMe: oldestMsgKey.fromMe,
|
|
716
|
-
oldestMsgId: oldestMsgKey.id,
|
|
717
|
-
oldestMsgTimestampMs: oldestMsgTimestamp,
|
|
718
|
-
onDemandMsgCount: count
|
|
719
|
-
},
|
|
720
|
-
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
|
|
721
|
-
};
|
|
722
|
-
return sendPeerDataOperationMessage(pdoMessage);
|
|
723
|
-
};
|
|
724
|
-
const requestPlaceholderResend = async (messageKey) => {
|
|
725
|
-
if (!authState.creds.me?.id) {
|
|
726
|
-
throw new Boom('Not authenticated');
|
|
727
|
-
}
|
|
728
|
-
if (placeholderResendCache.get(messageKey?.id)) {
|
|
729
|
-
logger.debug({ messageKey }, 'already requested resend');
|
|
730
|
-
return;
|
|
731
|
-
}
|
|
732
|
-
else {
|
|
733
|
-
placeholderResendCache.set(messageKey?.id, true);
|
|
734
|
-
}
|
|
735
|
-
await delay(5000);
|
|
736
|
-
if (!placeholderResendCache.get(messageKey?.id)) {
|
|
737
|
-
logger.debug({ messageKey }, 'message received while resend requested');
|
|
738
|
-
return 'RESOLVED';
|
|
739
|
-
}
|
|
740
|
-
const pdoMessage = {
|
|
741
|
-
placeholderMessageResendRequest: [
|
|
742
|
-
{
|
|
743
|
-
messageKey
|
|
744
|
-
}
|
|
745
|
-
],
|
|
746
|
-
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
|
|
747
|
-
};
|
|
748
|
-
setTimeout(() => {
|
|
749
|
-
if (placeholderResendCache.get(messageKey?.id)) {
|
|
750
|
-
logger.debug({ messageKey }, 'PDO message without response after 15 seconds. Phone possibly offline');
|
|
751
|
-
placeholderResendCache.del(messageKey?.id);
|
|
752
|
-
}
|
|
753
|
-
}, 15000);
|
|
754
|
-
return sendPeerDataOperationMessage(pdoMessage);
|
|
755
|
-
};
|
|
756
1092
|
const handleCall = async (node) => {
|
|
757
|
-
let status;
|
|
758
1093
|
const { attrs } = node;
|
|
759
1094
|
const [infoChild] = getAllBinaryNodeChildren(node);
|
|
1095
|
+
const status = getCallStatusFromNode(infoChild);
|
|
760
1096
|
if (!infoChild) {
|
|
761
1097
|
throw new Boom('Missing call info in call node');
|
|
762
1098
|
}
|
|
763
1099
|
const callId = infoChild.attrs['call-id'];
|
|
764
1100
|
const from = infoChild.attrs.from || infoChild.attrs['call-creator'];
|
|
765
|
-
status = getCallStatusFromNode(infoChild);
|
|
766
|
-
if (isLidUser(from) && infoChild.tag === 'relaylatency') {
|
|
767
|
-
const verify = callOfferCache.get(callId);
|
|
768
|
-
if (!verify) {
|
|
769
|
-
status = 'offer';
|
|
770
|
-
const callLid = {
|
|
771
|
-
chatId: attrs.from,
|
|
772
|
-
from,
|
|
773
|
-
id: callId,
|
|
774
|
-
date: new Date(+attrs.t * 1000),
|
|
775
|
-
offline: !!attrs.offline,
|
|
776
|
-
status
|
|
777
|
-
};
|
|
778
|
-
callOfferCache.set(callId, callLid);
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
1101
|
const call = {
|
|
782
1102
|
chatId: attrs.from,
|
|
783
1103
|
from,
|
|
@@ -790,9 +1110,9 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
790
1110
|
call.isVideo = !!getBinaryNodeChild(infoChild, 'video');
|
|
791
1111
|
call.isGroup = infoChild.attrs.type === 'group' || !!infoChild.attrs['group-jid'];
|
|
792
1112
|
call.groupJid = infoChild.attrs['group-jid'];
|
|
793
|
-
callOfferCache.set(call.id, call);
|
|
1113
|
+
await callOfferCache.set(call.id, call);
|
|
794
1114
|
}
|
|
795
|
-
const existingCall = callOfferCache.get(call.id);
|
|
1115
|
+
const existingCall = await callOfferCache.get(call.id);
|
|
796
1116
|
// use existing call info to populate this event
|
|
797
1117
|
if (existingCall) {
|
|
798
1118
|
call.isVideo = existingCall.isVideo;
|
|
@@ -800,7 +1120,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
800
1120
|
}
|
|
801
1121
|
// delete data once call has ended
|
|
802
1122
|
if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
|
|
803
|
-
callOfferCache.del(call.id);
|
|
1123
|
+
await callOfferCache.del(call.id);
|
|
804
1124
|
}
|
|
805
1125
|
ev.emit('call', [call]);
|
|
806
1126
|
await sendMessageAck(node);
|
|
@@ -833,6 +1153,19 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
833
1153
|
}
|
|
834
1154
|
}
|
|
835
1155
|
]);
|
|
1156
|
+
// resend the message with device_fanout=false, use at your own risk
|
|
1157
|
+
// if (attrs.error === '475') {
|
|
1158
|
+
// const msg = await getMessage(key)
|
|
1159
|
+
// if (msg) {
|
|
1160
|
+
// await relayMessage(key.remoteJid!, msg, {
|
|
1161
|
+
// messageId: key.id!,
|
|
1162
|
+
// useUserDevicesCache: false,
|
|
1163
|
+
// additionalAttributes: {
|
|
1164
|
+
// device_fanout: 'false'
|
|
1165
|
+
// }
|
|
1166
|
+
// })
|
|
1167
|
+
// }
|
|
1168
|
+
// }
|
|
836
1169
|
}
|
|
837
1170
|
};
|
|
838
1171
|
/// processes a node with the given function
|
|
@@ -877,165 +1210,32 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
877
1210
|
return { enqueue };
|
|
878
1211
|
};
|
|
879
1212
|
const offlineNodeProcessor = makeOfflineNodeProcessor();
|
|
880
|
-
const processNode = (type, node, identifier, exec) => {
|
|
1213
|
+
const processNode = async (type, node, identifier, exec) => {
|
|
881
1214
|
const isOffline = !!node.attrs.offline;
|
|
882
1215
|
if (isOffline) {
|
|
883
1216
|
offlineNodeProcessor.enqueue(type, node);
|
|
884
1217
|
}
|
|
885
1218
|
else {
|
|
886
|
-
processNodeWithBuffer(node, identifier, exec);
|
|
1219
|
+
await processNodeWithBuffer(node, identifier, exec);
|
|
887
1220
|
}
|
|
888
1221
|
};
|
|
889
|
-
// Handles newsletter notifications
|
|
890
|
-
async function handleNewsletterNotification(node) {
|
|
891
|
-
const from = node.attrs.from;
|
|
892
|
-
const child = getAllBinaryNodeChildren(node)[0];
|
|
893
|
-
const author = node.attrs.participant;
|
|
894
|
-
logger.info({ from, child }, 'got newsletter notification');
|
|
895
|
-
switch (child.tag) {
|
|
896
|
-
case 'reaction':
|
|
897
|
-
const reactionUpdate = {
|
|
898
|
-
id: from,
|
|
899
|
-
server_id: child.attrs.message_id,
|
|
900
|
-
reaction: {
|
|
901
|
-
code: getBinaryNodeChildString(child, 'reaction'),
|
|
902
|
-
count: 1
|
|
903
|
-
}
|
|
904
|
-
};
|
|
905
|
-
ev.emit('newsletter.reaction', reactionUpdate);
|
|
906
|
-
break;
|
|
907
|
-
case 'view':
|
|
908
|
-
const viewUpdate = {
|
|
909
|
-
id: from,
|
|
910
|
-
server_id: child.attrs.message_id,
|
|
911
|
-
count: parseInt(child.content?.toString() || '0', 10)
|
|
912
|
-
};
|
|
913
|
-
ev.emit('newsletter.view', viewUpdate);
|
|
914
|
-
break;
|
|
915
|
-
case 'participant':
|
|
916
|
-
const participantUpdate = {
|
|
917
|
-
id: from,
|
|
918
|
-
author,
|
|
919
|
-
user: child.attrs.jid,
|
|
920
|
-
action: child.attrs.action,
|
|
921
|
-
new_role: child.attrs.role
|
|
922
|
-
};
|
|
923
|
-
ev.emit('newsletter-participants.update', participantUpdate);
|
|
924
|
-
break;
|
|
925
|
-
case 'update':
|
|
926
|
-
const settingsNode = getBinaryNodeChild(child, 'settings');
|
|
927
|
-
if (settingsNode) {
|
|
928
|
-
const update = {};
|
|
929
|
-
const nameNode = getBinaryNodeChild(settingsNode, 'name');
|
|
930
|
-
if (nameNode?.content)
|
|
931
|
-
update.name = nameNode.content.toString();
|
|
932
|
-
const descriptionNode = getBinaryNodeChild(settingsNode, 'description');
|
|
933
|
-
if (descriptionNode?.content)
|
|
934
|
-
update.description = descriptionNode.content.toString();
|
|
935
|
-
ev.emit('newsletter-settings.update', {
|
|
936
|
-
id: from,
|
|
937
|
-
update
|
|
938
|
-
});
|
|
939
|
-
}
|
|
940
|
-
break;
|
|
941
|
-
case 'message':
|
|
942
|
-
const plaintextNode = getBinaryNodeChild(child, 'plaintext');
|
|
943
|
-
if (plaintextNode?.content) {
|
|
944
|
-
try {
|
|
945
|
-
const contentBuf = typeof plaintextNode.content === 'string'
|
|
946
|
-
? Buffer.from(plaintextNode.content, 'binary')
|
|
947
|
-
: Buffer.from(plaintextNode.content);
|
|
948
|
-
const messageProto = proto.Message.decode(contentBuf);
|
|
949
|
-
const fullMessage = proto.WebMessageInfo.fromObject({
|
|
950
|
-
key: {
|
|
951
|
-
remoteJid: from,
|
|
952
|
-
id: child.attrs.message_id || child.attrs.server_id,
|
|
953
|
-
fromMe: false
|
|
954
|
-
},
|
|
955
|
-
message: messageProto,
|
|
956
|
-
messageTimestamp: +child.attrs.t
|
|
957
|
-
});
|
|
958
|
-
await upsertMessage(fullMessage, 'append');
|
|
959
|
-
logger.info('Processed plaintext newsletter message');
|
|
960
|
-
}
|
|
961
|
-
catch (error) {
|
|
962
|
-
logger.error({ error }, 'Failed to decode plaintext newsletter message');
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
break;
|
|
966
|
-
default:
|
|
967
|
-
logger.warn({ node }, 'Unknown newsletter notification');
|
|
968
|
-
break;
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
// Handles mex newsletter notifications
|
|
972
|
-
async function handleMexNewsletterNotification(node) {
|
|
973
|
-
const mexNode = getBinaryNodeChild(node, 'mex');
|
|
974
|
-
if (!mexNode?.content) {
|
|
975
|
-
logger.warn({ node }, 'Invalid mex newsletter notification');
|
|
976
|
-
return;
|
|
977
|
-
}
|
|
978
|
-
let data;
|
|
979
|
-
try {
|
|
980
|
-
data = JSON.parse(mexNode.content.toString());
|
|
981
|
-
}
|
|
982
|
-
catch (error) {
|
|
983
|
-
logger.error({ err: error, node }, 'Failed to parse mex newsletter notification');
|
|
984
|
-
return;
|
|
985
|
-
}
|
|
986
|
-
const operation = data?.operation;
|
|
987
|
-
const updates = data?.updates;
|
|
988
|
-
if (!updates || !operation) {
|
|
989
|
-
logger.warn({ data }, 'Invalid mex newsletter notification content');
|
|
990
|
-
return;
|
|
991
|
-
}
|
|
992
|
-
logger.info({ operation, updates }, 'got mex newsletter notification');
|
|
993
|
-
switch (operation) {
|
|
994
|
-
case 'NotificationNewsletterUpdate':
|
|
995
|
-
for (const update of updates) {
|
|
996
|
-
if (update.jid && update.settings && Object.keys(update.settings).length > 0) {
|
|
997
|
-
ev.emit('newsletter-settings.update', {
|
|
998
|
-
id: update.jid,
|
|
999
|
-
update: update.settings
|
|
1000
|
-
});
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
break;
|
|
1004
|
-
case 'NotificationNewsletterAdminPromote':
|
|
1005
|
-
for (const update of updates) {
|
|
1006
|
-
if (update.jid && update.user) {
|
|
1007
|
-
ev.emit('newsletter-participants.update', {
|
|
1008
|
-
id: update.jid,
|
|
1009
|
-
author: node.attrs.from,
|
|
1010
|
-
user: update.user,
|
|
1011
|
-
new_role: 'ADMIN',
|
|
1012
|
-
action: 'promote'
|
|
1013
|
-
});
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
break;
|
|
1017
|
-
default:
|
|
1018
|
-
logger.info({ operation, data }, 'Unhandled mex newsletter notification');
|
|
1019
|
-
break;
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
1222
|
// recv a message
|
|
1023
|
-
ws.on('CB:message', (node) => {
|
|
1024
|
-
processNode('message', node, 'processing message', handleMessage);
|
|
1223
|
+
ws.on('CB:message', async (node) => {
|
|
1224
|
+
await processNode('message', node, 'processing message', handleMessage);
|
|
1025
1225
|
});
|
|
1026
1226
|
ws.on('CB:call', async (node) => {
|
|
1027
|
-
processNode('call', node, 'handling call', handleCall);
|
|
1227
|
+
await processNode('call', node, 'handling call', handleCall);
|
|
1028
1228
|
});
|
|
1029
|
-
ws.on('CB:receipt', node => {
|
|
1030
|
-
processNode('receipt', node, 'handling receipt', handleReceipt);
|
|
1229
|
+
ws.on('CB:receipt', async (node) => {
|
|
1230
|
+
await processNode('receipt', node, 'handling receipt', handleReceipt);
|
|
1031
1231
|
});
|
|
1032
1232
|
ws.on('CB:notification', async (node) => {
|
|
1033
|
-
processNode('notification', node, 'handling notification', handleNotification);
|
|
1233
|
+
await processNode('notification', node, 'handling notification', handleNotification);
|
|
1034
1234
|
});
|
|
1035
1235
|
ws.on('CB:ack,class:message', (node) => {
|
|
1036
1236
|
handleBadAck(node).catch(error => onUnexpectedError(error, 'handling bad ack'));
|
|
1037
1237
|
});
|
|
1038
|
-
ev.on('call', ([call]) => {
|
|
1238
|
+
ev.on('call', async ([call]) => {
|
|
1039
1239
|
if (!call) {
|
|
1040
1240
|
return;
|
|
1041
1241
|
}
|
|
@@ -1063,7 +1263,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1063
1263
|
msg.message = { call: { callKey: Buffer.from(call.id) } };
|
|
1064
1264
|
}
|
|
1065
1265
|
const protoMsg = proto.WebMessageInfo.fromObject(msg);
|
|
1066
|
-
upsertMessage(protoMsg, call.offline ? 'append' : 'notify');
|
|
1266
|
+
await upsertMessage(protoMsg, call.offline ? 'append' : 'notify');
|
|
1067
1267
|
}
|
|
1068
1268
|
});
|
|
1069
1269
|
ev.on('connection.update', ({ isOnline }) => {
|
|
@@ -1078,7 +1278,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1078
1278
|
sendRetryRequest,
|
|
1079
1279
|
rejectCall,
|
|
1080
1280
|
fetchMessageHistory,
|
|
1081
|
-
requestPlaceholderResend
|
|
1281
|
+
requestPlaceholderResend,
|
|
1282
|
+
messageRetryManager
|
|
1082
1283
|
};
|
|
1083
1284
|
};
|
|
1084
1285
|
//# sourceMappingURL=messages-recv.js.map
|