@d0v3riz/baileys 6.7.24 → 7.0.0-rc.6
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 +23 -8
- 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/business.d.ts +29 -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 +15 -9
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +49 -20
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +39 -14
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/communities.js +82 -2
- package/lib/Socket/communities.js.map +1 -1
- package/lib/Socket/groups.d.ts +14 -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 +39 -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 +24 -16
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +463 -319
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +25 -16
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +365 -125
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +16 -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 +11 -3
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +305 -71
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +8 -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 +99 -14
- 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 +63 -18
- 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 +58 -50
- 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 -0
- package/lib/Utils/index.d.ts.map +1 -1
- package/lib/Utils/index.js +2 -0
- 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 +149 -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 +47 -23
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts +4 -4
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +55 -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 +8 -8
- package/lib/Utils/process-message.d.ts.map +1 -1
- package/lib/Utils/process-message.js +68 -23
- 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
|
@@ -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, isJidStatusBroadcast,
|
|
10
|
+
import { areJidsSameUser, binaryNodeToString, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString, isJidGroup, 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 ||
|
|
@@ -32,6 +32,187 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
32
32
|
useClones: false
|
|
33
33
|
});
|
|
34
34
|
let sendActiveReceipts = false;
|
|
35
|
+
const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
|
|
36
|
+
if (!authState.creds.me?.id) {
|
|
37
|
+
throw new Boom('Not authenticated');
|
|
38
|
+
}
|
|
39
|
+
const pdoMessage = {
|
|
40
|
+
historySyncOnDemandRequest: {
|
|
41
|
+
chatJid: oldestMsgKey.remoteJid,
|
|
42
|
+
oldestMsgFromMe: oldestMsgKey.fromMe,
|
|
43
|
+
oldestMsgId: oldestMsgKey.id,
|
|
44
|
+
oldestMsgTimestampMs: oldestMsgTimestamp,
|
|
45
|
+
onDemandMsgCount: count
|
|
46
|
+
},
|
|
47
|
+
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
|
|
48
|
+
};
|
|
49
|
+
return sendPeerDataOperationMessage(pdoMessage);
|
|
50
|
+
};
|
|
51
|
+
const requestPlaceholderResend = async (messageKey) => {
|
|
52
|
+
if (!authState.creds.me?.id) {
|
|
53
|
+
throw new Boom('Not authenticated');
|
|
54
|
+
}
|
|
55
|
+
if (placeholderResendCache.get(messageKey?.id)) {
|
|
56
|
+
logger.debug({ messageKey }, 'already requested resend');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
placeholderResendCache.set(messageKey?.id, true);
|
|
61
|
+
}
|
|
62
|
+
await delay(5000);
|
|
63
|
+
if (!placeholderResendCache.get(messageKey?.id)) {
|
|
64
|
+
logger.debug({ messageKey }, 'message received while resend requested');
|
|
65
|
+
return 'RESOLVED';
|
|
66
|
+
}
|
|
67
|
+
const pdoMessage = {
|
|
68
|
+
placeholderMessageResendRequest: [
|
|
69
|
+
{
|
|
70
|
+
messageKey
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
|
|
74
|
+
};
|
|
75
|
+
setTimeout(() => {
|
|
76
|
+
if (placeholderResendCache.get(messageKey?.id)) {
|
|
77
|
+
logger.debug({ messageKey }, 'PDO message without response after 15 seconds. Phone possibly offline');
|
|
78
|
+
placeholderResendCache.del(messageKey?.id);
|
|
79
|
+
}
|
|
80
|
+
}, 15000);
|
|
81
|
+
return sendPeerDataOperationMessage(pdoMessage);
|
|
82
|
+
};
|
|
83
|
+
// Handles mex newsletter notifications
|
|
84
|
+
const handleMexNewsletterNotification = async (node) => {
|
|
85
|
+
const mexNode = getBinaryNodeChild(node, 'mex');
|
|
86
|
+
if (!mexNode?.content) {
|
|
87
|
+
logger.warn({ node }, 'Invalid mex newsletter notification');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
let data;
|
|
91
|
+
try {
|
|
92
|
+
data = JSON.parse(mexNode.content.toString());
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
logger.error({ err: error, node }, 'Failed to parse mex newsletter notification');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const operation = data?.operation;
|
|
99
|
+
const updates = data?.updates;
|
|
100
|
+
if (!updates || !operation) {
|
|
101
|
+
logger.warn({ data }, 'Invalid mex newsletter notification content');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
logger.info({ operation, updates }, 'got mex newsletter notification');
|
|
105
|
+
switch (operation) {
|
|
106
|
+
case 'NotificationNewsletterUpdate':
|
|
107
|
+
for (const update of updates) {
|
|
108
|
+
if (update.jid && update.settings && Object.keys(update.settings).length > 0) {
|
|
109
|
+
ev.emit('newsletter-settings.update', {
|
|
110
|
+
id: update.jid,
|
|
111
|
+
update: update.settings
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
116
|
+
case 'NotificationNewsletterAdminPromote':
|
|
117
|
+
for (const update of updates) {
|
|
118
|
+
if (update.jid && update.user) {
|
|
119
|
+
ev.emit('newsletter-participants.update', {
|
|
120
|
+
id: update.jid,
|
|
121
|
+
author: node.attrs.from,
|
|
122
|
+
user: update.user,
|
|
123
|
+
new_role: 'ADMIN',
|
|
124
|
+
action: 'promote'
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
break;
|
|
129
|
+
default:
|
|
130
|
+
logger.info({ operation, data }, 'Unhandled mex newsletter notification');
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
// Handles newsletter notifications
|
|
135
|
+
const handleNewsletterNotification = async (node) => {
|
|
136
|
+
const from = node.attrs.from;
|
|
137
|
+
const child = getAllBinaryNodeChildren(node)[0];
|
|
138
|
+
const author = node.attrs.participant;
|
|
139
|
+
logger.info({ from, child }, 'got newsletter notification');
|
|
140
|
+
switch (child.tag) {
|
|
141
|
+
case 'reaction':
|
|
142
|
+
const reactionUpdate = {
|
|
143
|
+
id: from,
|
|
144
|
+
server_id: child.attrs.message_id,
|
|
145
|
+
reaction: {
|
|
146
|
+
code: getBinaryNodeChildString(child, 'reaction'),
|
|
147
|
+
count: 1
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
ev.emit('newsletter.reaction', reactionUpdate);
|
|
151
|
+
break;
|
|
152
|
+
case 'view':
|
|
153
|
+
const viewUpdate = {
|
|
154
|
+
id: from,
|
|
155
|
+
server_id: child.attrs.message_id,
|
|
156
|
+
count: parseInt(child.content?.toString() || '0', 10)
|
|
157
|
+
};
|
|
158
|
+
ev.emit('newsletter.view', viewUpdate);
|
|
159
|
+
break;
|
|
160
|
+
case 'participant':
|
|
161
|
+
const participantUpdate = {
|
|
162
|
+
id: from,
|
|
163
|
+
author,
|
|
164
|
+
user: child.attrs.jid,
|
|
165
|
+
action: child.attrs.action,
|
|
166
|
+
new_role: child.attrs.role
|
|
167
|
+
};
|
|
168
|
+
ev.emit('newsletter-participants.update', participantUpdate);
|
|
169
|
+
break;
|
|
170
|
+
case 'update':
|
|
171
|
+
const settingsNode = getBinaryNodeChild(child, 'settings');
|
|
172
|
+
if (settingsNode) {
|
|
173
|
+
const update = {};
|
|
174
|
+
const nameNode = getBinaryNodeChild(settingsNode, 'name');
|
|
175
|
+
if (nameNode?.content)
|
|
176
|
+
update.name = nameNode.content.toString();
|
|
177
|
+
const descriptionNode = getBinaryNodeChild(settingsNode, 'description');
|
|
178
|
+
if (descriptionNode?.content)
|
|
179
|
+
update.description = descriptionNode.content.toString();
|
|
180
|
+
ev.emit('newsletter-settings.update', {
|
|
181
|
+
id: from,
|
|
182
|
+
update
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
break;
|
|
186
|
+
case 'message':
|
|
187
|
+
const plaintextNode = getBinaryNodeChild(child, 'plaintext');
|
|
188
|
+
if (plaintextNode?.content) {
|
|
189
|
+
try {
|
|
190
|
+
const contentBuf = typeof plaintextNode.content === 'string'
|
|
191
|
+
? Buffer.from(plaintextNode.content, 'binary')
|
|
192
|
+
: Buffer.from(plaintextNode.content);
|
|
193
|
+
const messageProto = proto.Message.decode(contentBuf).toJSON();
|
|
194
|
+
const fullMessage = proto.WebMessageInfo.fromObject({
|
|
195
|
+
key: {
|
|
196
|
+
remoteJid: from,
|
|
197
|
+
id: child.attrs.message_id || child.attrs.server_id,
|
|
198
|
+
fromMe: false // TODO: is this really true though
|
|
199
|
+
},
|
|
200
|
+
message: messageProto,
|
|
201
|
+
messageTimestamp: +child.attrs.t
|
|
202
|
+
}).toJSON();
|
|
203
|
+
await upsertMessage(fullMessage, 'append');
|
|
204
|
+
logger.info('Processed plaintext newsletter message');
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
logger.error({ error }, 'Failed to decode plaintext newsletter message');
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
break;
|
|
211
|
+
default:
|
|
212
|
+
logger.warn({ node }, 'Unknown newsletter notification');
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
35
216
|
const sendMessageAck = async ({ tag, attrs, content }, errorCode) => {
|
|
36
217
|
const stanza = {
|
|
37
218
|
tag: 'ack',
|
|
@@ -85,20 +266,76 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
85
266
|
const { fullMessage } = decodeMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '');
|
|
86
267
|
const { key: msgKey } = fullMessage;
|
|
87
268
|
const msgId = msgKey.id;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
269
|
+
if (messageRetryManager) {
|
|
270
|
+
// Check if we've exceeded max retries using the new system
|
|
271
|
+
if (messageRetryManager.hasExceededMaxRetries(msgId)) {
|
|
272
|
+
logger.debug({ msgId }, 'reached retry limit with new retry manager, clearing');
|
|
273
|
+
messageRetryManager.markRetryFailed(msgId);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
// Increment retry count using new system
|
|
277
|
+
const retryCount = messageRetryManager.incrementRetryCount(msgId);
|
|
278
|
+
// Use the new retry count for the rest of the logic
|
|
279
|
+
const key = `${msgId}:${msgKey?.participant}`;
|
|
280
|
+
msgRetryCache.set(key, retryCount);
|
|
94
281
|
}
|
|
95
|
-
|
|
96
|
-
|
|
282
|
+
else {
|
|
283
|
+
// Fallback to old system
|
|
284
|
+
const key = `${msgId}:${msgKey?.participant}`;
|
|
285
|
+
let retryCount = (await msgRetryCache.get(key)) || 0;
|
|
286
|
+
if (retryCount >= maxMsgRetryCount) {
|
|
287
|
+
logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
|
|
288
|
+
msgRetryCache.del(key);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
retryCount += 1;
|
|
292
|
+
await msgRetryCache.set(key, retryCount);
|
|
293
|
+
}
|
|
294
|
+
const key = `${msgId}:${msgKey?.participant}`;
|
|
295
|
+
const retryCount = (await msgRetryCache.get(key)) || 1;
|
|
97
296
|
const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
297
|
+
const fromJid = node.attrs.from;
|
|
298
|
+
// Check if we should recreate the session
|
|
299
|
+
let shouldRecreateSession = false;
|
|
300
|
+
let recreateReason = '';
|
|
301
|
+
if (enableAutoSessionRecreation && messageRetryManager) {
|
|
302
|
+
try {
|
|
303
|
+
// Check if we have a session with this JID
|
|
304
|
+
const sessionId = signalRepository.jidToSignalProtocolAddress(fromJid);
|
|
305
|
+
const hasSession = await signalRepository.validateSession(fromJid);
|
|
306
|
+
const result = messageRetryManager.shouldRecreateSession(fromJid, retryCount, hasSession.exists);
|
|
307
|
+
shouldRecreateSession = result.recreate;
|
|
308
|
+
recreateReason = result.reason;
|
|
309
|
+
if (shouldRecreateSession) {
|
|
310
|
+
logger.debug({ fromJid, retryCount, reason: recreateReason }, 'recreating session for retry');
|
|
311
|
+
// Delete existing session to force recreation
|
|
312
|
+
await authState.keys.set({ session: { [sessionId]: null } });
|
|
313
|
+
forceIncludeKeys = true;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
logger.warn({ error, fromJid }, 'failed to check session recreation');
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (retryCount <= 2) {
|
|
321
|
+
// Use new retry manager for phone requests if available
|
|
322
|
+
if (messageRetryManager) {
|
|
323
|
+
// Schedule phone request with delay (like whatsmeow)
|
|
324
|
+
messageRetryManager.schedulePhoneRequest(msgId, async () => {
|
|
325
|
+
try {
|
|
326
|
+
const requestId = await requestPlaceholderResend(msgKey);
|
|
327
|
+
logger.debug(`sendRetryRequest: requested placeholder resend (${requestId}) for message ${msgId} (scheduled)`);
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
logger.warn({ error, msgId }, 'failed to send scheduled phone request');
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
// Fallback to immediate request
|
|
336
|
+
const msgId = await requestPlaceholderResend(msgKey);
|
|
337
|
+
logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId}`);
|
|
338
|
+
}
|
|
102
339
|
}
|
|
103
340
|
const deviceIdentity = encodeSignedDeviceIdentity(account, true);
|
|
104
341
|
await authState.keys.transaction(async () => {
|
|
@@ -116,7 +353,9 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
116
353
|
count: retryCount.toString(),
|
|
117
354
|
id: node.attrs.id,
|
|
118
355
|
t: node.attrs.t,
|
|
119
|
-
v: '1'
|
|
356
|
+
v: '1',
|
|
357
|
+
// ADD ERROR FIELD
|
|
358
|
+
error: '0'
|
|
120
359
|
}
|
|
121
360
|
},
|
|
122
361
|
{
|
|
@@ -132,7 +371,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
132
371
|
if (node.attrs.participant) {
|
|
133
372
|
receipt.attrs.participant = node.attrs.participant;
|
|
134
373
|
}
|
|
135
|
-
if (retryCount > 1 || forceIncludeKeys) {
|
|
374
|
+
if (retryCount > 1 || forceIncludeKeys || shouldRecreateSession) {
|
|
136
375
|
const { update, preKeys } = await getNextPreKeys(authState, 1);
|
|
137
376
|
const [keyId] = Object.keys(preKeys);
|
|
138
377
|
const key = preKeys[+keyId];
|
|
@@ -152,7 +391,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
152
391
|
}
|
|
153
392
|
await sendNode(receipt);
|
|
154
393
|
logger.info({ msgAttrs: node.attrs, retryCount }, 'sent retry receipt');
|
|
155
|
-
});
|
|
394
|
+
}, authState?.creds?.me?.id || 'sendRetryRequest');
|
|
156
395
|
};
|
|
157
396
|
const handleEncryptNotification = async (node) => {
|
|
158
397
|
const from = node.attrs.from;
|
|
@@ -177,14 +416,18 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
177
416
|
}
|
|
178
417
|
}
|
|
179
418
|
};
|
|
180
|
-
const handleGroupNotification = (
|
|
181
|
-
|
|
419
|
+
const handleGroupNotification = (fullNode, child, msg) => {
|
|
420
|
+
// TODO: Support PN/LID (Here is only LID now)
|
|
421
|
+
const actingParticipantLid = fullNode.attrs.participant;
|
|
422
|
+
const actingParticipantPn = fullNode.attrs.participant_pn;
|
|
423
|
+
const affectedParticipantLid = getBinaryNodeChild(child, 'participant')?.attrs?.jid || actingParticipantLid;
|
|
424
|
+
const affectedParticipantPn = getBinaryNodeChild(child, 'participant')?.attrs?.phone_number || actingParticipantPn;
|
|
182
425
|
switch (child?.tag) {
|
|
183
426
|
case 'create':
|
|
184
427
|
const metadata = extractGroupMetadata(child);
|
|
185
428
|
msg.messageStubType = WAMessageStubType.GROUP_CREATE;
|
|
186
429
|
msg.messageStubParameters = [metadata.subject];
|
|
187
|
-
msg.key = { participant: metadata.owner };
|
|
430
|
+
msg.key = { participant: metadata.owner, participantAlt: metadata.ownerPn };
|
|
188
431
|
ev.emit('chats.upsert', [
|
|
189
432
|
{
|
|
190
433
|
id: metadata.id,
|
|
@@ -195,7 +438,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
195
438
|
ev.emit('groups.upsert', [
|
|
196
439
|
{
|
|
197
440
|
...metadata,
|
|
198
|
-
author:
|
|
441
|
+
author: actingParticipantLid,
|
|
442
|
+
authorPn: actingParticipantPn
|
|
199
443
|
}
|
|
200
444
|
]);
|
|
201
445
|
break;
|
|
@@ -220,15 +464,24 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
220
464
|
case 'leave':
|
|
221
465
|
const stubType = `GROUP_PARTICIPANT_${child.tag.toUpperCase()}`;
|
|
222
466
|
msg.messageStubType = WAMessageStubType[stubType];
|
|
223
|
-
const participants = getBinaryNodeChildren(child, 'participant').map(
|
|
467
|
+
const participants = getBinaryNodeChildren(child, 'participant').map(({ attrs }) => {
|
|
468
|
+
// TODO: Store LID MAPPINGS
|
|
469
|
+
return {
|
|
470
|
+
id: attrs.jid,
|
|
471
|
+
phoneNumber: isLidUser(attrs.jid) && isPnUser(attrs.phone_number) ? attrs.phone_number : undefined,
|
|
472
|
+
lid: isPnUser(attrs.jid) && isLidUser(attrs.lid) ? attrs.lid : undefined,
|
|
473
|
+
admin: (attrs.type || null)
|
|
474
|
+
};
|
|
475
|
+
});
|
|
224
476
|
if (participants.length === 1 &&
|
|
225
477
|
// if recv. "remove" message and sender removed themselves
|
|
226
478
|
// mark as left
|
|
227
|
-
areJidsSameUser(participants[0],
|
|
479
|
+
(areJidsSameUser(participants[0].id, actingParticipantLid) ||
|
|
480
|
+
areJidsSameUser(participants[0].id, actingParticipantPn)) &&
|
|
228
481
|
child.tag === 'remove') {
|
|
229
482
|
msg.messageStubType = WAMessageStubType.GROUP_PARTICIPANT_LEAVE;
|
|
230
483
|
}
|
|
231
|
-
msg.messageStubParameters = participants;
|
|
484
|
+
msg.messageStubParameters = participants.map(a => JSON.stringify(a));
|
|
232
485
|
break;
|
|
233
486
|
case 'subject':
|
|
234
487
|
msg.messageStubType = WAMessageStubType.GROUP_CHANGE_SUBJECT;
|
|
@@ -269,12 +522,20 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
269
522
|
break;
|
|
270
523
|
case 'created_membership_requests':
|
|
271
524
|
msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
|
|
272
|
-
msg.messageStubParameters = [
|
|
525
|
+
msg.messageStubParameters = [
|
|
526
|
+
JSON.stringify({ lid: affectedParticipantLid, pn: affectedParticipantPn }),
|
|
527
|
+
'created',
|
|
528
|
+
child.attrs.request_method
|
|
529
|
+
];
|
|
273
530
|
break;
|
|
274
531
|
case 'revoked_membership_requests':
|
|
275
|
-
const isDenied = areJidsSameUser(
|
|
532
|
+
const isDenied = areJidsSameUser(affectedParticipantLid, actingParticipantLid);
|
|
533
|
+
// TODO: LIDMAPPING SUPPORT
|
|
276
534
|
msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
|
|
277
|
-
msg.messageStubParameters = [
|
|
535
|
+
msg.messageStubParameters = [
|
|
536
|
+
JSON.stringify({ lid: affectedParticipantLid, pn: affectedParticipantPn }),
|
|
537
|
+
isDenied ? 'revoked' : 'rejected'
|
|
538
|
+
];
|
|
278
539
|
break;
|
|
279
540
|
}
|
|
280
541
|
};
|
|
@@ -304,7 +565,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
304
565
|
await handleMexNewsletterNotification(node);
|
|
305
566
|
break;
|
|
306
567
|
case 'w:gp2':
|
|
307
|
-
|
|
568
|
+
// TODO: HANDLE PARTICIPANT_PN
|
|
569
|
+
handleGroupNotification(node, child, result);
|
|
308
570
|
break;
|
|
309
571
|
case 'mediaretry':
|
|
310
572
|
const event = decodeMediaRetryNode(node);
|
|
@@ -315,10 +577,12 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
315
577
|
break;
|
|
316
578
|
case 'devices':
|
|
317
579
|
const devices = getBinaryNodeChildren(child, 'device');
|
|
318
|
-
if (areJidsSameUser(child.attrs.jid, authState.creds.me.id)
|
|
319
|
-
|
|
320
|
-
|
|
580
|
+
if (areJidsSameUser(child.attrs.jid, authState.creds.me.id) ||
|
|
581
|
+
areJidsSameUser(child.attrs.lid, authState.creds.me.lid)) {
|
|
582
|
+
const deviceData = devices.map(d => ({ id: d.attrs.jid, lid: d.attrs.lid }));
|
|
583
|
+
logger.info({ deviceData }, 'my own devices changed');
|
|
321
584
|
}
|
|
585
|
+
//TODO: drop a new event, add hashes
|
|
322
586
|
break;
|
|
323
587
|
case 'server_sync':
|
|
324
588
|
const update = getBinaryNodeChild(node, 'collection');
|
|
@@ -453,32 +717,79 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
453
717
|
}
|
|
454
718
|
return data instanceof Buffer ? data : Buffer.from(data);
|
|
455
719
|
}
|
|
456
|
-
const willSendMessageAgain = (id, participant) => {
|
|
720
|
+
const willSendMessageAgain = async (id, participant) => {
|
|
457
721
|
const key = `${id}:${participant}`;
|
|
458
|
-
const retryCount = msgRetryCache.get(key) || 0;
|
|
722
|
+
const retryCount = (await msgRetryCache.get(key)) || 0;
|
|
459
723
|
return retryCount < maxMsgRetryCount;
|
|
460
724
|
};
|
|
461
|
-
const updateSendMessageAgainCount = (id, participant) => {
|
|
725
|
+
const updateSendMessageAgainCount = async (id, participant) => {
|
|
462
726
|
const key = `${id}:${participant}`;
|
|
463
|
-
const newValue = (msgRetryCache.get(key) || 0) + 1;
|
|
464
|
-
msgRetryCache.set(key, newValue);
|
|
727
|
+
const newValue = ((await msgRetryCache.get(key)) || 0) + 1;
|
|
728
|
+
await msgRetryCache.set(key, newValue);
|
|
465
729
|
};
|
|
466
730
|
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
731
|
const remoteJid = key.remoteJid;
|
|
470
732
|
const participant = key.participant || remoteJid;
|
|
733
|
+
const retryCount = +retryNode.attrs.count || 1;
|
|
734
|
+
// Try to get messages from cache first, then fallback to getMessage
|
|
735
|
+
const msgs = [];
|
|
736
|
+
for (const id of ids) {
|
|
737
|
+
let msg;
|
|
738
|
+
// Try to get from retry cache first if enabled
|
|
739
|
+
if (messageRetryManager) {
|
|
740
|
+
const cachedMsg = messageRetryManager.getRecentMessage(remoteJid, id);
|
|
741
|
+
if (cachedMsg) {
|
|
742
|
+
msg = cachedMsg.message;
|
|
743
|
+
logger.debug({ jid: remoteJid, id }, 'found message in retry cache');
|
|
744
|
+
// Mark retry as successful since we found the message
|
|
745
|
+
messageRetryManager.markRetrySuccess(id);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
// Fallback to getMessage if not found in cache
|
|
749
|
+
if (!msg) {
|
|
750
|
+
msg = await getMessage({ ...key, id });
|
|
751
|
+
if (msg) {
|
|
752
|
+
logger.debug({ jid: remoteJid, id }, 'found message via getMessage');
|
|
753
|
+
// Also mark as successful if found via getMessage
|
|
754
|
+
if (messageRetryManager) {
|
|
755
|
+
messageRetryManager.markRetrySuccess(id);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
msgs.push(msg);
|
|
760
|
+
}
|
|
471
761
|
// if it's the primary jid sending the request
|
|
472
762
|
// just re-send the message to everyone
|
|
473
763
|
// prevents the first message decryption failure
|
|
474
764
|
const sendToAll = !jidDecode(participant)?.device;
|
|
475
|
-
|
|
765
|
+
// Check if we should recreate session for this retry
|
|
766
|
+
let shouldRecreateSession = false;
|
|
767
|
+
let recreateReason = '';
|
|
768
|
+
if (enableAutoSessionRecreation && messageRetryManager) {
|
|
769
|
+
try {
|
|
770
|
+
const sessionId = signalRepository.jidToSignalProtocolAddress(participant);
|
|
771
|
+
const hasSession = await signalRepository.validateSession(participant);
|
|
772
|
+
const result = messageRetryManager.shouldRecreateSession(participant, retryCount, hasSession.exists);
|
|
773
|
+
shouldRecreateSession = result.recreate;
|
|
774
|
+
recreateReason = result.reason;
|
|
775
|
+
if (shouldRecreateSession) {
|
|
776
|
+
logger.debug({ participant, retryCount, reason: recreateReason }, 'recreating session for outgoing retry');
|
|
777
|
+
await authState.keys.set({ session: { [sessionId]: null } });
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
catch (error) {
|
|
781
|
+
logger.warn({ error, participant }, 'failed to check session recreation for outgoing retry');
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
await assertSessions([participant]);
|
|
476
785
|
if (isJidGroup(remoteJid)) {
|
|
477
786
|
await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } });
|
|
478
787
|
}
|
|
479
|
-
logger.debug({ participant, sendToAll }, 'forced new session for retry recp');
|
|
788
|
+
logger.debug({ participant, sendToAll, shouldRecreateSession, recreateReason }, 'forced new session for retry recp');
|
|
480
789
|
for (const [i, msg] of msgs.entries()) {
|
|
481
|
-
if (
|
|
790
|
+
if (!ids[i])
|
|
791
|
+
continue;
|
|
792
|
+
if (msg && (await willSendMessageAgain(ids[i], participant))) {
|
|
482
793
|
updateSendMessageAgainCount(ids[i], participant);
|
|
483
794
|
const msgRelayOpts = { messageId: ids[i] };
|
|
484
795
|
if (sendToAll) {
|
|
@@ -509,7 +820,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
509
820
|
fromMe,
|
|
510
821
|
participant: attrs.participant
|
|
511
822
|
};
|
|
512
|
-
if (shouldIgnoreJid(remoteJid) && remoteJid !==
|
|
823
|
+
if (shouldIgnoreJid(remoteJid) && remoteJid !== S_WHATSAPP_NET) {
|
|
513
824
|
logger.debug({ remoteJid }, 'ignoring receipt from jid');
|
|
514
825
|
await sendMessageAck(node);
|
|
515
826
|
return;
|
|
@@ -550,14 +861,15 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
550
861
|
// correctly set who is asking for the retry
|
|
551
862
|
key.participant = key.participant || attrs.from;
|
|
552
863
|
const retryNode = getBinaryNodeChild(node, 'retry');
|
|
553
|
-
if (willSendMessageAgain(ids[0], key.participant)) {
|
|
864
|
+
if (ids[0] && key.participant && (await willSendMessageAgain(ids[0], key.participant))) {
|
|
554
865
|
if (key.fromMe) {
|
|
555
866
|
try {
|
|
867
|
+
updateSendMessageAgainCount(ids[0], key.participant);
|
|
556
868
|
logger.debug({ attrs, key }, 'recv retry request');
|
|
557
869
|
await sendMessagesAgain(key, ids, retryNode);
|
|
558
870
|
}
|
|
559
871
|
catch (error) {
|
|
560
|
-
logger.error({ key, ids, trace: error.stack }, 'error in sending message again');
|
|
872
|
+
logger.error({ key, ids, trace: error instanceof Error ? error.stack : 'Unknown error' }, 'error in sending message again');
|
|
561
873
|
}
|
|
562
874
|
}
|
|
563
875
|
else {
|
|
@@ -577,7 +889,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
577
889
|
};
|
|
578
890
|
const handleNotification = async (node) => {
|
|
579
891
|
const remoteJid = node.attrs.from;
|
|
580
|
-
if (shouldIgnoreJid(remoteJid) && remoteJid !==
|
|
892
|
+
if (shouldIgnoreJid(remoteJid) && remoteJid !== S_WHATSAPP_NET) {
|
|
581
893
|
logger.debug({ remoteJid, id: node.attrs.id }, 'ignored notification');
|
|
582
894
|
await sendMessageAck(node);
|
|
583
895
|
return;
|
|
@@ -588,10 +900,13 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
588
900
|
const msg = await processNotification(node);
|
|
589
901
|
if (msg) {
|
|
590
902
|
const fromMe = areJidsSameUser(node.attrs.participant || remoteJid, authState.creds.me.id);
|
|
903
|
+
const { senderAlt: participantAlt, addressingMode } = extractAddressingContext(node);
|
|
591
904
|
msg.key = {
|
|
592
905
|
remoteJid,
|
|
593
906
|
fromMe,
|
|
594
907
|
participant: node.attrs.participant,
|
|
908
|
+
participantAlt,
|
|
909
|
+
addressingMode,
|
|
595
910
|
id: node.attrs.id,
|
|
596
911
|
...(msg.key || {})
|
|
597
912
|
};
|
|
@@ -608,176 +923,137 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
608
923
|
}
|
|
609
924
|
};
|
|
610
925
|
const handleMessage = async (node) => {
|
|
611
|
-
if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !==
|
|
926
|
+
if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !== S_WHATSAPP_NET) {
|
|
612
927
|
logger.debug({ key: node.attrs.key }, 'ignored message');
|
|
613
|
-
await sendMessageAck(node);
|
|
928
|
+
await sendMessageAck(node, NACK_REASONS.UnhandledError);
|
|
614
929
|
return;
|
|
615
930
|
}
|
|
616
931
|
const encNode = getBinaryNodeChild(node, 'enc');
|
|
617
932
|
// TODO: temporary fix for crashes and issues resulting of failed msmsg decryption
|
|
618
933
|
if (encNode && encNode.attrs.type === 'msmsg') {
|
|
619
934
|
logger.debug({ key: node.attrs.key }, 'ignored msmsg');
|
|
620
|
-
await sendMessageAck(node);
|
|
935
|
+
await sendMessageAck(node, NACK_REASONS.MissingMessageSecret);
|
|
621
936
|
return;
|
|
622
937
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
938
|
+
const { fullMessage: msg, category, author, decrypt } = decryptMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
|
|
939
|
+
const alt = msg.key.participantAlt || msg.key.remoteJidAlt;
|
|
940
|
+
// store new mappings we didn't have before
|
|
941
|
+
if (!!alt) {
|
|
942
|
+
const altServer = jidDecode(alt)?.server;
|
|
943
|
+
const primaryJid = msg.key.participant || msg.key.remoteJid;
|
|
944
|
+
if (altServer === 'lid') {
|
|
945
|
+
if (!(await signalRepository.lidMapping.getPNForLID(alt))) {
|
|
946
|
+
await signalRepository.lidMapping.storeLIDPNMappings([{ lid: alt, pn: primaryJid }]);
|
|
947
|
+
await signalRepository.migrateSession(primaryJid, alt);
|
|
948
|
+
}
|
|
630
949
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (placeholderResendCache.get(node.attrs.id)) {
|
|
635
|
-
placeholderResendCache.del(node.attrs.id);
|
|
950
|
+
else {
|
|
951
|
+
await signalRepository.lidMapping.storeLIDPNMappings([{ lid: primaryJid, pn: alt }]);
|
|
952
|
+
await signalRepository.migrateSession(alt, primaryJid);
|
|
636
953
|
}
|
|
637
954
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
|
|
955
|
+
if (msg.key?.remoteJid && msg.key?.id && messageRetryManager) {
|
|
956
|
+
messageRetryManager.addRecentMessage(msg.key.remoteJid, msg.key.id, msg.message);
|
|
957
|
+
logger.debug({
|
|
958
|
+
jid: msg.key.remoteJid,
|
|
959
|
+
id: msg.key.id
|
|
960
|
+
}, 'Added message to recent cache for retry receipts');
|
|
645
961
|
}
|
|
646
962
|
try {
|
|
647
|
-
await
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
if (msg
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
963
|
+
await processingMutex.mutex(async () => {
|
|
964
|
+
await decrypt();
|
|
965
|
+
// message failed to decrypt
|
|
966
|
+
if (msg.messageStubType === proto.WebMessageInfo.StubType.CIPHERTEXT) {
|
|
967
|
+
if (msg?.messageStubParameters?.[0] === MISSING_KEYS_ERROR_TEXT) {
|
|
968
|
+
return sendMessageAck(node, NACK_REASONS.ParsingError);
|
|
969
|
+
}
|
|
970
|
+
const errorMessage = msg?.messageStubParameters?.[0] || '';
|
|
971
|
+
const isPreKeyError = errorMessage.includes('PreKey');
|
|
972
|
+
logger.debug(`[handleMessage] Attempting retry request for failed decryption`);
|
|
973
|
+
// Handle both pre-key and normal retries in single mutex
|
|
974
|
+
retryMutex.mutex(async () => {
|
|
975
|
+
try {
|
|
976
|
+
if (!ws.isOpen) {
|
|
977
|
+
logger.debug({ node }, 'Connection closed, skipping retry');
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
// Handle pre-key errors with upload and delay
|
|
981
|
+
if (isPreKeyError) {
|
|
982
|
+
logger.info({ error: errorMessage }, 'PreKey error detected, uploading and retrying');
|
|
983
|
+
try {
|
|
984
|
+
logger.debug('Uploading pre-keys for error recovery');
|
|
985
|
+
await uploadPreKeys(5);
|
|
986
|
+
logger.debug('Waiting for server to process new pre-keys');
|
|
987
|
+
await delay(1000);
|
|
659
988
|
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
if (retryRequestDelayMs) {
|
|
663
|
-
await delay(retryRequestDelayMs);
|
|
989
|
+
catch (uploadErr) {
|
|
990
|
+
logger.error({ uploadErr }, 'Pre-key upload failed, proceeding with retry anyway');
|
|
664
991
|
}
|
|
665
992
|
}
|
|
666
|
-
|
|
667
|
-
|
|
993
|
+
const encNode = getBinaryNodeChild(node, 'enc');
|
|
994
|
+
await sendRetryRequest(node, !encNode);
|
|
995
|
+
if (retryRequestDelayMs) {
|
|
996
|
+
await delay(retryRequestDelayMs);
|
|
668
997
|
}
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
else {
|
|
672
|
-
// no type in the receipt => message delivered
|
|
673
|
-
let type = undefined;
|
|
674
|
-
let participant = msg.key.participant;
|
|
675
|
-
if (category === 'peer') {
|
|
676
|
-
// special peer message
|
|
677
|
-
type = 'peer_msg';
|
|
678
998
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
999
|
+
catch (err) {
|
|
1000
|
+
logger.error({ err, isPreKeyError }, 'Failed to handle retry, attempting basic retry');
|
|
1001
|
+
// Still attempt retry even if pre-key upload failed
|
|
1002
|
+
try {
|
|
1003
|
+
const encNode = getBinaryNodeChild(node, 'enc');
|
|
1004
|
+
await sendRetryRequest(node, !encNode);
|
|
1005
|
+
}
|
|
1006
|
+
catch (retryErr) {
|
|
1007
|
+
logger.error({ retryErr }, 'Failed to send retry after error handling');
|
|
685
1008
|
}
|
|
686
1009
|
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
1010
|
+
await sendMessageAck(node, NACK_REASONS.UnhandledError);
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
else {
|
|
1014
|
+
// no type in the receipt => message delivered
|
|
1015
|
+
let type = undefined;
|
|
1016
|
+
let participant = msg.key.participant;
|
|
1017
|
+
if (category === 'peer') {
|
|
1018
|
+
// special peer message
|
|
1019
|
+
type = 'peer_msg';
|
|
1020
|
+
}
|
|
1021
|
+
else if (msg.key.fromMe) {
|
|
1022
|
+
// message was sent by us from a different device
|
|
1023
|
+
type = 'sender';
|
|
1024
|
+
// need to specially handle this case
|
|
1025
|
+
if (isLidUser(msg.key.remoteJid) || isLidUser(msg.key.remoteJidAlt)) {
|
|
1026
|
+
participant = author; // TODO: investigate sending receipts to LIDs and not PNs
|
|
696
1027
|
}
|
|
697
1028
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
1029
|
+
else if (!sendActiveReceipts) {
|
|
1030
|
+
type = 'inactive';
|
|
1031
|
+
}
|
|
1032
|
+
await sendReceipt(msg.key.remoteJid, participant, [msg.key.id], type);
|
|
1033
|
+
// send ack for history message
|
|
1034
|
+
const isAnyHistoryMsg = getHistoryMsg(msg.message);
|
|
1035
|
+
if (isAnyHistoryMsg) {
|
|
1036
|
+
const jid = jidNormalizedUser(msg.key.remoteJid);
|
|
1037
|
+
await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync');
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
cleanMessage(msg, authState.creds.me.id, authState.creds.me.lid);
|
|
1041
|
+
await upsertMessage(msg, node.attrs.offline ? 'append' : 'notify');
|
|
1042
|
+
});
|
|
703
1043
|
}
|
|
704
1044
|
catch (error) {
|
|
705
|
-
logger.error({ error, node }, 'error in handling message');
|
|
706
|
-
}
|
|
707
|
-
};
|
|
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');
|
|
1045
|
+
logger.error({ error, node: binaryNodeToString(node) }, 'error in handling message');
|
|
727
1046
|
}
|
|
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
1047
|
};
|
|
756
1048
|
const handleCall = async (node) => {
|
|
757
|
-
let status;
|
|
758
1049
|
const { attrs } = node;
|
|
759
1050
|
const [infoChild] = getAllBinaryNodeChildren(node);
|
|
1051
|
+
const status = getCallStatusFromNode(infoChild);
|
|
760
1052
|
if (!infoChild) {
|
|
761
1053
|
throw new Boom('Missing call info in call node');
|
|
762
1054
|
}
|
|
763
1055
|
const callId = infoChild.attrs['call-id'];
|
|
764
1056
|
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
1057
|
const call = {
|
|
782
1058
|
chatId: attrs.from,
|
|
783
1059
|
from,
|
|
@@ -790,9 +1066,9 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
790
1066
|
call.isVideo = !!getBinaryNodeChild(infoChild, 'video');
|
|
791
1067
|
call.isGroup = infoChild.attrs.type === 'group' || !!infoChild.attrs['group-jid'];
|
|
792
1068
|
call.groupJid = infoChild.attrs['group-jid'];
|
|
793
|
-
callOfferCache.set(call.id, call);
|
|
1069
|
+
await callOfferCache.set(call.id, call);
|
|
794
1070
|
}
|
|
795
|
-
const existingCall = callOfferCache.get(call.id);
|
|
1071
|
+
const existingCall = await callOfferCache.get(call.id);
|
|
796
1072
|
// use existing call info to populate this event
|
|
797
1073
|
if (existingCall) {
|
|
798
1074
|
call.isVideo = existingCall.isVideo;
|
|
@@ -800,7 +1076,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
800
1076
|
}
|
|
801
1077
|
// delete data once call has ended
|
|
802
1078
|
if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
|
|
803
|
-
callOfferCache.del(call.id);
|
|
1079
|
+
await callOfferCache.del(call.id);
|
|
804
1080
|
}
|
|
805
1081
|
ev.emit('call', [call]);
|
|
806
1082
|
await sendMessageAck(node);
|
|
@@ -886,139 +1162,6 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
886
1162
|
processNodeWithBuffer(node, identifier, exec);
|
|
887
1163
|
}
|
|
888
1164
|
};
|
|
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
1165
|
// recv a message
|
|
1023
1166
|
ws.on('CB:message', (node) => {
|
|
1024
1167
|
processNode('message', node, 'processing message', handleMessage);
|
|
@@ -1078,7 +1221,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1078
1221
|
sendRetryRequest,
|
|
1079
1222
|
rejectCall,
|
|
1080
1223
|
fetchMessageHistory,
|
|
1081
|
-
requestPlaceholderResend
|
|
1224
|
+
requestPlaceholderResend,
|
|
1225
|
+
messageRetryManager
|
|
1082
1226
|
};
|
|
1083
1227
|
};
|
|
1084
1228
|
//# sourceMappingURL=messages-recv.js.map
|