@periskope/baileys 6.8.0-alpha.1 → 7.0.0-alpha-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -6
- package/lib/Signal/Group/group_cipher.d.ts +1 -0
- package/lib/Signal/Group/group_cipher.d.ts.map +1 -1
- package/lib/Signal/Group/group_cipher.js +36 -28
- package/lib/Signal/Group/group_cipher.js.map +1 -1
- package/lib/Signal/Group/queue-job.d.ts +1 -0
- package/lib/Signal/Group/queue-job.d.ts.map +1 -1
- package/lib/Signal/Group/queue-job.js +3 -0
- package/lib/Signal/Group/queue-job.js.map +1 -1
- package/lib/Signal/libsignal.d.ts.map +1 -1
- package/lib/Signal/libsignal.js +41 -76
- package/lib/Signal/libsignal.js.map +1 -1
- package/lib/Signal/lid-mapping.d.ts +1 -3
- package/lib/Signal/lid-mapping.d.ts.map +1 -1
- package/lib/Signal/lid-mapping.js +3 -29
- package/lib/Signal/lid-mapping.js.map +1 -1
- package/lib/Socket/business.d.ts.map +1 -1
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +4 -3
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/groups.d.ts.map +1 -1
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +302 -272
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +1 -1
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/newsletter.d.ts.map +1 -1
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +57 -43
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +2 -4
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Utils/auth-utils.d.ts.map +1 -1
- package/lib/Utils/auth-utils.js +78 -362
- package/lib/Utils/auth-utils.js.map +1 -1
- package/lib/Utils/decode-wa-message.d.ts +0 -5
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +3 -24
- package/lib/Utils/decode-wa-message.js.map +1 -1
- package/lib/Utils/generics.d.ts.map +1 -1
- package/lib/Utils/generics.js +16 -6
- package/lib/Utils/generics.js.map +1 -1
- package/lib/Utils/process-message.d.ts +2 -2
- package/lib/Utils/process-message.d.ts.map +1 -1
- package/lib/Utils/process-message.js +2 -2
- package/lib/Utils/process-message.js.map +1 -1
- package/lib/WAM/encode.d.ts.map +1 -1
- package/lib/WAM/encode.js +0 -1
- package/lib/WAM/encode.js.map +1 -1
- package/package.json +2 -1
|
@@ -7,7 +7,7 @@ import { DEFAULT_CACHE_TTLS, KEY_BUNDLE_TYPE, MIN_PREKEY_COUNT } from '../Defaul
|
|
|
7
7
|
import { WAMessageStatus, WAMessageStubType } from '../Types/index.js';
|
|
8
8
|
import { aesDecryptCTR, aesEncryptGCM, cleanMessage, Curve, decodeMediaRetryNode, decodeMessageNode, decryptMessageNode, delay, derivePairingCodeKey, encodeBigEndian, encodeSignedDeviceIdentity, getCallStatusFromNode, getHistoryMsg, getNextPreKeys, getStatusFromReceiptType, hkdf, MISSING_KEYS_ERROR_TEXT, NACK_REASONS, NO_MESSAGE_FOUND_ERROR_TEXT, unixTimestampSeconds, xmppPreKey, xmppSignedPreKey } from '../Utils/index.js';
|
|
9
9
|
import { makeMutex } from '../Utils/make-mutex.js';
|
|
10
|
-
import { areJidsSameUser, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString, isJidGroup, isJidStatusBroadcast, isLidUser, jidDecode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
10
|
+
import { areJidsSameUser, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString, isJidGroup, isJidStatusBroadcast, 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) => {
|
|
@@ -32,187 +32,6 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
32
32
|
useClones: false
|
|
33
33
|
});
|
|
34
34
|
let sendActiveReceipts = false;
|
|
35
|
-
const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
|
|
36
|
-
if (!authState.creds.me?.id) {
|
|
37
|
-
throw new Boom('Not authenticated');
|
|
38
|
-
}
|
|
39
|
-
const pdoMessage = {
|
|
40
|
-
historySyncOnDemandRequest: {
|
|
41
|
-
chatJid: oldestMsgKey.remoteJid,
|
|
42
|
-
oldestMsgFromMe: oldestMsgKey.fromMe,
|
|
43
|
-
oldestMsgId: oldestMsgKey.id,
|
|
44
|
-
oldestMsgTimestampMs: oldestMsgTimestamp,
|
|
45
|
-
onDemandMsgCount: count
|
|
46
|
-
},
|
|
47
|
-
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
|
|
48
|
-
};
|
|
49
|
-
return sendPeerDataOperationMessage(pdoMessage);
|
|
50
|
-
};
|
|
51
|
-
const requestPlaceholderResend = async (messageKey) => {
|
|
52
|
-
if (!authState.creds.me?.id) {
|
|
53
|
-
throw new Boom('Not authenticated');
|
|
54
|
-
}
|
|
55
|
-
if (placeholderResendCache.get(messageKey?.id)) {
|
|
56
|
-
logger.debug({ messageKey }, 'already requested resend');
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
placeholderResendCache.set(messageKey?.id, true);
|
|
61
|
-
}
|
|
62
|
-
await delay(5000);
|
|
63
|
-
if (!placeholderResendCache.get(messageKey?.id)) {
|
|
64
|
-
logger.debug({ messageKey }, 'message received while resend requested');
|
|
65
|
-
return 'RESOLVED';
|
|
66
|
-
}
|
|
67
|
-
const pdoMessage = {
|
|
68
|
-
placeholderMessageResendRequest: [
|
|
69
|
-
{
|
|
70
|
-
messageKey
|
|
71
|
-
}
|
|
72
|
-
],
|
|
73
|
-
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
|
|
74
|
-
};
|
|
75
|
-
setTimeout(() => {
|
|
76
|
-
if (placeholderResendCache.get(messageKey?.id)) {
|
|
77
|
-
logger.debug({ messageKey }, 'PDO message without response after 15 seconds. Phone possibly offline');
|
|
78
|
-
placeholderResendCache.del(messageKey?.id);
|
|
79
|
-
}
|
|
80
|
-
}, 15000);
|
|
81
|
-
return sendPeerDataOperationMessage(pdoMessage);
|
|
82
|
-
};
|
|
83
|
-
// Handles mex newsletter notifications
|
|
84
|
-
const handleMexNewsletterNotification = async (node) => {
|
|
85
|
-
const mexNode = getBinaryNodeChild(node, 'mex');
|
|
86
|
-
if (!mexNode?.content) {
|
|
87
|
-
logger.warn({ node }, 'Invalid mex newsletter notification');
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
let data;
|
|
91
|
-
try {
|
|
92
|
-
data = JSON.parse(mexNode.content.toString());
|
|
93
|
-
}
|
|
94
|
-
catch (error) {
|
|
95
|
-
logger.error({ err: error, node }, 'Failed to parse mex newsletter notification');
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
const operation = data?.operation;
|
|
99
|
-
const updates = data?.updates;
|
|
100
|
-
if (!updates || !operation) {
|
|
101
|
-
logger.warn({ data }, 'Invalid mex newsletter notification content');
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
logger.info({ operation, updates }, 'got mex newsletter notification');
|
|
105
|
-
switch (operation) {
|
|
106
|
-
case 'NotificationNewsletterUpdate':
|
|
107
|
-
for (const update of updates) {
|
|
108
|
-
if (update.jid && update.settings && Object.keys(update.settings).length > 0) {
|
|
109
|
-
ev.emit('newsletter-settings.update', {
|
|
110
|
-
id: update.jid,
|
|
111
|
-
update: update.settings
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
break;
|
|
116
|
-
case 'NotificationNewsletterAdminPromote':
|
|
117
|
-
for (const update of updates) {
|
|
118
|
-
if (update.jid && update.user) {
|
|
119
|
-
ev.emit('newsletter-participants.update', {
|
|
120
|
-
id: update.jid,
|
|
121
|
-
author: node.attrs.from,
|
|
122
|
-
user: update.user,
|
|
123
|
-
new_role: 'ADMIN',
|
|
124
|
-
action: 'promote'
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
break;
|
|
129
|
-
default:
|
|
130
|
-
logger.info({ operation, data }, 'Unhandled mex newsletter notification');
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
// Handles newsletter notifications
|
|
135
|
-
const handleNewsletterNotification = async (node) => {
|
|
136
|
-
const from = node.attrs.from;
|
|
137
|
-
const child = getAllBinaryNodeChildren(node)[0];
|
|
138
|
-
const author = node.attrs.participant;
|
|
139
|
-
logger.info({ from, child }, 'got newsletter notification');
|
|
140
|
-
switch (child.tag) {
|
|
141
|
-
case 'reaction':
|
|
142
|
-
const reactionUpdate = {
|
|
143
|
-
id: from,
|
|
144
|
-
server_id: child.attrs.message_id,
|
|
145
|
-
reaction: {
|
|
146
|
-
code: getBinaryNodeChildString(child, 'reaction'),
|
|
147
|
-
count: 1
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
ev.emit('newsletter.reaction', reactionUpdate);
|
|
151
|
-
break;
|
|
152
|
-
case 'view':
|
|
153
|
-
const viewUpdate = {
|
|
154
|
-
id: from,
|
|
155
|
-
server_id: child.attrs.message_id,
|
|
156
|
-
count: parseInt(child.content?.toString() || '0', 10)
|
|
157
|
-
};
|
|
158
|
-
ev.emit('newsletter.view', viewUpdate);
|
|
159
|
-
break;
|
|
160
|
-
case 'participant':
|
|
161
|
-
const participantUpdate = {
|
|
162
|
-
id: from,
|
|
163
|
-
author,
|
|
164
|
-
user: child.attrs.jid,
|
|
165
|
-
action: child.attrs.action,
|
|
166
|
-
new_role: child.attrs.role
|
|
167
|
-
};
|
|
168
|
-
ev.emit('newsletter-participants.update', participantUpdate);
|
|
169
|
-
break;
|
|
170
|
-
case 'update':
|
|
171
|
-
const settingsNode = getBinaryNodeChild(child, 'settings');
|
|
172
|
-
if (settingsNode) {
|
|
173
|
-
const update = {};
|
|
174
|
-
const nameNode = getBinaryNodeChild(settingsNode, 'name');
|
|
175
|
-
if (nameNode?.content)
|
|
176
|
-
update.name = nameNode.content.toString();
|
|
177
|
-
const descriptionNode = getBinaryNodeChild(settingsNode, 'description');
|
|
178
|
-
if (descriptionNode?.content)
|
|
179
|
-
update.description = descriptionNode.content.toString();
|
|
180
|
-
ev.emit('newsletter-settings.update', {
|
|
181
|
-
id: from,
|
|
182
|
-
update
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
break;
|
|
186
|
-
case 'message':
|
|
187
|
-
const plaintextNode = getBinaryNodeChild(child, 'plaintext');
|
|
188
|
-
if (plaintextNode?.content) {
|
|
189
|
-
try {
|
|
190
|
-
const contentBuf = typeof plaintextNode.content === 'string'
|
|
191
|
-
? Buffer.from(plaintextNode.content, 'binary')
|
|
192
|
-
: Buffer.from(plaintextNode.content);
|
|
193
|
-
const messageProto = proto.Message.decode(contentBuf);
|
|
194
|
-
const fullMessage = proto.WebMessageInfo.create({
|
|
195
|
-
key: {
|
|
196
|
-
remoteJid: from,
|
|
197
|
-
id: child.attrs.message_id || child.attrs.server_id,
|
|
198
|
-
fromMe: false
|
|
199
|
-
},
|
|
200
|
-
message: messageProto,
|
|
201
|
-
messageTimestamp: +child.attrs.t
|
|
202
|
-
});
|
|
203
|
-
await upsertMessage(fullMessage, 'append');
|
|
204
|
-
logger.info('Processed plaintext newsletter message');
|
|
205
|
-
}
|
|
206
|
-
catch (error) {
|
|
207
|
-
logger.error({ error }, 'Failed to decode plaintext newsletter message');
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
break;
|
|
211
|
-
default:
|
|
212
|
-
logger.warn({ node }, 'Unknown newsletter notification');
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
35
|
const sendMessageAck = async ({ tag, attrs, content }, errorCode) => {
|
|
217
36
|
const stanza = {
|
|
218
37
|
tag: 'ack',
|
|
@@ -410,8 +229,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
410
229
|
ev.emit('creds.update', update);
|
|
411
230
|
}
|
|
412
231
|
await sendNode(receipt);
|
|
413
|
-
logger.info({ msgAttrs: node.attrs, retryCount }, 'sent retry receipt');
|
|
414
|
-
}
|
|
232
|
+
logger.info({ msgAttrs: node.attrs, retryCount, shouldRecreateSession, recreateReason }, 'sent retry receipt');
|
|
233
|
+
});
|
|
415
234
|
};
|
|
416
235
|
const handleEncryptNotification = async (node) => {
|
|
417
236
|
const from = node.attrs.from;
|
|
@@ -835,7 +654,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
835
654
|
if (typeof status !== 'undefined' &&
|
|
836
655
|
// basically, we only want to know when a message from us has been delivered to/read by the other person
|
|
837
656
|
// or another device of ours has read some messages
|
|
838
|
-
|
|
657
|
+
status >= proto.WebMessageInfo.Status.SERVER_ACK) {
|
|
839
658
|
if (isJidGroup(remoteJid) || isJidStatusBroadcast(remoteJid)) {
|
|
840
659
|
const updateKey = status === proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
|
|
841
660
|
if (attrs.participant) {
|
|
@@ -946,7 +765,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
946
765
|
// TODO: temporary fix for crashes and issues resulting of failed msmsg decryption
|
|
947
766
|
if (encNode && encNode.attrs.type === 'msmsg') {
|
|
948
767
|
logger.debug({ key: node.attrs.key }, 'ignored msmsg');
|
|
949
|
-
await sendMessageAck(node);
|
|
768
|
+
await sendMessageAck(node, NACK_REASONS.MissingMessageSecret);
|
|
950
769
|
return;
|
|
951
770
|
}
|
|
952
771
|
let response;
|
|
@@ -989,105 +808,183 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
989
808
|
await lidMapping.storeLIDPNMapping(msg.key.participant || msg.key.remoteJid, alt);
|
|
990
809
|
}
|
|
991
810
|
}
|
|
992
|
-
|
|
993
|
-
|
|
811
|
+
}
|
|
812
|
+
if (msg.key?.remoteJid && msg.key?.id && messageRetryManager) {
|
|
813
|
+
messageRetryManager.addRecentMessage(msg.key.remoteJid, msg.key.id, msg.message);
|
|
814
|
+
logger.debug({
|
|
815
|
+
jid: msg.key.remoteJid,
|
|
816
|
+
id: msg.key.id
|
|
817
|
+
}, 'Added message to recent cache for retry receipts');
|
|
818
|
+
}
|
|
819
|
+
if (msg.message?.protocolMessage?.lidMigrationMappingSyncMessage?.encodedMappingPayload) {
|
|
820
|
+
try {
|
|
821
|
+
const payload = msg.message.protocolMessage.lidMigrationMappingSyncMessage.encodedMappingPayload;
|
|
822
|
+
const decoded = proto.LIDMigrationMappingSyncPayload.decode(payload);
|
|
994
823
|
logger.debug({
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
}, '
|
|
824
|
+
mappingCount: decoded.pnToLidMappings?.length || 0,
|
|
825
|
+
timestamp: decoded.chatDbMigrationTimestamp
|
|
826
|
+
}, 'Received LID migration sync message from server');
|
|
827
|
+
const lidMapping = signalRepository.getLIDMappingStore();
|
|
828
|
+
if (decoded.pnToLidMappings && decoded.pnToLidMappings.length > 0) {
|
|
829
|
+
for (const mapping of decoded.pnToLidMappings) {
|
|
830
|
+
const pn = `${mapping.pn}@s.whatsapp.net`;
|
|
831
|
+
// Use latestLid if available, otherwise assignedLid (proper LID refresh)
|
|
832
|
+
const lidValue = mapping.latestLid || mapping.assignedLid;
|
|
833
|
+
const lid = `${lidValue}@lid`;
|
|
834
|
+
await lidMapping.storeLIDPNMapping(lid, pn);
|
|
835
|
+
logger.debug({
|
|
836
|
+
pn,
|
|
837
|
+
lid,
|
|
838
|
+
assignedLid: mapping.assignedLid,
|
|
839
|
+
latestLid: mapping.latestLid,
|
|
840
|
+
usedLatest: !!mapping.latestLid
|
|
841
|
+
}, 'Stored server-provided PN-LID mapping');
|
|
842
|
+
}
|
|
843
|
+
}
|
|
998
844
|
}
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
try {
|
|
1026
|
-
logger.debug('Uploading pre-keys for error recovery');
|
|
1027
|
-
await uploadPreKeys(5);
|
|
1028
|
-
logger.debug('Waiting for server to process new pre-keys');
|
|
1029
|
-
await delay(1000);
|
|
1030
|
-
}
|
|
1031
|
-
catch (uploadErr) {
|
|
1032
|
-
logger.error({ uploadErr }, 'Pre-key upload failed, proceeding with retry anyway');
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
const encNode = getBinaryNodeChild(node, 'enc');
|
|
1036
|
-
await sendRetryRequest(node, !encNode);
|
|
1037
|
-
if (retryRequestDelayMs) {
|
|
1038
|
-
await delay(retryRequestDelayMs);
|
|
1039
|
-
}
|
|
845
|
+
catch (error) {
|
|
846
|
+
logger.error({ error }, 'Failed to process LID migration sync message');
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
try {
|
|
850
|
+
await Promise.all([
|
|
851
|
+
processingMutex.mutex(async () => {
|
|
852
|
+
await decrypt();
|
|
853
|
+
// message failed to decrypt
|
|
854
|
+
if (msg.messageStubType === proto.WebMessageInfo.StubType.CIPHERTEXT) {
|
|
855
|
+
if (msg?.messageStubParameters?.[0] === MISSING_KEYS_ERROR_TEXT) {
|
|
856
|
+
return sendMessageAck(node, NACK_REASONS.ParsingError);
|
|
857
|
+
}
|
|
858
|
+
const errorMessage = msg?.messageStubParameters?.[0] || '';
|
|
859
|
+
const isPreKeyError = errorMessage.includes('PreKey');
|
|
860
|
+
console.debug(`[handleMessage] Attempting retry request for failed decryption`);
|
|
861
|
+
// Handle both pre-key and normal retries in single mutex
|
|
862
|
+
retryMutex.mutex(async () => {
|
|
863
|
+
try {
|
|
864
|
+
if (!ws.isOpen) {
|
|
865
|
+
logger.debug({ node }, 'Connection closed, skipping retry');
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
if (getBinaryNodeChild(node, 'unavailable')) {
|
|
869
|
+
logger.debug('Message unavailable, skipping retry');
|
|
870
|
+
return;
|
|
1040
871
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
872
|
+
// Handle pre-key errors with upload and delay
|
|
873
|
+
if (isPreKeyError) {
|
|
874
|
+
logger.info({ error: errorMessage }, 'PreKey error detected, uploading and retrying');
|
|
1044
875
|
try {
|
|
1045
|
-
|
|
1046
|
-
await
|
|
876
|
+
logger.debug('Uploading pre-keys for error recovery');
|
|
877
|
+
await uploadPreKeys(5);
|
|
878
|
+
logger.debug('Waiting for server to process new pre-keys');
|
|
879
|
+
await delay(1000);
|
|
1047
880
|
}
|
|
1048
|
-
catch (
|
|
1049
|
-
logger.error({
|
|
881
|
+
catch (uploadErr) {
|
|
882
|
+
logger.error({ uploadErr }, 'Pre-key upload failed, proceeding with retry anyway');
|
|
1050
883
|
}
|
|
1051
884
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
let type = undefined;
|
|
1057
|
-
let participant = msg.key.participant;
|
|
1058
|
-
if (category === 'peer') {
|
|
1059
|
-
// special peer message
|
|
1060
|
-
type = 'peer_msg';
|
|
1061
|
-
}
|
|
1062
|
-
else if (msg.key.fromMe) {
|
|
1063
|
-
// message was sent by us from a different device
|
|
1064
|
-
type = 'sender';
|
|
1065
|
-
// need to specially handle this case
|
|
1066
|
-
if (isLidUser(msg.key.remoteJid) || isLidUser(msg.key.remoteJidAlt)) {
|
|
1067
|
-
participant = author; // TODO: investigate sending receipts to LIDs and not PNs
|
|
885
|
+
const encNode = getBinaryNodeChild(node, 'enc');
|
|
886
|
+
await sendRetryRequest(node, !encNode);
|
|
887
|
+
if (retryRequestDelayMs) {
|
|
888
|
+
await delay(retryRequestDelayMs);
|
|
1068
889
|
}
|
|
1069
890
|
}
|
|
1070
|
-
|
|
1071
|
-
|
|
891
|
+
catch (err) {
|
|
892
|
+
logger.error({ err, isPreKeyError }, 'Failed to handle retry, attempting basic retry');
|
|
893
|
+
// Still attempt retry even if pre-key upload failed
|
|
894
|
+
try {
|
|
895
|
+
const encNode = getBinaryNodeChild(node, 'enc');
|
|
896
|
+
await sendRetryRequest(node, !encNode);
|
|
897
|
+
}
|
|
898
|
+
catch (retryErr) {
|
|
899
|
+
logger.error({ retryErr }, 'Failed to send retry after error handling');
|
|
900
|
+
}
|
|
1072
901
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
else {
|
|
905
|
+
// no type in the receipt => message delivered
|
|
906
|
+
let type = undefined;
|
|
907
|
+
let participant = msg.key.participant;
|
|
908
|
+
if (category === 'peer') {
|
|
909
|
+
// special peer message
|
|
910
|
+
type = 'peer_msg';
|
|
911
|
+
}
|
|
912
|
+
else if (msg.key.fromMe) {
|
|
913
|
+
// message was sent by us from a different device
|
|
914
|
+
type = 'sender';
|
|
915
|
+
// need to specially handle this case
|
|
916
|
+
if (isLidUser(msg.key.remoteJid) || isLidUser(msg.key.remoteJidAlt)) {
|
|
917
|
+
participant = author; // TODO: investigate sending receipts to LIDs and not PNs
|
|
1079
918
|
}
|
|
1080
919
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
920
|
+
else if (!sendActiveReceipts) {
|
|
921
|
+
type = 'inactive';
|
|
922
|
+
}
|
|
923
|
+
await sendReceipt(msg.key.remoteJid, participant, [msg.key.id], type);
|
|
924
|
+
// send ack for history message
|
|
925
|
+
const isAnyHistoryMsg = getHistoryMsg(msg.message);
|
|
926
|
+
if (isAnyHistoryMsg) {
|
|
927
|
+
const jid = jidNormalizedUser(msg.key.remoteJid);
|
|
928
|
+
await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync');
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
cleanMessage(msg, authState.creds.me.id);
|
|
932
|
+
await sendMessageAck(node);
|
|
933
|
+
await upsertMessage(msg, node.attrs.offline ? 'append' : 'notify');
|
|
934
|
+
})
|
|
935
|
+
]);
|
|
936
|
+
}
|
|
937
|
+
catch (error) {
|
|
938
|
+
logger.error({ error, node }, 'error in handling message');
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
|
|
942
|
+
if (!authState.creds.me?.id) {
|
|
943
|
+
throw new Boom('Not authenticated');
|
|
944
|
+
}
|
|
945
|
+
const pdoMessage = {
|
|
946
|
+
historySyncOnDemandRequest: {
|
|
947
|
+
chatJid: oldestMsgKey.remoteJid,
|
|
948
|
+
oldestMsgFromMe: oldestMsgKey.fromMe,
|
|
949
|
+
oldestMsgId: oldestMsgKey.id,
|
|
950
|
+
oldestMsgTimestampMs: oldestMsgTimestamp,
|
|
951
|
+
onDemandMsgCount: count
|
|
952
|
+
},
|
|
953
|
+
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
|
|
954
|
+
};
|
|
955
|
+
return sendPeerDataOperationMessage(pdoMessage);
|
|
956
|
+
};
|
|
957
|
+
const requestPlaceholderResend = async (messageKey) => {
|
|
958
|
+
if (!authState.creds.me?.id) {
|
|
959
|
+
throw new Boom('Not authenticated');
|
|
960
|
+
}
|
|
961
|
+
if (placeholderResendCache.get(messageKey?.id)) {
|
|
962
|
+
logger.debug({ messageKey }, 'already requested resend');
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
else {
|
|
966
|
+
placeholderResendCache.set(messageKey?.id, true);
|
|
1090
967
|
}
|
|
968
|
+
await delay(5000);
|
|
969
|
+
if (!placeholderResendCache.get(messageKey?.id)) {
|
|
970
|
+
logger.debug({ messageKey }, 'message received while resend requested');
|
|
971
|
+
return 'RESOLVED';
|
|
972
|
+
}
|
|
973
|
+
const pdoMessage = {
|
|
974
|
+
placeholderMessageResendRequest: [
|
|
975
|
+
{
|
|
976
|
+
messageKey
|
|
977
|
+
}
|
|
978
|
+
],
|
|
979
|
+
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
|
|
980
|
+
};
|
|
981
|
+
setTimeout(() => {
|
|
982
|
+
if (placeholderResendCache.get(messageKey?.id)) {
|
|
983
|
+
logger.debug({ messageKey }, 'PDO message without response after 15 seconds. Phone possibly offline');
|
|
984
|
+
placeholderResendCache.del(messageKey?.id);
|
|
985
|
+
}
|
|
986
|
+
}, 15000);
|
|
987
|
+
return sendPeerDataOperationMessage(pdoMessage);
|
|
1091
988
|
};
|
|
1092
989
|
const handleCall = async (node) => {
|
|
1093
990
|
let status;
|
|
@@ -1222,6 +1119,139 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1222
1119
|
processNodeWithBuffer(node, identifier, exec);
|
|
1223
1120
|
}
|
|
1224
1121
|
};
|
|
1122
|
+
// Handles newsletter notifications
|
|
1123
|
+
async function handleNewsletterNotification(node) {
|
|
1124
|
+
const from = node.attrs.from;
|
|
1125
|
+
const child = getAllBinaryNodeChildren(node)[0];
|
|
1126
|
+
const author = node.attrs.participant;
|
|
1127
|
+
logger.info({ from, child }, 'got newsletter notification');
|
|
1128
|
+
switch (child.tag) {
|
|
1129
|
+
case 'reaction':
|
|
1130
|
+
const reactionUpdate = {
|
|
1131
|
+
id: from,
|
|
1132
|
+
server_id: child.attrs.message_id,
|
|
1133
|
+
reaction: {
|
|
1134
|
+
code: getBinaryNodeChildString(child, 'reaction'),
|
|
1135
|
+
count: 1
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
ev.emit('newsletter.reaction', reactionUpdate);
|
|
1139
|
+
break;
|
|
1140
|
+
case 'view':
|
|
1141
|
+
const viewUpdate = {
|
|
1142
|
+
id: from,
|
|
1143
|
+
server_id: child.attrs.message_id,
|
|
1144
|
+
count: parseInt(child.content?.toString() || '0', 10)
|
|
1145
|
+
};
|
|
1146
|
+
ev.emit('newsletter.view', viewUpdate);
|
|
1147
|
+
break;
|
|
1148
|
+
case 'participant':
|
|
1149
|
+
const participantUpdate = {
|
|
1150
|
+
id: from,
|
|
1151
|
+
author,
|
|
1152
|
+
user: child.attrs.jid,
|
|
1153
|
+
action: child.attrs.action,
|
|
1154
|
+
new_role: child.attrs.role
|
|
1155
|
+
};
|
|
1156
|
+
ev.emit('newsletter-participants.update', participantUpdate);
|
|
1157
|
+
break;
|
|
1158
|
+
case 'update':
|
|
1159
|
+
const settingsNode = getBinaryNodeChild(child, 'settings');
|
|
1160
|
+
if (settingsNode) {
|
|
1161
|
+
const update = {};
|
|
1162
|
+
const nameNode = getBinaryNodeChild(settingsNode, 'name');
|
|
1163
|
+
if (nameNode?.content)
|
|
1164
|
+
update.name = nameNode.content.toString();
|
|
1165
|
+
const descriptionNode = getBinaryNodeChild(settingsNode, 'description');
|
|
1166
|
+
if (descriptionNode?.content)
|
|
1167
|
+
update.description = descriptionNode.content.toString();
|
|
1168
|
+
ev.emit('newsletter-settings.update', {
|
|
1169
|
+
id: from,
|
|
1170
|
+
update
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
break;
|
|
1174
|
+
case 'message':
|
|
1175
|
+
const plaintextNode = getBinaryNodeChild(child, 'plaintext');
|
|
1176
|
+
if (plaintextNode?.content) {
|
|
1177
|
+
try {
|
|
1178
|
+
const contentBuf = typeof plaintextNode.content === 'string'
|
|
1179
|
+
? Buffer.from(plaintextNode.content, 'binary')
|
|
1180
|
+
: Buffer.from(plaintextNode.content);
|
|
1181
|
+
const messageProto = proto.Message.decode(contentBuf);
|
|
1182
|
+
const fullMessage = proto.WebMessageInfo.create({
|
|
1183
|
+
key: {
|
|
1184
|
+
remoteJid: from,
|
|
1185
|
+
id: child.attrs.message_id || child.attrs.server_id,
|
|
1186
|
+
fromMe: false
|
|
1187
|
+
},
|
|
1188
|
+
message: messageProto,
|
|
1189
|
+
messageTimestamp: +child.attrs.t
|
|
1190
|
+
});
|
|
1191
|
+
await upsertMessage(fullMessage, 'append');
|
|
1192
|
+
logger.info('Processed plaintext newsletter message');
|
|
1193
|
+
}
|
|
1194
|
+
catch (error) {
|
|
1195
|
+
logger.error({ error }, 'Failed to decode plaintext newsletter message');
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
break;
|
|
1199
|
+
default:
|
|
1200
|
+
logger.warn({ node }, 'Unknown newsletter notification');
|
|
1201
|
+
break;
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
// Handles mex newsletter notifications
|
|
1205
|
+
async function handleMexNewsletterNotification(node) {
|
|
1206
|
+
const mexNode = getBinaryNodeChild(node, 'mex');
|
|
1207
|
+
if (!mexNode?.content) {
|
|
1208
|
+
logger.warn({ node }, 'Invalid mex newsletter notification');
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
let data;
|
|
1212
|
+
try {
|
|
1213
|
+
data = JSON.parse(mexNode.content.toString());
|
|
1214
|
+
}
|
|
1215
|
+
catch (error) {
|
|
1216
|
+
logger.error({ err: error, node }, 'Failed to parse mex newsletter notification');
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
const operation = data?.operation;
|
|
1220
|
+
const updates = data?.updates;
|
|
1221
|
+
if (!updates || !operation) {
|
|
1222
|
+
logger.warn({ data }, 'Invalid mex newsletter notification content');
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
logger.info({ operation, updates }, 'got mex newsletter notification');
|
|
1226
|
+
switch (operation) {
|
|
1227
|
+
case 'NotificationNewsletterUpdate':
|
|
1228
|
+
for (const update of updates) {
|
|
1229
|
+
if (update.jid && update.settings && Object.keys(update.settings).length > 0) {
|
|
1230
|
+
ev.emit('newsletter-settings.update', {
|
|
1231
|
+
id: update.jid,
|
|
1232
|
+
update: update.settings
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
break;
|
|
1237
|
+
case 'NotificationNewsletterAdminPromote':
|
|
1238
|
+
for (const update of updates) {
|
|
1239
|
+
if (update.jid && update.user) {
|
|
1240
|
+
ev.emit('newsletter-participants.update', {
|
|
1241
|
+
id: update.jid,
|
|
1242
|
+
author: node.attrs.from,
|
|
1243
|
+
user: update.user,
|
|
1244
|
+
new_role: 'ADMIN',
|
|
1245
|
+
action: 'promote'
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
break;
|
|
1250
|
+
default:
|
|
1251
|
+
logger.info({ operation, data }, 'Unhandled mex newsletter notification');
|
|
1252
|
+
break;
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1225
1255
|
// recv a message
|
|
1226
1256
|
ws.on('CB:message', (node) => {
|
|
1227
1257
|
processNode('message', node, 'processing message', handleMessage);
|