@zetagoaurum-socket/decagramton 3.2.4 → 3.2.7

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.
Files changed (92) hide show
  1. package/README.md +91 -91
  2. package/WAProto/index.js +56886 -17506
  3. package/engine-requirements.js +91 -0
  4. package/lib/Defaults/index.js +47 -2
  5. package/lib/Signal/Group/ciphertext-message.d.ts +9 -0
  6. package/lib/Signal/Group/ciphertext-message.js +15 -0
  7. package/lib/Signal/Group/group-session-builder.d.ts +14 -0
  8. package/lib/Signal/Group/group-session-builder.js +64 -0
  9. package/lib/Signal/Group/group_cipher.d.ts +17 -0
  10. package/lib/Signal/Group/group_cipher.js +96 -0
  11. package/lib/Signal/Group/index.d.ts +11 -0
  12. package/lib/Signal/Group/index.js +57 -0
  13. package/lib/Signal/Group/keyhelper.d.ts +10 -0
  14. package/lib/Signal/Group/keyhelper.js +55 -0
  15. package/lib/Signal/Group/queue-job.d.ts +1 -0
  16. package/lib/Signal/Group/queue-job.js +57 -0
  17. package/lib/Signal/Group/sender-chain-key.d.ts +13 -0
  18. package/lib/Signal/Group/sender-chain-key.js +34 -0
  19. package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -0
  20. package/lib/Signal/Group/sender-key-distribution-message.js +66 -0
  21. package/lib/Signal/Group/sender-key-message.d.ts +18 -0
  22. package/lib/Signal/Group/sender-key-message.js +69 -0
  23. package/lib/Signal/Group/sender-key-name.d.ts +17 -0
  24. package/lib/Signal/Group/sender-key-name.js +51 -0
  25. package/lib/Signal/Group/sender-key-record.d.ts +30 -0
  26. package/lib/Signal/Group/sender-key-record.js +53 -0
  27. package/lib/Signal/Group/sender-key-state.d.ts +38 -0
  28. package/lib/Signal/Group/sender-key-state.js +99 -0
  29. package/lib/Signal/Group/sender-message-key.d.ts +11 -0
  30. package/{WASignalGroup/sender_message_key.js → lib/Signal/Group/sender-message-key.js} +6 -16
  31. package/lib/Signal/libsignal.js +51 -29
  32. package/lib/Socket/business.d.ts +3 -2
  33. package/lib/Socket/chats.d.ts +215 -28
  34. package/lib/Socket/chats.js +166 -70
  35. package/lib/Socket/dugong.d.ts +254 -0
  36. package/lib/Socket/dugong.js +432 -141
  37. package/lib/Socket/groups.js +20 -23
  38. package/lib/Socket/index.js +2 -15
  39. package/lib/Socket/messages-recv.d.ts +56 -55
  40. package/lib/Socket/messages-recv.js +367 -131
  41. package/lib/Socket/messages-send.d.ts +3 -2
  42. package/lib/Socket/messages-send.js +423 -380
  43. package/lib/Socket/newsletter.js +147 -21
  44. package/lib/Socket/socket.js +156 -148
  45. package/lib/Socket/usync.d.ts +3 -3
  46. package/lib/Types/GroupMetadata.d.ts +1 -0
  47. package/lib/Types/Newsletter.d.ts +97 -86
  48. package/lib/Types/Newsletter.js +38 -32
  49. package/lib/Types/USync.d.ts +25 -0
  50. package/lib/Types/USync.js +2 -0
  51. package/lib/Utils/anti-crash.js +31 -0
  52. package/lib/Utils/chat-utils.js +6 -1
  53. package/lib/Utils/generics.js +66 -34
  54. package/lib/Utils/history.js +6 -1
  55. package/lib/Utils/index.js +0 -1
  56. package/lib/Utils/link-preview.js +1 -1
  57. package/lib/Utils/messages-media.js +145 -57
  58. package/lib/Utils/messages.js +92 -306
  59. package/lib/Utils/signal.js +48 -46
  60. package/lib/Utils/use-multi-file-auth-state.js +45 -6
  61. package/lib/Utils/validate-connection.js +89 -65
  62. package/lib/WABinary/constants.d.ts +27 -24
  63. package/lib/WABinary/encode.js +160 -123
  64. package/lib/WABinary/generic-utils.d.ts +2 -0
  65. package/lib/WABinary/generic-utils.js +124 -36
  66. package/lib/WABinary/jid-utils.js +5 -26
  67. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +1 -1
  68. package/lib/index.d.ts +1 -0
  69. package/lib/index.js +56 -0
  70. package/package.json +107 -101
  71. package/LICENSE +0 -21
  72. package/WAProto/GenerateStatics.sh +0 -4
  73. package/WAProto/WAProto.proto +0 -3344
  74. package/WAProto/index.d.ts +0 -37016
  75. package/WASignalGroup/GroupProtocol.js +0 -1697
  76. package/WASignalGroup/ciphertext_message.js +0 -16
  77. package/WASignalGroup/group_cipher.js +0 -120
  78. package/WASignalGroup/group_session_builder.js +0 -46
  79. package/WASignalGroup/index.js +0 -5
  80. package/WASignalGroup/keyhelper.js +0 -21
  81. package/WASignalGroup/protobufs.js +0 -3
  82. package/WASignalGroup/queue_job.js +0 -69
  83. package/WASignalGroup/sender_chain_key.js +0 -50
  84. package/WASignalGroup/sender_key_distribution_message.js +0 -78
  85. package/WASignalGroup/sender_key_message.js +0 -92
  86. package/WASignalGroup/sender_key_name.js +0 -70
  87. package/WASignalGroup/sender_key_record.js +0 -56
  88. package/WASignalGroup/sender_key_state.js +0 -129
  89. package/decagramton.jpg +0 -0
  90. package/lib/Utils/rate-limiter.js +0 -55
  91. package/lib/WAUSync/Fall +0 -1
  92. package/lib/WAUSync/Protocols/Fal +0 -1
@@ -6,78 +6,146 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.makeMessagesRecvSocket = void 0;
7
7
  const boom_1 = require("@hapi/boom");
8
8
  const crypto_1 = require("crypto");
9
- const node_cache_1 = __importDefault(require("node-cache"));
9
+ const node_cache_1 = __importDefault(require("@cacheable/node-cache"));
10
10
  const WAProto_1 = require("../../WAProto");
11
11
  const Defaults_1 = require("../Defaults");
12
12
  const Types_1 = require("../Types");
13
13
  const Utils_1 = require("../Utils");
14
- const Utils_2 = require("../Utils");
15
14
  const make_mutex_1 = require("../Utils/make-mutex");
16
15
  const WABinary_1 = require("../WABinary");
17
16
  const groups_1 = require("./groups");
18
17
  const messages_send_1 = require("./messages-send");
19
18
  const makeMessagesRecvSocket = (config) => {
20
- const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid } = config;
19
+ const {
20
+ logger,
21
+ retryRequestDelayMs,
22
+ maxMsgRetryCount,
23
+ getMessage,
24
+ shouldIgnoreJid
25
+ } = config;
21
26
  const sock = (0, messages_send_1.makeMessagesSocket)(config);
22
- const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, getUSyncDevices, createParticipantNodes } = sock;
27
+ const {
28
+ ev,
29
+ authState,
30
+ ws,
31
+ processingMutex,
32
+ signalRepository,
33
+ query,
34
+ upsertMessage,
35
+ resyncAppState,
36
+ groupMetadata,
37
+ onUnexpectedError,
38
+ assertSessions,
39
+ sendNode,
40
+ relayMessage,
41
+ sendReceipt,
42
+ uploadPreKeys,
43
+ createParticipantNodes,
44
+ getUSyncDevices,
45
+ sendPeerDataOperationMessage
46
+ } = sock;
23
47
  /** this mutex ensures that each retryRequest will wait for the previous one to finish */
24
48
  const retryMutex = (0, make_mutex_1.makeMutex)();
25
49
  const msgRetryCache = config.msgRetryCounterCache || new node_cache_1.default({
26
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY,
50
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
27
51
  useClones: false
28
52
  });
29
53
  const callOfferCache = config.callOfferCache || new node_cache_1.default({
30
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.CALL_OFFER,
54
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.CALL_OFFER, // 5 mins
55
+ useClones: false
56
+ });
57
+ const placeholderResendCache = config.placeholderResendCache || new node_cache_1.default({
58
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
31
59
  useClones: false
32
60
  });
33
61
  let sendActiveReceipts = false;
34
- const sendMessageAck = async ({ tag, attrs, content }) => {
62
+ const sendMessageAck = async ({ tag, attrs, content }, errorCode) => {
35
63
  const stanza = {
36
64
  tag: 'ack',
37
65
  attrs: {
38
66
  id: attrs.id,
39
67
  to: attrs.from,
40
- class: tag,
68
+ class: tag
41
69
  }
42
- };
70
+ }
71
+ if (!!errorCode) {
72
+ stanza.attrs.error = errorCode.toString();
73
+ }
43
74
  if (!!attrs.participant) {
44
75
  stanza.attrs.participant = attrs.participant;
45
76
  }
46
77
  if (!!attrs.recipient) {
47
78
  stanza.attrs.recipient = attrs.recipient;
48
79
  }
49
- if (!!attrs.type && (tag !== 'message' || (0, WABinary_1.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable'))) {
80
+ if (!!attrs.type && (tag !== 'message' || (0, WABinary_1.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable') || errorCode !== 0)) {
50
81
  stanza.attrs.type = attrs.type;
51
82
  }
52
83
  if (tag === 'message' && (0, WABinary_1.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable')) {
53
84
  stanza.attrs.from = authState.creds.me.id;
54
85
  }
55
- logger.debug({ recv: { tag, attrs }, sent: stanza.attrs }, 'sent ack');
86
+ logger.debug({
87
+ recv: {
88
+ tag,
89
+ attrs
90
+ },
91
+ sent: stanza.attrs }, 'sent ack');
56
92
  await sendNode(stanza);
57
93
  };
58
94
  const offerCall = async (toJid, isVideo = false) => {
59
95
  const callId = (0, crypto_1.randomBytes)(16).toString('hex').toUpperCase().substring(0, 64);
60
96
  const offerContent = [];
61
- offerContent.push({ tag: 'audio', attrs: { enc: 'opus', rate: '16000' }, content: undefined });
62
- offerContent.push({ tag: 'audio', attrs: { enc: 'opus', rate: '8000' }, content: undefined });
97
+ offerContent.push({
98
+ tag: 'audio',
99
+ attrs: {
100
+ enc: 'opus',
101
+ rate: '16000'
102
+ }, content: undefined
103
+ });
104
+ offerContent.push({
105
+ tag: 'audio',
106
+ attrs: {
107
+ enc: 'opus',
108
+ rate: '8000'
109
+ }, content: undefined
110
+ });
63
111
  if (isVideo) {
64
112
  offerContent.push({
65
113
  tag: 'video',
66
- attrs: { enc: 'vp8', dec: 'vp8', orientation: '0', 'screen_width': '1920', 'screen_height': '1080', 'device_orientation': '0' },
67
- content: undefined
114
+ attrs: {
115
+ orientation: '0',
116
+ 'screen_width': '1920',
117
+ 'screen_height': '1080',
118
+ 'device_orientation': '0',
119
+ enc: 'vp8',
120
+ dec: 'vp8',
121
+ }
68
122
  });
69
123
  }
70
- offerContent.push({ tag: 'net', attrs: { medium: '3' }, content: undefined });
71
- offerContent.push({ tag: 'capability', attrs: { ver: '1' }, content: new Uint8Array([1, 4, 255, 131, 207, 4]) });
72
- offerContent.push({ tag: 'encopt', attrs: { keygen: '2' }, content: undefined });
124
+ offerContent.push({
125
+ tag: 'net',
126
+ attrs: {
127
+ medium: '3'
128
+ }, content: undefined
129
+ });
130
+ offerContent.push({
131
+ tag: 'capability',
132
+ attrs: {
133
+ ver: '1'
134
+ }, content: new Uint8Array([1, 4, 255, 131, 207, 4]) });
135
+ offerContent.push({
136
+ tag: 'encopt',
137
+ attrs: {
138
+ keygen: '2'
139
+ }, content: undefined
140
+ })
73
141
  const encKey = (0, crypto_1.randomBytes)(32);
74
142
  const devices = (await getUSyncDevices([toJid], true, false)).map(({ user, device }) => (0, WABinary_1.jidEncode)(user, 's.whatsapp.net', device));
75
143
  await assertSessions(devices, true);
76
144
  const { nodes: destinations, shouldIncludeDeviceIdentity } = await createParticipantNodes(devices, {
77
145
  call: {
78
- callKey: new Uint8Array(encKey)
146
+ callKey: encKey
79
147
  }
80
- }, { count: '0' });
148
+ });
81
149
  offerContent.push({ tag: 'destination', attrs: {}, content: destinations });
82
150
  if (shouldIncludeDeviceIdentity) {
83
151
  offerContent.push({
@@ -89,7 +157,6 @@ const makeMessagesRecvSocket = (config) => {
89
157
  const stanza = ({
90
158
  tag: 'call',
91
159
  attrs: {
92
- id: (0, Utils_1.generateMessageIDV2)(),
93
160
  to: toJid,
94
161
  },
95
162
  content: [{
@@ -103,8 +170,9 @@ const makeMessagesRecvSocket = (config) => {
103
170
  });
104
171
  await query(stanza);
105
172
  return {
106
- id: callId,
107
- to: toJid
173
+ callId,
174
+ toJid,
175
+ isVideo,
108
176
  };
109
177
  };
110
178
  const rejectCall = async (callId, callFrom) => {
@@ -127,16 +195,24 @@ const makeMessagesRecvSocket = (config) => {
127
195
  await query(stanza);
128
196
  };
129
197
  const sendRetryRequest = async (node, forceIncludeKeys = false) => {
130
- const msgId = node.attrs.id;
131
- let retryCount = msgRetryCache.get(msgId) || 0;
198
+ const { fullMessage } = (0, Utils_1.decodeMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '');
199
+ const { key: msgKey } = fullMessage;
200
+ const msgId = msgKey.id;
201
+ const key = `${msgId}:${msgKey === null || msgKey === void 0 ? void 0 : msgKey.participant}`;
202
+ let retryCount = msgRetryCache.get(key) || 0;
132
203
  if (retryCount >= maxMsgRetryCount) {
133
204
  logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
134
- msgRetryCache.del(msgId);
205
+ msgRetryCache.del(key);
135
206
  return;
136
207
  }
137
208
  retryCount += 1;
138
- msgRetryCache.set(msgId, retryCount);
209
+ msgRetryCache.set(key, retryCount);
139
210
  const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds;
211
+ if (retryCount === 1) {
212
+ //request a resend via phone
213
+ const msgId = await requestPlaceholderResend(msgKey);
214
+ logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId}`);
215
+ }
140
216
  const deviceIdentity = (0, Utils_1.encodeSignedDeviceIdentity)(account, true);
141
217
  await authState.keys.transaction(async () => {
142
218
  const receipt = {
@@ -215,6 +291,8 @@ const makeMessagesRecvSocket = (config) => {
215
291
  }
216
292
  };
217
293
  const handleGroupNotification = (participant, child, msg) => {
294
+ var _a, _b, _c, _d;
295
+ const participantJid = ((_b = (_a = (0, WABinary_1.getBinaryNodeChild)(child, 'participant')) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b.jid) || participant;
218
296
  switch (child === null || child === void 0 ? void 0 : child.tag) {
219
297
  case 'create':
220
298
  const metadata = (0, groups_1.extractGroupMetadata)(child);
@@ -240,6 +318,11 @@ const makeMessagesRecvSocket = (config) => {
240
318
  }
241
319
  };
242
320
  break;
321
+ case 'modify':
322
+ const oldNumber = (0, WABinary_1.getBinaryNodeChildren)(child, 'participant').map(p => p.attrs.jid);
323
+ msg.messageStubParameters = oldNumber || [];
324
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER;
325
+ break;
243
326
  case 'promote':
244
327
  case 'demote':
245
328
  case 'remove':
@@ -261,6 +344,11 @@ const makeMessagesRecvSocket = (config) => {
261
344
  msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_SUBJECT;
262
345
  msg.messageStubParameters = [child.attrs.subject];
263
346
  break;
347
+ case 'description':
348
+ const description = (_d = (_c = (0, WABinary_1.getBinaryNodeChild)(child, 'body')) === null || _c === void 0 ? void 0 : _c.content) === null || _d === void 0 ? void 0 : _d.toString();
349
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_DESCRIPTION;
350
+ msg.messageStubParameters = description ? [description] : undefined;
351
+ break;
264
352
  case 'announcement':
265
353
  case 'not_announcement':
266
354
  msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_ANNOUNCE;
@@ -289,10 +377,66 @@ const makeMessagesRecvSocket = (config) => {
289
377
  msg.messageStubParameters = [approvalMode.attrs.state];
290
378
  }
291
379
  break;
380
+ case 'created_membership_requests':
381
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
382
+ msg.messageStubParameters = [participantJid, 'created', child.attrs.request_method];
383
+ break;
384
+ case 'revoked_membership_requests':
385
+ const isDenied = (0, WABinary_1.areJidsSameUser)(participantJid, participant);
386
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
387
+ msg.messageStubParameters = [participantJid, isDenied ? 'revoked' : 'rejected'];
388
+ break;
389
+ break;
390
+ default:
391
+ // console.log("BAILEYS-DEBUG:", JSON.stringify({ ...child, content: Buffer.isBuffer(child.content) ? child.content.toString() : child.content, participant }, null, 2))
392
+ }
393
+ };
394
+ const handleNewsletterNotification = (id, node) => {
395
+ const messages = (0, WABinary_1.getBinaryNodeChild)(node, 'messages');
396
+ const message = (0, WABinary_1.getBinaryNodeChild)(messages, 'message');
397
+ const serverId = message.attrs.server_id;
398
+ const reactionsList = (0, WABinary_1.getBinaryNodeChild)(message, 'reactions');
399
+ const viewsList = (0, WABinary_1.getBinaryNodeChildren)(message, 'views_count');
400
+ if (reactionsList) {
401
+ const reactions = (0, WABinary_1.getBinaryNodeChildren)(reactionsList, 'reaction');
402
+ if (reactions.length === 0) {
403
+ ev.emit('newsletter.reaction', { id, 'server_id': serverId, reaction: { removed: true } });
404
+ }
405
+ reactions.forEach(item => {
406
+ var _a, _b;
407
+ ev.emit('newsletter.reaction', { id, 'server_id': serverId, reaction: { code: (_a = item.attrs) === null || _a === void 0 ? void 0 : _a.code, count: +((_b = item.attrs) === null || _b === void 0 ? void 0 : _b.count) } });
408
+ });
409
+ }
410
+ if (viewsList.length) {
411
+ viewsList.forEach(item => {
412
+ ev.emit('newsletter.view', { id, 'server_id': serverId, count: +item.attrs.count });
413
+ });
414
+ }
415
+ };
416
+ const handleMexNewsletterNotification = (id, node) => {
417
+ var _a;
418
+ const operation = node === null || node === void 0 ? void 0 : node.attrs.op_name;
419
+ const content = JSON.parse((_a = node === null || node === void 0 ? void 0 : node.content) === null || _a === void 0 ? void 0 : _a.toString());
420
+ let contentPath;
421
+ if (operation === Types_1.MexOperations.PROMOTE || operation === Types_1.MexOperations.DEMOTE) {
422
+ let action;
423
+ if (operation === Types_1.MexOperations.PROMOTE) {
424
+ action = 'promote';
425
+ contentPath = content.data[Types_1.XWAPaths.PROMOTE];
426
+ }
427
+ if (operation === Types_1.MexOperations.DEMOTE) {
428
+ action = 'demote';
429
+ contentPath = content.data[Types_1.XWAPaths.DEMOTE];
430
+ }
431
+ ev.emit('newsletter-participants.update', { id, author: contentPath.actor.pn, user: contentPath.user.pn, new_role: contentPath.user_new_role, action });
432
+ }
433
+ if (operation === Types_1.MexOperations.UPDATE) {
434
+ contentPath = content.data[Types_1.XWAPaths.METADATA_UPDATE];
435
+ ev.emit('newsletter-settings.update', { id, update: contentPath.thread_metadata.settings });
292
436
  }
293
437
  };
294
438
  const processNotification = async (node) => {
295
- var _a, _b, _c;
439
+ var _a, _b;
296
440
  const result = {};
297
441
  const [child] = (0, WABinary_1.getAllBinaryNodeChildren)(node);
298
442
  const nodeType = node.attrs.type;
@@ -311,6 +455,12 @@ const makeMessagesRecvSocket = (config) => {
311
455
  logger.debug({ jid }, 'got privacy token update');
312
456
  }
313
457
  break;
458
+ case 'newsletter':
459
+ handleNewsletterNotification(node.attrs.from, child);
460
+ break;
461
+ case 'mex':
462
+ handleMexNewsletterNotification(node.attrs.from, child);
463
+ break;
314
464
  case 'w:gp2':
315
465
  handleGroupNotification(node.attrs.participant, child, result);
316
466
  break;
@@ -321,9 +471,6 @@ const makeMessagesRecvSocket = (config) => {
321
471
  case 'encrypt':
322
472
  await handleEncryptNotification(node);
323
473
  break;
324
- case 'newsletter':
325
- // TO DO
326
- break;
327
474
  case 'devices':
328
475
  const devices = (0, WABinary_1.getBinaryNodeChildren)(child, 'device');
329
476
  if ((0, WABinary_1.areJidsSameUser)(child.attrs.jid, authState.creds.me.id)) {
@@ -342,7 +489,7 @@ const makeMessagesRecvSocket = (config) => {
342
489
  const setPicture = (0, WABinary_1.getBinaryNodeChild)(node, 'set');
343
490
  const delPicture = (0, WABinary_1.getBinaryNodeChild)(node, 'delete');
344
491
  ev.emit('contacts.update', [{
345
- id: (0, WABinary_1.jidNormalizedUser)((_a = node === null || node === void 0 ? void 0 : node.attrs) === null || _a === void 0 ? void 0 : _a.jid) || ((_c = (_b = (setPicture || delPicture)) === null || _b === void 0 ? void 0 : _b.attrs) === null || _c === void 0 ? void 0 : _c.hash) || '',
492
+ id: from || ((_b = (_a = (setPicture || delPicture)) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b.hash) || '',
346
493
  imgUrl: setPicture ? 'changed' : 'removed'
347
494
  }]);
348
495
  if ((0, WABinary_1.isJidGroup)(from)) {
@@ -387,11 +534,11 @@ const makeMessagesRecvSocket = (config) => {
387
534
  const ref = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_ref'));
388
535
  const primaryIdentityPublicKey = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'primary_identity_pub'));
389
536
  const primaryEphemeralPublicKeyWrapped = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_wrapped_primary_ephemeral_pub'));
390
- const codePairingPublicKey = decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped);
537
+ const codePairingPublicKey = await decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped);
391
538
  const companionSharedKey = Utils_1.Curve.sharedKey(authState.creds.pairingEphemeralKeyPair.private, codePairingPublicKey);
392
539
  const random = (0, crypto_1.randomBytes)(32);
393
540
  const linkCodeSalt = (0, crypto_1.randomBytes)(32);
394
- const linkCodePairingExpanded = (0, Utils_1.hkdf)(companionSharedKey, 32, {
541
+ const linkCodePairingExpanded = await (0, Utils_1.hkdf)(companionSharedKey, 32, {
395
542
  salt: linkCodeSalt,
396
543
  info: 'link_code_pairing_key_bundle_encryption_key'
397
544
  });
@@ -401,7 +548,7 @@ const makeMessagesRecvSocket = (config) => {
401
548
  const encryptedPayload = Buffer.concat([linkCodeSalt, encryptIv, encrypted]);
402
549
  const identitySharedKey = Utils_1.Curve.sharedKey(authState.creds.signedIdentityKey.private, primaryIdentityPublicKey);
403
550
  const identityPayload = Buffer.concat([companionSharedKey, identitySharedKey, random]);
404
- authState.creds.advSecretKey = (0, Utils_1.hkdf)(identityPayload, 32, { info: 'adv_secret' }).toString('base64');
551
+ authState.creds.advSecretKey = (await (0, Utils_1.hkdf)(identityPayload, 32, { info: 'adv_secret' })).toString('base64');
405
552
  await query({
406
553
  tag: 'iq',
407
554
  attrs: {
@@ -444,10 +591,10 @@ const makeMessagesRecvSocket = (config) => {
444
591
  return result;
445
592
  }
446
593
  };
447
- function decipherLinkPublicKey(data) {
594
+ async function decipherLinkPublicKey(data) {
448
595
  const buffer = toRequiredBuffer(data);
449
596
  const salt = buffer.slice(0, 32);
450
- const secretKey = (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
597
+ const secretKey = await (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
451
598
  const iv = buffer.slice(32, 48);
452
599
  const payload = buffer.slice(48, 80);
453
600
  return (0, Utils_1.aesDecryptCTR)(payload, secretKey, iv);
@@ -470,6 +617,7 @@ const makeMessagesRecvSocket = (config) => {
470
617
  };
471
618
  const sendMessagesAgain = async (key, ids, retryNode) => {
472
619
  var _a;
620
+ // todo: implement a cache to store the last 256 sent messages (copy whatsmeow)
473
621
  const msgs = await Promise.all(ids.map(id => getMessage({ ...key, id })));
474
622
  const remoteJid = key.remoteJid;
475
623
  const participant = key.participant || remoteJid;
@@ -482,8 +630,7 @@ const makeMessagesRecvSocket = (config) => {
482
630
  await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } });
483
631
  }
484
632
  logger.debug({ participant, sendToAll }, 'forced new session for retry recp');
485
- for (let i = 0; i < msgs.length; i++) {
486
- const msg = msgs[i];
633
+ for (const [i, msg] of msgs.entries()) {
487
634
  if (msg) {
488
635
  updateSendMessageAgainCount(ids[i], participant);
489
636
  const msgRelayOpts = { messageId: ids[i] };
@@ -509,7 +656,7 @@ const makeMessagesRecvSocket = (config) => {
509
656
  const isLid = attrs.from.includes('lid');
510
657
  const isNodeFromMe = (0, WABinary_1.areJidsSameUser)(attrs.participant || attrs.from, isLid ? (_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.lid : (_b = authState.creds.me) === null || _b === void 0 ? void 0 : _b.id);
511
658
  const remoteJid = !isNodeFromMe || (0, WABinary_1.isJidGroup)(attrs.from) ? attrs.from : attrs.recipient;
512
- const fromMe = !attrs.recipient || (attrs.type === 'retry' && isNodeFromMe);
659
+ const fromMe = !attrs.recipient || ((attrs.type === 'retry' || attrs.type === 'sender') && isNodeFromMe);
513
660
  const key = {
514
661
  remoteJid,
515
662
  id: '',
@@ -526,59 +673,63 @@ const makeMessagesRecvSocket = (config) => {
526
673
  const items = (0, WABinary_1.getBinaryNodeChildren)(content[0], 'item');
527
674
  ids.push(...items.map(i => i.attrs.id));
528
675
  }
529
- await Promise.all([
530
- processingMutex.mutex(async () => {
531
- const status = (0, Utils_1.getStatusFromReceiptType)(attrs.type);
532
- if (typeof status !== 'undefined' &&
533
- (
534
- // basically, we only want to know when a message from us has been delivered to/read by the other person
535
- // or another device of ours has read some messages
536
- status > WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ||
537
- !isNodeFromMe)) {
538
- if ((0, WABinary_1.isJidGroup)(remoteJid)) {
539
- if (attrs.participant) {
540
- const updateKey = status === WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
541
- ev.emit('message-receipt.update', ids.map(id => ({
676
+ try {
677
+ await Promise.all([
678
+ processingMutex.mutex(async () => {
679
+ const status = (0, Utils_1.getStatusFromReceiptType)(attrs.type);
680
+ if (typeof status !== 'undefined' &&
681
+ (
682
+ // basically, we only want to know when a message from us has been delivered to/read by the other person
683
+ // or another device of ours has read some messages
684
+ status >= WAProto_1.proto.WebMessageInfo.Status.SERVER_ACK ||
685
+ !isNodeFromMe)) {
686
+ if ((0, WABinary_1.isJidGroup)(remoteJid) || (0, WABinary_1.isJidStatusBroadcast)(remoteJid)) {
687
+ if (attrs.participant) {
688
+ const updateKey = status === WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
689
+ ev.emit('message-receipt.update', ids.map(id => ({
690
+ key: { ...key, id },
691
+ receipt: {
692
+ userJid: (0, WABinary_1.jidNormalizedUser)(attrs.participant),
693
+ [updateKey]: +attrs.t
694
+ }
695
+ })));
696
+ }
697
+ }
698
+ else {
699
+ ev.emit('messages.update', ids.map(id => ({
542
700
  key: { ...key, id },
543
- receipt: {
544
- userJid: (0, WABinary_1.jidNormalizedUser)(attrs.participant),
545
- [updateKey]: +attrs.t
546
- }
701
+ update: { status }
547
702
  })));
548
703
  }
549
704
  }
550
- else {
551
- ev.emit('messages.update', ids.map(id => ({
552
- key: { ...key, id },
553
- update: { status }
554
- })));
555
- }
556
- }
557
- if (attrs.type === 'retry') {
558
- // correctly set who is asking for the retry
559
- key.participant = key.participant || attrs.from;
560
- const retryNode = (0, WABinary_1.getBinaryNodeChild)(node, 'retry');
561
- if (willSendMessageAgain(ids[0], key.participant)) {
562
- if (key.fromMe) {
563
- try {
564
- logger.debug({ attrs, key }, 'recv retry request');
565
- await sendMessagesAgain(key, ids, retryNode);
705
+ if (attrs.type === 'retry') {
706
+ // correctly set who is asking for the retry
707
+ key.participant = key.participant || attrs.from;
708
+ const retryNode = (0, WABinary_1.getBinaryNodeChild)(node, 'retry');
709
+ if (willSendMessageAgain(ids[0], key.participant)) {
710
+ if (key.fromMe) {
711
+ try {
712
+ logger.debug({ attrs, key }, 'recv retry request');
713
+ await sendMessagesAgain(key, ids, retryNode);
714
+ }
715
+ catch (error) {
716
+ logger.error({ key, ids, trace: error.stack }, 'error in sending message again');
717
+ }
566
718
  }
567
- catch (error) {
568
- logger.error({ key, ids, trace: error.stack }, 'error in sending message again');
719
+ else {
720
+ logger.info({ attrs, key }, 'recv retry for not fromMe message');
569
721
  }
570
722
  }
571
723
  else {
572
- logger.info({ attrs, key }, 'recv retry for not fromMe message');
724
+ logger.info({ attrs, key }, 'will not send message again, as sent too many times');
573
725
  }
574
726
  }
575
- else {
576
- logger.info({ attrs, key }, 'will not send message again, as sent too many times');
577
- }
578
- }
579
- }),
580
- sendMessageAck(node)
581
- ]);
727
+ })
728
+ ]);
729
+ }
730
+ finally {
731
+ await sendMessageAck(node);
732
+ }
582
733
  };
583
734
  const handleNotification = async (node) => {
584
735
  const remoteJid = node.attrs.from;
@@ -587,27 +738,31 @@ const makeMessagesRecvSocket = (config) => {
587
738
  await sendMessageAck(node);
588
739
  return;
589
740
  }
590
- await Promise.all([
591
- processingMutex.mutex(async () => {
592
- var _a;
593
- const msg = await processNotification(node);
594
- if (msg) {
595
- const fromMe = (0, WABinary_1.areJidsSameUser)(node.attrs.participant || remoteJid, authState.creds.me.id);
596
- msg.key = {
597
- remoteJid,
598
- fromMe,
599
- participant: node.attrs.participant,
600
- id: node.attrs.id,
601
- ...(msg.key || {})
602
- };
603
- (_a = msg.participant) !== null && _a !== void 0 ? _a : (msg.participant = node.attrs.participant);
604
- msg.messageTimestamp = +node.attrs.t;
605
- const fullMsg = WAProto_1.proto.WebMessageInfo.fromObject(msg);
606
- await upsertMessage(fullMsg, 'append');
607
- }
608
- }),
609
- sendMessageAck(node)
610
- ]);
741
+ try {
742
+ await Promise.all([
743
+ processingMutex.mutex(async () => {
744
+ var _a;
745
+ const msg = await processNotification(node);
746
+ if (msg) {
747
+ const fromMe = (0, WABinary_1.areJidsSameUser)(node.attrs.participant || remoteJid, authState.creds.me.id);
748
+ msg.key = {
749
+ remoteJid,
750
+ fromMe,
751
+ participant: node.attrs.participant,
752
+ id: node.attrs.id,
753
+ ...(msg.key || {})
754
+ };
755
+ (_a = msg.participant) !== null && _a !== void 0 ? _a : (msg.participant = node.attrs.participant);
756
+ msg.messageTimestamp = +node.attrs.t;
757
+ const fullMsg = WAProto_1.proto.WebMessageInfo.fromObject(msg);
758
+ await upsertMessage(fullMsg, 'append');
759
+ }
760
+ })
761
+ ]);
762
+ }
763
+ finally {
764
+ await sendMessageAck(node);
765
+ }
611
766
  };
612
767
  const handleMessage = async (node) => {
613
768
  var _a, _b, _c;
@@ -638,25 +793,7 @@ const makeMessagesRecvSocket = (config) => {
638
793
  placeholderResendCache.del(node.attrs.id);
639
794
  }
640
795
  }
641
- let msg;
642
- let category;
643
- let author;
644
- let decrypt;
645
-
646
- try {
647
- const decryptionResult = (0, Utils_1.decryptMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
648
- msg = decryptionResult.fullMessage;
649
- category = decryptionResult.category;
650
- author = decryptionResult.author;
651
- decrypt = decryptionResult.decrypt;
652
- } catch (error) {
653
- if (error.message.includes('Bad MAC')) {
654
- logger.error({ key: node.attrs.key, error: error.stack }, 'Bad MAC error, triggering retry');
655
- await sendRetryRequest(node, true); // Force include keys to reset session
656
- return;
657
- }
658
- throw error;
659
- }
796
+ const { fullMessage: msg, category, author, decrypt } = (0, Utils_1.decryptMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
660
797
  if (response && ((_a = msg === null || msg === void 0 ? void 0 : msg.messageStubParameters) === null || _a === void 0 ? void 0 : _a[0]) === Utils_1.NO_MESSAGE_FOUND_ERROR_TEXT) {
661
798
  msg.messageStubParameters = [Utils_1.NO_MESSAGE_FOUND_ERROR_TEXT, response];
662
799
  }
@@ -738,6 +875,54 @@ const makeMessagesRecvSocket = (config) => {
738
875
  logger.error({ error, node }, 'error in handling message');
739
876
  }
740
877
  };
878
+ const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
879
+ var _a;
880
+ if (!((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id)) {
881
+ throw new boom_1.Boom('Not authenticated');
882
+ }
883
+ const pdoMessage = {
884
+ historySyncOnDemandRequest: {
885
+ chatJid: oldestMsgKey.remoteJid,
886
+ oldestMsgFromMe: oldestMsgKey.fromMe,
887
+ oldestMsgId: oldestMsgKey.id,
888
+ oldestMsgTimestampMs: oldestMsgTimestamp,
889
+ onDemandMsgCount: count
890
+ },
891
+ peerDataOperationRequestType: WAProto_1.proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
892
+ };
893
+ return sendPeerDataOperationMessage(pdoMessage);
894
+ };
895
+ const requestPlaceholderResend = async (messageKey) => {
896
+ var _a;
897
+ if (!((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id)) {
898
+ throw new boom_1.Boom('Not authenticated');
899
+ }
900
+ if (placeholderResendCache.get(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id)) {
901
+ logger.debug({ messageKey }, 'already requested resend');
902
+ return;
903
+ }
904
+ else {
905
+ placeholderResendCache.set(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id, true);
906
+ }
907
+ await (0, Utils_1.delay)(5000);
908
+ if (!placeholderResendCache.get(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id)) {
909
+ logger.debug({ messageKey }, 'message received while resend requested');
910
+ return 'RESOLVED';
911
+ }
912
+ const pdoMessage = {
913
+ placeholderMessageResendRequest: [{
914
+ messageKey
915
+ }],
916
+ peerDataOperationRequestType: WAProto_1.proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
917
+ };
918
+ setTimeout(() => {
919
+ if (placeholderResendCache.get(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id)) {
920
+ logger.debug({ messageKey }, 'PDO message without response after 15 seconds. Phone possibly offline');
921
+ placeholderResendCache.del(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id);
922
+ }
923
+ }, 15000);
924
+ return sendPeerDataOperationMessage(pdoMessage);
925
+ };
741
926
  const handleCall = async (node) => {
742
927
  const { attrs } = node;
743
928
  const [infoChild] = (0, WABinary_1.getAllBinaryNodeChildren)(node);
@@ -765,22 +950,30 @@ const makeMessagesRecvSocket = (config) => {
765
950
  call.isGroup = existingCall.isGroup;
766
951
  }
767
952
  // delete data once call has ended
768
- if (status === 'reject' || status === 'accept' || status === 'timeout') {
953
+ if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
769
954
  callOfferCache.del(call.id);
770
955
  }
771
956
  ev.emit('call', [call]);
772
957
  await sendMessageAck(node);
773
958
  };
774
959
  const handleBadAck = async ({ attrs }) => {
775
- const key = { remoteJid: attrs.from, fromMe: true, id: attrs.id };
960
+ const key = { remoteJid: attrs.from, fromMe: true, id: attrs.id, 'server_id': attrs === null || attrs === void 0 ? void 0 : attrs.server_id };
776
961
  // current hypothesis is that if pash is sent in the ack
777
962
  // it means -- the message hasn't reached all devices yet
778
963
  // we'll retry sending the message here
779
964
  if (attrs.phash) {
780
965
  logger.info({ attrs }, 'received phash in ack, resending message...');
966
+ const cacheKey = `${key.remoteJid}:${key.id}`;
967
+ if ((msgRetryCache.get(cacheKey) || 0) >= maxMsgRetryCount) {
968
+ logger.warn({ attrs }, 'reached max retry count, not sending message again');
969
+ msgRetryCache.del(cacheKey);
970
+ return;
971
+ }
972
+ const retryCount = msgRetryCache.get(cacheKey) || 0;
781
973
  const msg = await getMessage(key);
782
974
  if (msg) {
783
975
  await relayMessage(key.remoteJid, msg, { messageId: key.id, useUserDevicesCache: false });
976
+ msgRetryCache.set(cacheKey, retryCount + 1);
784
977
  }
785
978
  else {
786
979
  logger.warn({ attrs }, 'could not send message again, as it was not found');
@@ -810,22 +1003,63 @@ const makeMessagesRecvSocket = (config) => {
810
1003
  await execTask();
811
1004
  ev.flush();
812
1005
  function execTask() {
813
- return exec(node)
1006
+ return exec(node, false)
814
1007
  .catch(err => onUnexpectedError(err, identifier));
815
1008
  }
816
1009
  };
1010
+ const makeOfflineNodeProcessor = () => {
1011
+ const nodeProcessorMap = new Map([
1012
+ ['message', handleMessage],
1013
+ ['call', handleCall],
1014
+ ['receipt', handleReceipt],
1015
+ ['notification', handleNotification]
1016
+ ]);
1017
+ const nodes = [];
1018
+ let isProcessing = false;
1019
+ const enqueue = (type, node) => {
1020
+ nodes.push({ type, node });
1021
+ if (isProcessing) {
1022
+ return;
1023
+ }
1024
+ isProcessing = true;
1025
+ const promise = async () => {
1026
+ while (nodes.length && ws.isOpen) {
1027
+ const { type, node } = nodes.shift();
1028
+ const nodeProcessor = nodeProcessorMap.get(type);
1029
+ if (!nodeProcessor) {
1030
+ onUnexpectedError(new Error(`unknown offline node type: ${type}`), 'processing offline node');
1031
+ continue;
1032
+ }
1033
+ await nodeProcessor(node);
1034
+ }
1035
+ isProcessing = false;
1036
+ };
1037
+ promise().catch(error => onUnexpectedError(error, 'processing offline nodes'));
1038
+ };
1039
+ return { enqueue };
1040
+ };
1041
+ const offlineNodeProcessor = makeOfflineNodeProcessor();
1042
+ const processNode = (type, node, identifier, exec) => {
1043
+ const isOffline = !!node.attrs.offline;
1044
+ if (isOffline) {
1045
+ offlineNodeProcessor.enqueue(type, node);
1046
+ }
1047
+ else {
1048
+ processNodeWithBuffer(node, identifier, exec);
1049
+ }
1050
+ };
817
1051
  // recv a message
818
1052
  ws.on('CB:message', (node) => {
819
- processNodeWithBuffer(node, 'processing message', handleMessage);
1053
+ processNode('message', node, 'processing message', handleMessage);
820
1054
  });
821
1055
  ws.on('CB:call', async (node) => {
822
- processNodeWithBuffer(node, 'handling call', handleCall);
1056
+ processNode('call', node, 'handling call', handleCall);
823
1057
  });
824
1058
  ws.on('CB:receipt', node => {
825
- processNodeWithBuffer(node, 'handling receipt', handleReceipt);
1059
+ processNode('receipt', node, 'handling receipt', handleReceipt);
826
1060
  });
827
1061
  ws.on('CB:notification', async (node) => {
828
- processNodeWithBuffer(node, 'handling notification', handleNotification);
1062
+ processNode('notification', node, 'handling notification', handleNotification);
829
1063
  });
830
1064
  ws.on('CB:ack,class:message', (node) => {
831
1065
  handleBadAck(node)
@@ -867,8 +1101,10 @@ const makeMessagesRecvSocket = (config) => {
867
1101
  ...sock,
868
1102
  sendMessageAck,
869
1103
  sendRetryRequest,
1104
+ rejectCall,
870
1105
  offerCall,
871
- rejectCall
1106
+ fetchMessageHistory,
1107
+ requestPlaceholderResend,
872
1108
  };
873
1109
  };
874
1110
  exports.makeMessagesRecvSocket = makeMessagesRecvSocket;