dcodeindra-baileyspro 2.3.9

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 (286) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2534 -0
  3. package/WAProto/Adv/Adv.d.ts +518 -0
  4. package/WAProto/Adv/Adv.js +1734 -0
  5. package/WAProto/Adv/Adv.proto +36 -0
  6. package/WAProto/BotMetadata/BotMetadata.d.ts +5745 -0
  7. package/WAProto/BotMetadata/BotMetadata.js +16291 -0
  8. package/WAProto/BotMetadata/BotMetadata.proto +463 -0
  9. package/WAProto/Cert/Cert.d.ts +497 -0
  10. package/WAProto/Cert/Cert.js +1503 -0
  11. package/WAProto/Cert/Cert.proto +28 -0
  12. package/WAProto/ChatLockSettings/ChatLockSettings.d.ts +391 -0
  13. package/WAProto/ChatLockSettings/ChatLockSettings.js +1155 -0
  14. package/WAProto/ChatLockSettings/ChatLockSettings.proto +7 -0
  15. package/WAProto/CompanionReg/CompanionReg.d.ts +1055 -0
  16. package/WAProto/CompanionReg/CompanionReg.js +3532 -0
  17. package/WAProto/CompanionReg/CompanionReg.proto +89 -0
  18. package/WAProto/DeviceCapabilities/DeviceCapabilities.d.ts +187 -0
  19. package/WAProto/DeviceCapabilities/DeviceCapabilities.js +520 -0
  20. package/WAProto/DeviceCapabilities/DeviceCapabilities.proto +14 -0
  21. package/WAProto/E2E/E2E.d.ts +28417 -0
  22. package/WAProto/E2E/E2E.js +98438 -0
  23. package/WAProto/E2E/E2E.proto +2289 -0
  24. package/WAProto/Ephemeral/Ephemeral.d.ts +95 -0
  25. package/WAProto/Ephemeral/Ephemeral.js +269 -0
  26. package/WAProto/Ephemeral/Ephemeral.proto +6 -0
  27. package/WAProto/HistorySync/HistorySync.d.ts +40728 -0
  28. package/WAProto/HistorySync/HistorySync.js +142980 -0
  29. package/WAProto/HistorySync/HistorySync.proto +207 -0
  30. package/WAProto/LidMigrationSyncPayload/LidMigrationSyncPayload.d.ts +189 -0
  31. package/WAProto/LidMigrationSyncPayload/LidMigrationSyncPayload.js +585 -0
  32. package/WAProto/LidMigrationSyncPayload/LidMigrationSyncPayload.proto +11 -0
  33. package/WAProto/MdStorageChatRowOpaqueData/MdStorageChatRowOpaqueData.d.ts +461 -0
  34. package/WAProto/MdStorageChatRowOpaqueData/MdStorageChatRowOpaqueData.js +1559 -0
  35. package/WAProto/MdStorageChatRowOpaqueData/MdStorageChatRowOpaqueData.proto +37 -0
  36. package/WAProto/MdStorageMsgRowOpaqueData/MdStorageMsgRowOpaqueData.d.ts +29294 -0
  37. package/WAProto/MdStorageMsgRowOpaqueData/MdStorageMsgRowOpaqueData.js +101732 -0
  38. package/WAProto/MdStorageMsgRowOpaqueData/MdStorageMsgRowOpaqueData.proto +76 -0
  39. package/WAProto/MmsRetry/MmsRetry.d.ts +200 -0
  40. package/WAProto/MmsRetry/MmsRetry.js +586 -0
  41. package/WAProto/MmsRetry/MmsRetry.proto +17 -0
  42. package/WAProto/Protocol/Protocol.d.ts +218 -0
  43. package/WAProto/Protocol/Protocol.js +701 -0
  44. package/WAProto/Protocol/Protocol.proto +20 -0
  45. package/WAProto/Reporting/Reporting.d.ts +301 -0
  46. package/WAProto/Reporting/Reporting.js +989 -0
  47. package/WAProto/Reporting/Reporting.proto +19 -0
  48. package/WAProto/ServerSync/ServerSync.d.ts +1050 -0
  49. package/WAProto/ServerSync/ServerSync.js +3176 -0
  50. package/WAProto/ServerSync/ServerSync.proto +59 -0
  51. package/WAProto/SignalLocalStorageProtocol/SignalLocalStorageProtocol.d.ts +1507 -0
  52. package/WAProto/SignalLocalStorageProtocol/SignalLocalStorageProtocol.js +4756 -0
  53. package/WAProto/SignalLocalStorageProtocol/SignalLocalStorageProtocol.proto +88 -0
  54. package/WAProto/SignalWhisperTextProtocol/SignalWhisperTextProtocol.d.ts +617 -0
  55. package/WAProto/SignalWhisperTextProtocol/SignalWhisperTextProtocol.js +1940 -0
  56. package/WAProto/SignalWhisperTextProtocol/SignalWhisperTextProtocol.proto +38 -0
  57. package/WAProto/StatusAttributions/StatusAttributions.d.ts +636 -0
  58. package/WAProto/StatusAttributions/StatusAttributions.js +2037 -0
  59. package/WAProto/StatusAttributions/StatusAttributions.proto +61 -0
  60. package/WAProto/SyncAction/SyncAction.d.ts +7227 -0
  61. package/WAProto/SyncAction/SyncAction.js +22271 -0
  62. package/WAProto/SyncAction/SyncAction.proto +423 -0
  63. package/WAProto/UserPassword/UserPassword.d.ts +298 -0
  64. package/WAProto/UserPassword/UserPassword.js +898 -0
  65. package/WAProto/UserPassword/UserPassword.proto +27 -0
  66. package/WAProto/VnameCert/VnameCert.d.ts +658 -0
  67. package/WAProto/VnameCert/VnameCert.js +2225 -0
  68. package/WAProto/VnameCert/VnameCert.proto +60 -0
  69. package/WAProto/Wa6/Wa6.d.ts +1613 -0
  70. package/WAProto/Wa6/Wa6.js +6299 -0
  71. package/WAProto/Wa6/Wa6.proto +229 -0
  72. package/WAProto/Web/Web.d.ts +31718 -0
  73. package/WAProto/Web/Web.js +113402 -0
  74. package/WAProto/Web/Web.proto +545 -0
  75. package/WAProto/index.d.ts +49 -0
  76. package/WAProto/index.js +28 -0
  77. package/WASignalGroup/GroupProtocol.js +1771 -0
  78. package/WASignalGroup/ciphertext_message.js +10 -0
  79. package/WASignalGroup/group_cipher.js +103 -0
  80. package/WASignalGroup/group_session_builder.js +39 -0
  81. package/WASignalGroup/index.js +5 -0
  82. package/WASignalGroup/keyhelper.js +17 -0
  83. package/WASignalGroup/protobufs.js +2 -0
  84. package/WASignalGroup/queue_job.js +64 -0
  85. package/WASignalGroup/sender_chain_key.js +38 -0
  86. package/WASignalGroup/sender_key_distribution_message.js +68 -0
  87. package/WASignalGroup/sender_key_message.js +79 -0
  88. package/WASignalGroup/sender_key_name.js +59 -0
  89. package/WASignalGroup/sender_key_record.js +47 -0
  90. package/WASignalGroup/sender_key_state.js +110 -0
  91. package/WASignalGroup/sender_message_key.js +30 -0
  92. package/check-node-version.js +10 -0
  93. package/lib/Defaults/baileys-version.json +3 -0
  94. package/lib/Defaults/index.d.ts +51 -0
  95. package/lib/Defaults/index.js +108 -0
  96. package/lib/Defaults/phonenumber-mcc.json +223 -0
  97. package/lib/Signal/Group/ciphertext-message.d.ts +9 -0
  98. package/lib/Signal/Group/ciphertext-message.js +19 -0
  99. package/lib/Signal/Group/group-session-builder.d.ts +17 -0
  100. package/lib/Signal/Group/group-session-builder.js +72 -0
  101. package/lib/Signal/Group/group_cipher.d.ts +19 -0
  102. package/lib/Signal/Group/group_cipher.js +99 -0
  103. package/lib/Signal/Group/index.d.ts +11 -0
  104. package/lib/Signal/Group/index.js +61 -0
  105. package/lib/Signal/Group/keyhelper.d.ts +16 -0
  106. package/lib/Signal/Group/keyhelper.js +66 -0
  107. package/lib/Signal/Group/queue-job.d.ts +1 -0
  108. package/lib/Signal/Group/queue-job.js +64 -0
  109. package/lib/Signal/Group/sender-chain-key.d.ts +14 -0
  110. package/lib/Signal/Group/sender-chain-key.js +39 -0
  111. package/lib/Signal/Group/sender-key-distribution-message.d.ts +17 -0
  112. package/lib/Signal/Group/sender-key-distribution-message.js +71 -0
  113. package/lib/Signal/Group/sender-key-message.d.ts +19 -0
  114. package/lib/Signal/Group/sender-key-message.js +73 -0
  115. package/lib/Signal/Group/sender-key-name.d.ts +19 -0
  116. package/lib/Signal/Group/sender-key-name.js +59 -0
  117. package/lib/Signal/Group/sender-key-record.d.ts +32 -0
  118. package/lib/Signal/Group/sender-key-record.js +53 -0
  119. package/lib/Signal/Group/sender-key-record.ts +77 -0
  120. package/lib/Signal/Group/sender-key-state.d.ts +44 -0
  121. package/lib/Signal/Group/sender-key-state.js +104 -0
  122. package/lib/Signal/Group/sender-message-key.d.ts +11 -0
  123. package/lib/Signal/Group/sender-message-key.js +33 -0
  124. package/lib/Signal/libsignal.d.ts +3 -0
  125. package/lib/Signal/libsignal.js +153 -0
  126. package/lib/Socket/Client/index.d.ts +2 -0
  127. package/lib/Socket/Client/index.js +18 -0
  128. package/lib/Socket/Client/types.d.ts +15 -0
  129. package/lib/Socket/Client/types.js +14 -0
  130. package/lib/Socket/Client/websocket.d.ts +12 -0
  131. package/lib/Socket/Client/websocket.js +57 -0
  132. package/lib/Socket/business.d.ts +181 -0
  133. package/lib/Socket/business.js +259 -0
  134. package/lib/Socket/chats.d.ts +95 -0
  135. package/lib/Socket/chats.js +906 -0
  136. package/lib/Socket/community.d.ts +131 -0
  137. package/lib/Socket/community.js +369 -0
  138. package/lib/Socket/groups.d.ts +122 -0
  139. package/lib/Socket/groups.js +360 -0
  140. package/lib/Socket/index.d.ts +183 -0
  141. package/lib/Socket/index.js +10 -0
  142. package/lib/Socket/messages-recv.d.ts +170 -0
  143. package/lib/Socket/messages-recv.js +1074 -0
  144. package/lib/Socket/messages-send.d.ts +161 -0
  145. package/lib/Socket/messages-send.js +982 -0
  146. package/lib/Socket/newsletter.d.ts +140 -0
  147. package/lib/Socket/newsletter.js +242 -0
  148. package/lib/Socket/socket.d.ts +43 -0
  149. package/lib/Socket/socket.js +749 -0
  150. package/lib/Socket/usync.d.ts +36 -0
  151. package/lib/Socket/usync.js +71 -0
  152. package/lib/Store/index.d.ts +4 -0
  153. package/lib/Store/index.js +20 -0
  154. package/lib/Store/make-cache-manager-store.d.ts +13 -0
  155. package/lib/Store/make-cache-manager-store.js +77 -0
  156. package/lib/Store/make-in-memory-store.d.ts +117 -0
  157. package/lib/Store/make-in-memory-store.js +420 -0
  158. package/lib/Store/make-ordered-dictionary.d.ts +12 -0
  159. package/lib/Store/make-ordered-dictionary.js +83 -0
  160. package/lib/Store/object-repository.d.ts +10 -0
  161. package/lib/Store/object-repository.js +28 -0
  162. package/lib/Types/Auth.d.ts +103 -0
  163. package/lib/Types/Auth.js +2 -0
  164. package/lib/Types/Call.d.ts +13 -0
  165. package/lib/Types/Call.js +2 -0
  166. package/lib/Types/Chat.d.ts +115 -0
  167. package/lib/Types/Chat.js +6 -0
  168. package/lib/Types/Contact.d.ts +35 -0
  169. package/lib/Types/Contact.js +2 -0
  170. package/lib/Types/Events.d.ts +208 -0
  171. package/lib/Types/Events.js +2 -0
  172. package/lib/Types/GroupMetadata.d.ts +81 -0
  173. package/lib/Types/GroupMetadata.js +2 -0
  174. package/lib/Types/Label.d.ts +46 -0
  175. package/lib/Types/Label.js +28 -0
  176. package/lib/Types/LabelAssociation.d.ts +29 -0
  177. package/lib/Types/LabelAssociation.js +10 -0
  178. package/lib/Types/Message.d.ts +480 -0
  179. package/lib/Types/Message.js +9 -0
  180. package/lib/Types/MexUpdates.d.ts +9 -0
  181. package/lib/Types/MexUpdates.js +18 -0
  182. package/lib/Types/Newsletter.d.ts +92 -0
  183. package/lib/Types/Newsletter.js +33 -0
  184. package/lib/Types/Product.d.ts +78 -0
  185. package/lib/Types/Product.js +2 -0
  186. package/lib/Types/Signal.d.ts +57 -0
  187. package/lib/Types/Signal.js +2 -0
  188. package/lib/Types/Socket.d.ts +116 -0
  189. package/lib/Types/Socket.js +2 -0
  190. package/lib/Types/State.d.ts +27 -0
  191. package/lib/Types/State.js +2 -0
  192. package/lib/Types/USync.d.ts +25 -0
  193. package/lib/Types/USync.js +2 -0
  194. package/lib/Types/index.d.ts +70 -0
  195. package/lib/Types/index.js +42 -0
  196. package/lib/Utils/auth-utils.d.ts +18 -0
  197. package/lib/Utils/auth-utils.js +198 -0
  198. package/lib/Utils/baileys-event-stream.d.ts +16 -0
  199. package/lib/Utils/baileys-event-stream.js +64 -0
  200. package/lib/Utils/business.d.ts +22 -0
  201. package/lib/Utils/business.js +243 -0
  202. package/lib/Utils/chat-utils.d.ts +72 -0
  203. package/lib/Utils/chat-utils.js +762 -0
  204. package/lib/Utils/crypto.d.ts +40 -0
  205. package/lib/Utils/crypto.js +150 -0
  206. package/lib/Utils/decode-wa-message.d.ts +252 -0
  207. package/lib/Utils/decode-wa-message.js +232 -0
  208. package/lib/Utils/event-buffer.d.ts +35 -0
  209. package/lib/Utils/event-buffer.js +539 -0
  210. package/lib/Utils/generics.d.ts +96 -0
  211. package/lib/Utils/generics.js +553 -0
  212. package/lib/Utils/history.d.ts +29 -0
  213. package/lib/Utils/history.js +109 -0
  214. package/lib/Utils/index.d.ts +19 -0
  215. package/lib/Utils/index.js +35 -0
  216. package/lib/Utils/link-preview.d.ts +21 -0
  217. package/lib/Utils/link-preview.js +112 -0
  218. package/lib/Utils/logger.d.ts +11 -0
  219. package/lib/Utils/logger.js +7 -0
  220. package/lib/Utils/lt-hash.d.ts +12 -0
  221. package/lib/Utils/lt-hash.js +53 -0
  222. package/lib/Utils/make-mutex.d.ts +7 -0
  223. package/lib/Utils/make-mutex.js +45 -0
  224. package/lib/Utils/messages-media.d.ts +104 -0
  225. package/lib/Utils/messages-media.js +751 -0
  226. package/lib/Utils/messages.d.ts +80 -0
  227. package/lib/Utils/messages.js +1741 -0
  228. package/lib/Utils/noise-handler.d.ts +19 -0
  229. package/lib/Utils/noise-handler.js +150 -0
  230. package/lib/Utils/process-message.d.ts +41 -0
  231. package/lib/Utils/process-message.js +391 -0
  232. package/lib/Utils/signal.d.ts +33 -0
  233. package/lib/Utils/signal.js +154 -0
  234. package/lib/Utils/use-mongo-file-auth-state.d.ts +5 -0
  235. package/lib/Utils/use-mongo-file-auth-state.js +75 -0
  236. package/lib/Utils/use-multi-file-auth-state.d.ts +12 -0
  237. package/lib/Utils/use-multi-file-auth-state.js +123 -0
  238. package/lib/Utils/use-single-file-auth-state.d.ts +12 -0
  239. package/lib/Utils/use-single-file-auth-state.js +75 -0
  240. package/lib/Utils/validate-connection.d.ts +10 -0
  241. package/lib/Utils/validate-connection.js +174 -0
  242. package/lib/WABinary/constants.d.ts +27 -0
  243. package/lib/WABinary/constants.js +45 -0
  244. package/lib/WABinary/decode.d.ts +6 -0
  245. package/lib/WABinary/decode.js +255 -0
  246. package/lib/WABinary/encode.d.ts +2 -0
  247. package/lib/WABinary/encode.js +243 -0
  248. package/lib/WABinary/generic-utils.d.ts +16 -0
  249. package/lib/WABinary/generic-utils.js +125 -0
  250. package/lib/WABinary/index.d.ts +5 -0
  251. package/lib/WABinary/index.js +21 -0
  252. package/lib/WABinary/jid-utils.d.ts +34 -0
  253. package/lib/WABinary/jid-utils.js +73 -0
  254. package/lib/WABinary/types.d.ts +18 -0
  255. package/lib/WABinary/types.js +2 -0
  256. package/lib/WAM/BinaryInfo.d.ts +16 -0
  257. package/lib/WAM/BinaryInfo.js +14 -0
  258. package/lib/WAM/constants.d.ts +39 -0
  259. package/lib/WAM/constants.js +15362 -0
  260. package/lib/WAM/encode.d.ts +2 -0
  261. package/lib/WAM/encode.js +156 -0
  262. package/lib/WAM/index.d.ts +3 -0
  263. package/lib/WAM/index.js +19 -0
  264. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.d.ts +25 -0
  265. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +60 -0
  266. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -0
  267. package/lib/WAUSync/Protocols/USyncContactProtocol.js +32 -0
  268. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -0
  269. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +58 -0
  270. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -0
  271. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +31 -0
  272. package/lib/WAUSync/Protocols/USyncLIDProtocol.d.ts +8 -0
  273. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +26 -0
  274. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -0
  275. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +42 -0
  276. package/lib/WAUSync/Protocols/index.d.ts +6 -0
  277. package/lib/WAUSync/Protocols/index.js +22 -0
  278. package/lib/WAUSync/USyncQuery.d.ts +28 -0
  279. package/lib/WAUSync/USyncQuery.js +88 -0
  280. package/lib/WAUSync/USyncUser.d.ts +12 -0
  281. package/lib/WAUSync/USyncUser.js +27 -0
  282. package/lib/WAUSync/index.d.ts +3 -0
  283. package/lib/WAUSync/index.js +19 -0
  284. package/lib/index.d.ts +13 -0
  285. package/lib/index.js +45 -0
  286. package/package.json +63 -0
@@ -0,0 +1,1074 @@
1
+ "use strict"
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod }
4
+ }
5
+ Object.defineProperty(exports, "__esModule", { value: true })
6
+ const node_cache_1 = __importDefault(require("@cacheable/node-cache"))
7
+ const boom_1 = require("@hapi/boom")
8
+ const crypto_1 = require("crypto")
9
+ const WAProto_1 = require("../../WAProto")
10
+ const Defaults_1 = require("../Defaults")
11
+ const Types_1 = require("../Types")
12
+ const Utils_1 = require("../Utils")
13
+ const make_mutex_1 = require("../Utils/make-mutex")
14
+ const WABinary_1 = require("../WABinary")
15
+ const groups_1 = require("./groups")
16
+ const messages_send_1 = require("./messages-send")
17
+ const makeMessagesRecvSocket = (config) => {
18
+ const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid } = config
19
+ const sock = messages_send_1.makeMessagesSocket(config)
20
+ const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, getUSyncDevices, createParticipantNodes, sendPeerDataOperationMessage } = sock
21
+ /** this mutex ensures that each retryRequest will wait for the previous one to finish */
22
+ const retryMutex = make_mutex_1.makeMutex()
23
+ const msgRetryCache = config.msgRetryCounterCache || new node_cache_1.default({
24
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY,
25
+ useClones: false
26
+ })
27
+ const callOfferCache = config.callOfferCache || new node_cache_1.default({
28
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.CALL_OFFER,
29
+ useClones: false
30
+ })
31
+ const placeholderResendCache = config.placeholderResendCache || new node_cache_1.default({
32
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY,
33
+ useClones: false
34
+ })
35
+ let sendActiveReceipts = false
36
+ const sendMessageAck = async ({ tag, attrs, content }, errorCode) => {
37
+ const stanza = {
38
+ tag: 'ack',
39
+ attrs: {
40
+ id: attrs.id,
41
+ to: attrs.from,
42
+ class: tag
43
+ }
44
+ }
45
+ if (!!errorCode) {
46
+ stanza.attrs.error = errorCode.toString()
47
+ }
48
+ if (!!attrs.participant) {
49
+ stanza.attrs.participant = attrs.participant
50
+ }
51
+ if (!!attrs.recipient) {
52
+ stanza.attrs.recipient = attrs.recipient
53
+ }
54
+ if (!!attrs.type && (tag !== 'message' || WABinary_1.getBinaryNodeChild({ tag, attrs, content }, 'unavailable') || errorCode !== 0)) {
55
+ stanza.attrs.type = attrs.type
56
+ }
57
+ if (tag === 'message' && WABinary_1.getBinaryNodeChild({ tag, attrs, content }, 'unavailable')) {
58
+ stanza.attrs.from = authState.creds.me.id
59
+ }
60
+ logger.debug({ recv: { tag, attrs }, sent: stanza.attrs }, 'sent ack')
61
+ await sendNode(stanza)
62
+ }
63
+ const offerCall = async (toJid, isVideo = false) => {
64
+ const callId = crypto_1.randomBytes(16).toString('hex').toUpperCase().substring(0, 64)
65
+ const offerContent = []
66
+ offerContent.push({ tag: 'audio', attrs: { enc: 'opus', rate: '16000' }, content: undefined })
67
+ offerContent.push({ tag: 'audio', attrs: { enc: 'opus', rate: '8000' }, content: undefined })
68
+ if (isVideo) {
69
+ offerContent.push({
70
+ tag: 'video',
71
+ attrs: { enc: 'vp8', dec: 'vp8', orientation: '0', 'screen_width': '1920', 'screen_height': '1080', 'device_orientation': '0' },
72
+ content: undefined
73
+ })
74
+ }
75
+ offerContent.push({ tag: 'net', attrs: { medium: '3' }, content: undefined })
76
+ offerContent.push({ tag: 'capability', attrs: { ver: '1' }, content: new Uint8Array([1, 4, 255, 131, 207, 4]) })
77
+ offerContent.push({ tag: 'encopt', attrs: { keygen: '2' }, content: undefined })
78
+ const encKey = crypto_1.randomBytes(32)
79
+ const devices = (await getUSyncDevices([toJid], true, false)).map(({ user, device }) => WABinary_1.jidEncode(user, 's.whatsapp.net', device))
80
+ await assertSessions(devices, true)
81
+ const { nodes: destinations, shouldIncludeDeviceIdentity } = await createParticipantNodes(devices, {
82
+ call: {
83
+ callKey: new Uint8Array(encKey)
84
+ }
85
+ }, { count: '0' })
86
+ offerContent.push({ tag: 'destination', attrs: {}, content: destinations })
87
+ if (shouldIncludeDeviceIdentity) {
88
+ offerContent.push({
89
+ tag: 'device-identity',
90
+ attrs: {},
91
+ content: Utils_1.encodeSignedDeviceIdentity(authState.creds.account, true)
92
+ })
93
+ }
94
+ const stanza = ({
95
+ tag: 'call',
96
+ attrs: {
97
+ id: Utils_1.generateMessageID(),
98
+ to: toJid,
99
+ },
100
+ content: [{
101
+ tag: 'offer',
102
+ attrs: {
103
+ 'call-id': callId,
104
+ 'call-creator': authState.creds.me.id,
105
+ },
106
+ content: offerContent,
107
+ }],
108
+ })
109
+ await query(stanza)
110
+ return {
111
+ id: callId,
112
+ to: toJid
113
+ }
114
+ }
115
+ const rejectCall = async (callId, callFrom) => {
116
+ const stanza = ({
117
+ tag: 'call',
118
+ attrs: {
119
+ from: authState.creds.me.id,
120
+ to: callFrom,
121
+ },
122
+ content: [{
123
+ tag: 'reject',
124
+ attrs: {
125
+ 'call-id': callId,
126
+ 'call-creator': callFrom,
127
+ count: '0',
128
+ },
129
+ content: undefined,
130
+ }],
131
+ })
132
+ await query(stanza)
133
+ }
134
+ const sendRetryRequest = async (node, forceIncludeKeys = false) => {
135
+ const { fullMessage } = Utils_1.decodeMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '')
136
+ const { key: msgKey } = fullMessage
137
+ const msgId = msgKey.id
138
+ const key = `${msgId}:${msgKey?.participant}`
139
+ let retryCount = msgRetryCache.get(key) || 0
140
+ if (retryCount >= maxMsgRetryCount) {
141
+ logger.debug({ retryCount, msgId }, 'reached retry limit, clearing')
142
+ msgRetryCache.del(key)
143
+ return
144
+ }
145
+ retryCount += 1
146
+ msgRetryCache.set(key, retryCount)
147
+ const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds
148
+ if (retryCount === 1) {
149
+ //request a resend via phone
150
+ const msgId = await requestPlaceholderResend(msgKey)
151
+ logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId}`)
152
+ }
153
+ const deviceIdentity = Utils_1.encodeSignedDeviceIdentity(account, true)
154
+ await authState.keys.transaction(async () => {
155
+ const receipt = {
156
+ tag: 'receipt',
157
+ attrs: {
158
+ id: msgId,
159
+ type: 'retry',
160
+ to: node.attrs.from
161
+ },
162
+ content: [
163
+ {
164
+ tag: 'retry',
165
+ attrs: {
166
+ count: retryCount.toString(),
167
+ id: node.attrs.id,
168
+ t: node.attrs.t,
169
+ v: '1'
170
+ }
171
+ },
172
+ {
173
+ tag: 'registration',
174
+ attrs: {},
175
+ content: Utils_1.encodeBigEndian(authState.creds.registrationId)
176
+ }
177
+ ]
178
+ }
179
+ if (node.attrs.recipient) {
180
+ receipt.attrs.recipient = node.attrs.recipient
181
+ }
182
+ if (node.attrs.participant) {
183
+ receipt.attrs.participant = node.attrs.participant
184
+ }
185
+ if (retryCount > 1 || forceIncludeKeys) {
186
+ const { update, preKeys } = await Utils_1.getNextPreKeys(authState, 1)
187
+ const [keyId] = Object.keys(preKeys)
188
+ const key = preKeys[+keyId]
189
+ const content = receipt.content
190
+ content.push({
191
+ tag: 'keys',
192
+ attrs: {},
193
+ content: [
194
+ { tag: 'type', attrs: {}, content: Buffer.from(Defaults_1.KEY_BUNDLE_TYPE) },
195
+ { tag: 'identity', attrs: {}, content: identityKey.public },
196
+ Utils_1.xmppPreKey(key, +keyId),
197
+ Utils_1.xmppSignedPreKey(signedPreKey),
198
+ { tag: 'device-identity', attrs: {}, content: deviceIdentity }
199
+ ]
200
+ })
201
+ ev.emit('creds.update', update)
202
+ }
203
+ await sendNode(receipt)
204
+ logger.info({ msgAttrs: node.attrs, retryCount }, 'sent retry receipt')
205
+ })
206
+ }
207
+ const handleEncryptNotification = async (node) => {
208
+ const from = node.attrs.from
209
+ if (from === WABinary_1.S_WHATSAPP_NET) {
210
+ const countChild = WABinary_1.getBinaryNodeChild(node, 'count')
211
+ const count = +countChild.attrs.value
212
+ const shouldUploadMorePreKeys = count < Defaults_1.MIN_PREKEY_COUNT
213
+ logger.debug({ count, shouldUploadMorePreKeys }, 'recv pre-key count')
214
+ if (shouldUploadMorePreKeys) {
215
+ await uploadPreKeys()
216
+ }
217
+ }
218
+ else {
219
+ const identityNode = WABinary_1.getBinaryNodeChild(node, 'identity')
220
+ if (identityNode) {
221
+ logger.info({ jid: from }, 'identity changed')
222
+ // not handling right now
223
+ // signal will override new identity anyway
224
+ }
225
+ else {
226
+ logger.info({ node }, 'unknown encrypt notification')
227
+ }
228
+ }
229
+ }
230
+ const handleGroupNotification = (participant, child, msg, mode) => {
231
+ const participantJid = mode === 'lid' ? WABinary_1.getBinaryNodeChild(child, 'participant')?.attrs?.phone_number : WABinary_1.getBinaryNodeChild(child, 'participant')?.attrs?.jid || participant
232
+ switch (child.tag) {
233
+ case 'create':
234
+ const metadata = groups_1.extractGroupMetadata(child)
235
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_CREATE
236
+ msg.messageStubParameters = [metadata.subject]
237
+ msg.key = { participant: metadata.owner }
238
+ ev.emit('chats.upsert', [{
239
+ id: metadata.id,
240
+ name: metadata.subject,
241
+ conversationTimestamp: metadata.creation,
242
+ }])
243
+ ev.emit('groups.upsert', [{
244
+ ...metadata,
245
+ author: participant
246
+ }])
247
+ break
248
+ case 'delete':
249
+ msg.messageStubType = Types_1.WAMessageStubType.COMMUNITY_PARENT_GROUP_DELETED
250
+ msg.messageStubParameters = [participantJid, 'delete']
251
+ break
252
+ case 'ephemeral':
253
+ case 'not_ephemeral':
254
+ msg.message = {
255
+ protocolMessage: {
256
+ type: WAProto_1.proto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
257
+ ephemeralExpiration: +(child.attrs.expiration || 0)
258
+ }
259
+ }
260
+ break
261
+ case 'modify':
262
+ const oldNumber = mode === 'lid' ? WABinary_1.getBinaryNodeChildren(child, 'participant').map(p => p.attrs.phone_number) : WABinary_1.getBinaryNodeChildren(child, 'participant').map(p => p.attrs.jid)
263
+ msg.messageStubParameters = oldNumber || []
264
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER
265
+ break
266
+ case 'promote':
267
+ case 'demote':
268
+ case 'remove':
269
+ case 'add':
270
+ case 'leave':
271
+ let stubType = `GROUP_PARTICIPANT_${child.tag.toUpperCase()}`
272
+ if (child.attrs?.reason === 'linked_group_join') {
273
+ stubType = GROUP_PARTICIPANT_LINKED_GROUP_JOIN
274
+ }
275
+ msg.messageStubType = Types_1.WAMessageStubType[stubType]
276
+ const participants = mode === 'lid' ? WABinary_1.getBinaryNodeChildren(child, 'participant').map(p => p.attrs.phone_number) : WABinary_1.getBinaryNodeChildren(child, 'participant').map(p => p.attrs.jid)
277
+ if (participants.length === 1 &&
278
+ // if recv. "remove" message and sender removed themselves
279
+ // mark as left
280
+ WABinary_1.areJidsSameUser(participants[0], participant) &&
281
+ child.tag === 'remove') {
282
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_PARTICIPANT_LEAVE
283
+ }
284
+ msg.messageStubParameters = participants
285
+ break
286
+ case 'subject':
287
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_SUBJECT
288
+ msg.messageStubParameters = [participantJid, child.attrs.subject]
289
+ break
290
+ case 'description':
291
+ const description = WABinary_1.getBinaryNodeChild(child, 'body')?.content?.toString()
292
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_DESCRIPTION
293
+ msg.messageStubParameters = description ? [description] : undefined
294
+ break
295
+ case 'announcement':
296
+ case 'not_announcement':
297
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_ANNOUNCE
298
+ msg.messageStubParameters = [(child.tag === 'announcement') ? 'on' : 'off']
299
+ break
300
+ case 'locked':
301
+ case 'unlocked':
302
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_RESTRICT
303
+ msg.messageStubParameters = [(child.tag === 'locked') ? 'on' : 'off']
304
+ break
305
+ case 'invite':
306
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_INVITE_LINK
307
+ msg.messageStubParameters = [child.attrs.code]
308
+ break
309
+ case 'member_add_mode':
310
+ const addMode = child.content
311
+ if (addMode) {
312
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBER_ADD_MODE
313
+ msg.messageStubParameters = [addMode.toString()]
314
+ }
315
+ break
316
+ case 'membership_approval_mode':
317
+ const approvalMode = WABinary_1.getBinaryNodeChild(child, 'group_join')
318
+ if (approvalMode) {
319
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE
320
+ msg.messageStubParameters = [approvalMode.attrs.state]
321
+ }
322
+ break
323
+ case 'created_membership_requests':
324
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD
325
+ msg.messageStubParameters = [participantJid, 'created', child.attrs.request_method]
326
+ break
327
+ case 'revoked_membership_requests':
328
+ const isDenied = WABinary_1.areJidsSameUser(participantJid, participant)
329
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD
330
+ msg.messageStubParameters = [participantJid, isDenied ? 'revoked' : 'rejected']
331
+ break
332
+ case 'link':
333
+ case 'unlink':
334
+ const type = child.attrs?.unlink_type || child.attrs?.link_type
335
+ const stubMap = {
336
+ parent_group: Types_1.WAMessageStubType[`COMMUNITY_${child.tag.toUpperCase()}_PARENT_GROUP`],
337
+ sibling_group: Types_1.WAMessageStubType[`COMMUNITY_${child.tag.toUpperCase()}_SIBLING_GROUP`],
338
+ sub_group: Types_1.WAMessageStubType[`COMMUNITY_${child.tag.toUpperCase()}_SUB_GROUP`]
339
+ }
340
+ const groups = WABinary_1.getBinaryNodeChildren(child, 'group')
341
+ .map(g => g.attrs?.jid || g.attrs?.subject || '')
342
+ .filter(x => x)
343
+ msg.messageStubType = stubMap?.[type] || Types_1.WAMessageStubType[`COMMUNITY_${child.tag.toUpperCase()}_PARENT_GROUP`]
344
+ msg.messageStubParameters = [participantJid, child.tag, groups]
345
+ break
346
+ case 'linked_group_promote':
347
+ case 'linked_group_demote':
348
+ const stubtype = `COMMUNITY_PARTICIPANT_${child.tag.split('_')[2].toUpperCase()}`
349
+ const participantS = mode === 'lid' ? WABinary_1.getBinaryNodeChildren(child, 'participant').map(p => p.attrs.phone_number) : WABinary_1.getBinaryNodeChildren(child, 'participant').map(p => p.attrs.jid)
350
+ msg.messageStubType = Types_1.WAMessageStubType[stubtype]
351
+ msg.messageStubParameters = participantS
352
+ break
353
+ case 'created_sub_group_suggestion':
354
+ msg.messageStubType = Types_1.WAMessageStubType.SUGGESTED_SUBGROUP_ANNOUNCE
355
+ msg.messageStubParameters = [participantJid, 'add']
356
+ break
357
+ case 'revoked_sub_group_suggestions':
358
+ const res = WABinary_1.getBinaryNodeChildren(child, 'sub_group_suggestions')
359
+ const reason = res.attrs?.reason
360
+ if (reason === 'approved') msg.messageStubType = Types_1.WAMessageStubType.GROUP_CREATE
361
+ else msg.messageStubType = Types_1.WAMessageStubType.GENERIC_NOTIFICATION
362
+ msg.messageStubParameters = [participantJid, reason]
363
+ break
364
+ default:
365
+ logger.warn(child.tag, 'Unhandled group node')
366
+ break
367
+ }
368
+ }
369
+ const handleNewsletterNotification = (id, node) => {
370
+ const messages = WABinary_1.getBinaryNodeChild(node, 'messages')
371
+ const message = WABinary_1.getBinaryNodeChild(node, 'message')
372
+ const serverId = node.attrs.server_id
373
+ const reactionsList = WABinary_1.getBinaryNodeChild(node, 'reactions')
374
+ const viewsList = WABinary_1.getBinaryNodeChild(node, 'views_count')
375
+ if (reactionsList) {
376
+ const reactions = WABinary_1.getBinaryNodeChild(reactionsList, 'reaction')
377
+ if (reactions.length === 0) {
378
+ ev.emit('newsletter.reaction', {
379
+ id,
380
+ newsletter_server_id: serverId,
381
+ reaction: {
382
+ removed: true
383
+ }
384
+ })
385
+ }
386
+ reactions.forEach(item => {
387
+ ev.emit('newsletter.reaction', {
388
+ id,
389
+ newsletter_server_id: serverId,
390
+ reaction: {
391
+ code: item.attrs?.code,
392
+ count: +item.attrs.count
393
+ }
394
+ })
395
+ })
396
+ }
397
+ if (viewsList.length) {
398
+ viewsList.forEach(item => {
399
+ ev.emit('newsletter.view', {
400
+ id,
401
+ newsletter_server_id: serverId,
402
+ count: +item.attrs.count
403
+ })
404
+ })
405
+ }
406
+ }
407
+ const handleMexNewsletterNotification = (id, node) => {
408
+ const operation = node?.attrs?.op_name
409
+ const content = JSON.parse(node?.attrs?.content)
410
+ let contentPath
411
+ if (operation === Types_1.MexOperations.UPDATE) {
412
+ contentPath = content.data[Types_1.XWAPaths.METADATA_UPDATE]
413
+ ev.emit('newsletter-settings.update', {
414
+ id,
415
+ update: contentPath.thread_metadata.settings
416
+ })
417
+ } else {
418
+ let action
419
+ if (operation === Types_1.MexOperations.PROMOTE) {
420
+ action = 'promote'
421
+ contentPath.data[Types_1.XWAPaths.PROMOTE]
422
+ } else {
423
+ action = 'demote'
424
+ contentPath.data[Types_1.XWAPaths.DEMOTE]
425
+ }
426
+ ev.emit('newsletter-participants.update', {
427
+ id,
428
+ author: contentPath.actor.pn,
429
+ user: contentPath.user.pn,
430
+ new_role: contentPath.user_new_role,
431
+ action
432
+ })
433
+ }
434
+ }
435
+ const processNotification = async (node) => {
436
+ const result = {}
437
+ const [child] = WABinary_1.getAllBinaryNodeChildren(node)
438
+ const nodeType = node.attrs.type
439
+ const from = WABinary_1.jidNormalizedUser(node.attrs.from)
440
+ switch (nodeType) {
441
+ case 'privacy_token':
442
+ const tokenList = WABinary_1.getBinaryNodeChildren(child, 'token')
443
+ for (const { attrs, content } of tokenList) {
444
+ const jid = attrs.jid
445
+ ev.emit('chats.update', [
446
+ {
447
+ id: jid,
448
+ tcToken: content
449
+ }
450
+ ])
451
+ logger.debug({ jid }, 'got privacy token update')
452
+ }
453
+ break
454
+ case 'w:gp2':
455
+ const mode = node.attrs.addressing_mode
456
+ handleGroupNotification(mode === 'lid' ? node.attrs.participant_pn : node.attrs.participant, child, result, mode)
457
+ break
458
+ case 'newsletter':
459
+ handleNewsletterNotification(node.attrs.from, child)
460
+ break
461
+ case 'mex':
462
+ handleMexNewsletterNotification(node.attrs.from, child)
463
+ break
464
+ case 'mediaretry':
465
+ const event = Utils_1.decodeMediaRetryNode(node)
466
+ ev.emit('messages.media-update', [event])
467
+ break
468
+ case 'encrypt':
469
+ await handleEncryptNotification(node)
470
+ break
471
+ case 'devices':
472
+ const devices = WABinary_1.getBinaryNodeChildren(child, 'device')
473
+ if (WABinary_1.areJidsSameUser(child.attrs.jid, authState.creds.me.id)) {
474
+ const deviceJids = devices.map(d => d.attrs.jid)
475
+ logger.info({ deviceJids }, 'got my own devices')
476
+ }
477
+ break
478
+ case 'server_sync':
479
+ const update = WABinary_1.getBinaryNodeChild(node, 'collection')
480
+ if (update) {
481
+ const name = update.attrs.name
482
+ await resyncAppState([name], false)
483
+ }
484
+ break
485
+ case 'picture':
486
+ const setPicture = WABinary_1.getBinaryNodeChild(node, 'set')
487
+ const delPicture = WABinary_1.getBinaryNodeChild(node, 'delete')
488
+ ev.emit('contacts.update', [{
489
+ id: WABinary_1.jidNormalizedUser(node?.attrs?.from) || (setPicture || delPicture)?.attrs?.hash || '',
490
+ imgUrl: setPicture ? 'changed' : 'removed'
491
+ }])
492
+ if (WABinary_1.isJidGroup(from)) {
493
+ const node = setPicture || delPicture
494
+ result.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_ICON
495
+ if (setPicture) {
496
+ result.messageStubParameters = [setPicture.attrs.id]
497
+ }
498
+ result.participant = node?.attrs?.author
499
+ result.key = {
500
+ ...result.key || {},
501
+ participant: setPicture?.attrs?.author
502
+ }
503
+ }
504
+ break
505
+ case 'account_sync':
506
+ if (child.tag === 'disappearing_mode') {
507
+ const newDuration = +child.attrs.duration
508
+ const timestamp = +child.attrs.t
509
+ logger.info({ newDuration }, 'updated account disappearing mode')
510
+ ev.emit('creds.update', {
511
+ accountSettings: {
512
+ ...authState.creds.accountSettings,
513
+ defaultDisappearingMode: {
514
+ ephemeralExpiration: newDuration,
515
+ ephemeralSettingTimestamp: timestamp,
516
+ },
517
+ }
518
+ })
519
+ }
520
+ else if (child.tag === 'blocklist') {
521
+ const blocklists = WABinary_1.getBinaryNodeChildren(child, 'item')
522
+ for (const { attrs } of blocklists) {
523
+ const blocklist = [attrs.jid]
524
+ const type = (attrs.action === 'block') ? 'add' : 'remove'
525
+ ev.emit('blocklist.update', { blocklist, type })
526
+ }
527
+ }
528
+ break
529
+ case 'link_code_companion_reg':
530
+ const linkCodeCompanionReg = WABinary_1.getBinaryNodeChild(node, 'link_code_companion_reg')
531
+ const ref = toRequiredBuffer(WABinary_1.getBinaryNodeChildBuffer(linkCodeCompanionReg, 'link_code_pairing_ref'))
532
+ const primaryIdentityPublicKey = toRequiredBuffer(WABinary_1.getBinaryNodeChildBuffer(linkCodeCompanionReg, 'primary_identity_pub'))
533
+ const primaryEphemeralPublicKeyWrapped = toRequiredBuffer(WABinary_1.getBinaryNodeChildBuffer(linkCodeCompanionReg, 'link_code_pairing_wrapped_primary_ephemeral_pub'))
534
+ const codePairingPublicKey = await decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped)
535
+ const companionSharedKey = Utils_1.Curve.sharedKey(authState.creds.pairingEphemeralKeyPair.private, codePairingPublicKey)
536
+ const random = crypto_1.randomBytes(32)
537
+ const linkCodeSalt = crypto_1.randomBytes(32)
538
+ const linkCodePairingExpanded = await Utils_1.hkdf(companionSharedKey, 32, {
539
+ salt: linkCodeSalt,
540
+ info: 'link_code_pairing_key_bundle_encryption_key'
541
+ })
542
+ const encryptPayload = Buffer.concat([Buffer.from(authState.creds.signedIdentityKey.public), primaryIdentityPublicKey, random])
543
+ const encryptIv = crypto_1.randomBytes(12)
544
+ const encrypted = Utils_1.aesEncryptGCM(encryptPayload, linkCodePairingExpanded, encryptIv, Buffer.alloc(0))
545
+ const encryptedPayload = Buffer.concat([linkCodeSalt, encryptIv, encrypted])
546
+ const identitySharedKey = Utils_1.Curve.sharedKey(authState.creds.signedIdentityKey.private, primaryIdentityPublicKey)
547
+ const identityPayload = Buffer.concat([companionSharedKey, identitySharedKey, random])
548
+ authState.creds.advSecretKey = (await Utils_1.hkdf(identityPayload, 32, { info: 'adv_secret' })).toString('base64')
549
+ await query({
550
+ tag: 'iq',
551
+ attrs: {
552
+ to: WABinary_1.S_WHATSAPP_NET,
553
+ type: 'set',
554
+ id: sock.generateMessageTag(),
555
+ xmlns: 'md'
556
+ },
557
+ content: [
558
+ {
559
+ tag: 'link_code_companion_reg',
560
+ attrs: {
561
+ jid: authState.creds.me.id,
562
+ stage: 'companion_finish',
563
+ },
564
+ content: [
565
+ {
566
+ tag: 'link_code_pairing_wrapped_key_bundle',
567
+ attrs: {},
568
+ content: encryptedPayload
569
+ },
570
+ {
571
+ tag: 'companion_identity_public',
572
+ attrs: {},
573
+ content: authState.creds.signedIdentityKey.public
574
+ },
575
+ {
576
+ tag: 'link_code_pairing_ref',
577
+ attrs: {},
578
+ content: ref
579
+ }
580
+ ]
581
+ }
582
+ ]
583
+ })
584
+ authState.creds.registered = true
585
+ ev.emit('creds.update', authState.creds)
586
+ }
587
+ if (Object.keys(result).length) {
588
+ return result
589
+ }
590
+ }
591
+ async function decipherLinkPublicKey(data) {
592
+ const buffer = toRequiredBuffer(data)
593
+ const salt = buffer.slice(0, 32)
594
+ const secretKey = await Utils_1.derivePairingCodeKey(authState.creds.pairingCode, salt)
595
+ const iv = buffer.slice(32, 48)
596
+ const payload = buffer.slice(48, 80)
597
+ return Utils_1.aesDecryptCTR(payload, secretKey, iv)
598
+ }
599
+ function toRequiredBuffer(data) {
600
+ if (data === undefined) {
601
+ throw new boom_1.Boom('Invalid buffer', { statusCode: 400 })
602
+ }
603
+ return data instanceof Buffer ? data : Buffer.from(data)
604
+ }
605
+ const willSendMessageAgain = (id, participant) => {
606
+ const key = `${id}:${participant}`
607
+ const retryCount = msgRetryCache.get(key) || 0
608
+ return retryCount < maxMsgRetryCount
609
+ }
610
+ const updateSendMessageAgainCount = (id, participant) => {
611
+ const key = `${id}:${participant}`
612
+ const newValue = (msgRetryCache.get(key) || 0) + 1
613
+ msgRetryCache.set(key, newValue)
614
+ }
615
+ const sendMessagesAgain = async (key, ids, retryNode) => {
616
+ const msgs = await Promise.all(ids.map(id => getMessage({ ...key, id })))
617
+ const remoteJid = key.remoteJid
618
+ const participant = key.participant || remoteJid
619
+ // if it's the primary jid sending the request
620
+ // just re-send the message to everyone
621
+ // prevents the first message decryption failure
622
+ const sendToAll = !WABinary_1.jidDecode(participant)?.device
623
+ await assertSessions([participant], true)
624
+ if (WABinary_1.isJidGroup(remoteJid)) {
625
+ await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } })
626
+ }
627
+ logger.debug({ participant, sendToAll }, 'forced new session for retry recp')
628
+ for (const [i, msg] of msgs.entries()) {
629
+ if (msg) {
630
+ updateSendMessageAgainCount(ids[i], participant)
631
+ const msgRelayOpts = { messageId: ids[i] }
632
+ if (sendToAll) {
633
+ msgRelayOpts.useUserDevicesCache = false
634
+ }
635
+ else {
636
+ msgRelayOpts.participant = {
637
+ jid: participant,
638
+ count: +retryNode.attrs.count
639
+ }
640
+ }
641
+ await relayMessage(key.remoteJid, msg, msgRelayOpts)
642
+ }
643
+ else {
644
+ logger.debug({ jid: key.remoteJid, id: ids[i] }, 'recv retry request, but message not available')
645
+ }
646
+ }
647
+ }
648
+ const handleReceipt = async (node) => {
649
+ const { attrs, content } = node
650
+ const isLid = attrs.from.includes('lid')
651
+ const isNodeFromMe = WABinary_1.areJidsSameUser(attrs.participant || attrs.from, isLid ? authState.creds.me?.lid : authState.creds.me?.id)
652
+ const remoteJid = !isNodeFromMe || WABinary_1.isJidGroup(attrs.from) ? attrs.from : attrs.recipient
653
+ const fromMe = !attrs.recipient || ((attrs.type === 'retry' || attrs.type === 'sender') && isNodeFromMe)
654
+ const key = {
655
+ remoteJid,
656
+ id: '',
657
+ fromMe,
658
+ participant: attrs.participant
659
+ }
660
+ if (shouldIgnoreJid(remoteJid) && remoteJid !== '@s.whatsapp.net') {
661
+ logger.debug({ remoteJid }, 'ignoring receipt from jid')
662
+ await sendMessageAck(node)
663
+ return
664
+ }
665
+ const ids = [attrs.id]
666
+ if (Array.isArray(content)) {
667
+ const items = WABinary_1.getBinaryNodeChildren(content[0], 'item')
668
+ ids.push(...items.map(i => i.attrs.id))
669
+ }
670
+ try {
671
+ await Promise.all([
672
+ processingMutex.mutex(async () => {
673
+ const status = Utils_1.getStatusFromReceiptType(attrs.type)
674
+ if (typeof status !== 'undefined' && (
675
+ // basically, we only want to know when a message from us has been delivered to/read by the other person
676
+ // or another device of ours has read some messages
677
+ status >= WAProto_1.proto.WebMessageInfo.Status.SERVER_ACK ||
678
+ !isNodeFromMe)) {
679
+ if (WABinary_1.isJidGroup(remoteJid) || WABinary_1.isJidStatusBroadcast(remoteJid)) {
680
+ if (attrs.participant) {
681
+ const updateKey = status === WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp'
682
+ ev.emit('message-receipt.update', ids.map(id => ({
683
+ key: { ...key, id },
684
+ receipt: {
685
+ userJid: WABinary_1.jidNormalizedUser(attrs.participant),
686
+ [updateKey]: +attrs.t
687
+ }
688
+ })))
689
+ }
690
+ }
691
+ else {
692
+ ev.emit('messages.update', ids.map(id => ({
693
+ key: { ...key, id },
694
+ update: { status }
695
+ })))
696
+ }
697
+ }
698
+ if (attrs.type === 'retry') {
699
+ // correctly set who is asking for the retry
700
+ key.participant = key.participant || attrs.from
701
+ const retryNode = WABinary_1.getBinaryNodeChild(node, 'retry')
702
+ if (willSendMessageAgain(ids[0], key.participant)) {
703
+ if (key.fromMe) {
704
+ try {
705
+ logger.debug({ attrs, key }, 'recv retry request')
706
+ await sendMessagesAgain(key, ids, retryNode)
707
+ }
708
+ catch (error) {
709
+ logger.error({ key, ids, trace: error.stack }, 'error in sending message again')
710
+ }
711
+ }
712
+ else {
713
+ logger.info({ attrs, key }, 'recv retry for not fromMe message')
714
+ }
715
+ }
716
+ else {
717
+ logger.info({ attrs, key }, 'will not send message again, as sent too many times')
718
+ }
719
+ }
720
+ })
721
+ ])
722
+ }
723
+ finally {
724
+ await sendMessageAck(node)
725
+ }
726
+ }
727
+ const handleNotification = async (node) => {
728
+ const remoteJid = node.attrs.from
729
+ if (shouldIgnoreJid(remoteJid) && remoteJid !== '@s.whatsapp.net') {
730
+ logger.debug({ remoteJid, id: node.attrs.id }, 'ignored notification')
731
+ await sendMessageAck(node)
732
+ return
733
+ }
734
+ try {
735
+ await Promise.all([
736
+ processingMutex.mutex(async () => {
737
+ const msg = await processNotification(node)
738
+ if (msg) {
739
+ const fromMe = WABinary_1.areJidsSameUser(node.attrs.participant || remoteJid, authState.creds.me.id)
740
+ msg.key = {
741
+ remoteJid,
742
+ fromMe,
743
+ participant: node.attrs.participant,
744
+ id: node.attrs.id,
745
+ ...(msg.key || {})
746
+ }
747
+ msg.participant = msg.participant ? msg.participant : node.attrs.participant
748
+ msg.messageTimestamp = +node.attrs.t
749
+ const fullMsg = WAProto_1.proto.WebMessageInfo.fromObject(msg)
750
+ await upsertMessage(fullMsg, 'append')
751
+ }
752
+ })
753
+ ])
754
+ }
755
+ finally {
756
+ await sendMessageAck(node)
757
+ }
758
+ }
759
+ const handleMessage = async (node) => {
760
+ if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !== '@s.whatsapp.net') {
761
+ logger.debug({ key: node.attrs.key }, 'ignored message')
762
+ await sendMessageAck(node)
763
+ return
764
+ }
765
+ let response
766
+ if (WABinary_1.getBinaryNodeChild(node, 'unavailable') && !WABinary_1.getBinaryNodeChild(node, 'enc')) {
767
+ await sendMessageAck(node)
768
+ const { key } = Utils_1.decodeMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '').fullMessage
769
+ response = await requestPlaceholderResend(key)
770
+ if (response === 'RESOLVED') {
771
+ return
772
+ }
773
+ logger.debug('received unavailable message, acked and requested resend from phone')
774
+ }
775
+ else {
776
+ if (placeholderResendCache.get(node.attrs.id)) {
777
+ placeholderResendCache.del(node.attrs.id)
778
+ }
779
+ }
780
+ const { fullMessage: msg, category, author, decrypt } = Utils_1.decryptMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger)
781
+ if (response && msg?.messageStubParameters?.[0] === Utils_1.NO_MESSAGE_FOUND_ERROR_TEXT) {
782
+ msg.messageStubParameters = [Utils_1.NO_MESSAGE_FOUND_ERROR_TEXT, response]
783
+ }
784
+ if (msg.message?.protocolMessage?.type === WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER && node.attrs.sender_pn) {
785
+ ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn })
786
+ }
787
+ try {
788
+ await Promise.all([
789
+ processingMutex.mutex(async () => {
790
+ await decrypt()
791
+ // message failed to decrypt
792
+ if (msg.messageStubType === WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT) {
793
+ if (msg?.messageStubParameters?.[0] === Utils_1.MISSING_KEYS_ERROR_TEXT) {
794
+ return sendMessageAck(node, Utils_1.NACK_REASONS.ParsingError)
795
+ }
796
+ retryMutex.mutex(async () => {
797
+ if (ws.isOpen) {
798
+ if (WABinary_1.getBinaryNodeChild(node, 'unavailable')) {
799
+ return
800
+ }
801
+ const encNode = WABinary_1.getBinaryNodeChild(node, 'enc')
802
+ await sendRetryRequest(node, !encNode)
803
+ if (retryRequestDelayMs) {
804
+ await Utils_1.delay(retryRequestDelayMs)
805
+ }
806
+ }
807
+ else {
808
+ logger.debug({ node }, 'connection closed, ignoring retry req')
809
+ }
810
+ })
811
+ }
812
+ else {
813
+ // no type in the receipt => message delivered
814
+ let type = undefined
815
+ let participant = msg.key.participant
816
+ if (category === 'peer') { // special peer message
817
+ type = 'peer_msg'
818
+ }
819
+ else if (msg.key.fromMe) { // message was sent by us from a different device
820
+ type = 'sender'
821
+ // need to specially handle this case
822
+ if (WABinary_1.isJidUser(msg.key.remoteJid)) {
823
+ participant = author
824
+ }
825
+ }
826
+ else if (!sendActiveReceipts) {
827
+ type = 'inactive'
828
+ }
829
+ await sendReceipt(msg.key.remoteJid, participant, [msg.key.id], type)
830
+ // send ack for history message
831
+ const isAnyHistoryMsg = Utils_1.getHistoryMsg(msg.message)
832
+ if (isAnyHistoryMsg) {
833
+ const jid = WABinary_1.jidNormalizedUser(msg.key.remoteJid)
834
+ await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync')
835
+ }
836
+ }
837
+ if (node?.attrs?.addressing_mode === 'lid' && node?.attrs?.participant_pn) {
838
+ msg.key.participant = WABinary_1.jidNormalizedUser(node.attrs.participant_pn)
839
+ }
840
+ Utils_1.cleanMessage(msg, authState.creds.me.id)
841
+ await sendMessageAck(node)
842
+ await upsertMessage(msg, node.attrs.offline ? 'append' : 'notify')
843
+ })
844
+ ])
845
+ }
846
+ catch (error) {
847
+ logger.error({ error, node }, 'error in handling message')
848
+ }
849
+ }
850
+ const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
851
+ if (!authState.creds.me?.id) {
852
+ throw new boom_1.Boom('Not authenticated')
853
+ }
854
+ const pdoMessage = {
855
+ historySyncOnDemandRequest: {
856
+ chatJid: oldestMsgKey.remoteJid,
857
+ oldestMsgFromMe: oldestMsgKey.fromMe,
858
+ oldestMsgId: oldestMsgKey.id,
859
+ oldestMsgTimestampMs: oldestMsgTimestamp,
860
+ onDemandMsgCount: count
861
+ },
862
+ peerDataOperationRequestType: WAProto_1.proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
863
+ }
864
+ return sendPeerDataOperationMessage(pdoMessage)
865
+ }
866
+ const requestPlaceholderResend = async (messageKey) => {
867
+ if (!authState.creds.me?.id) {
868
+ throw new boom_1.Boom('Not authenticated')
869
+ }
870
+ if (placeholderResendCache.get(messageKey?.id)) {
871
+ logger.debug({ messageKey }, 'already requested resend')
872
+ return
873
+ }
874
+ else {
875
+ placeholderResendCache.set(messageKey?.id, true)
876
+ }
877
+ await Utils_1.delay(5000)
878
+ if (!placeholderResendCache.get(messageKey?.id)) {
879
+ logger.debug({ messageKey }, 'message received while resend requested')
880
+ return 'RESOLVED'
881
+ }
882
+ const pdoMessage = {
883
+ placeholderMessageResendRequest: [{
884
+ messageKey
885
+ }],
886
+ peerDataOperationRequestType: WAProto_1.proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
887
+ }
888
+ setTimeout(() => {
889
+ if (placeholderResendCache.get(messageKey?.id)) {
890
+ logger.debug({ messageKey }, 'PDO message without response after 15 seconds. Phone possibly offline')
891
+ placeholderResendCache.del(messageKey?.id)
892
+ }
893
+ }, 15000)
894
+ return sendPeerDataOperationMessage(pdoMessage)
895
+ }
896
+ const handleCall = async (node) => {
897
+ const { attrs } = node
898
+ const [infoChild] = WABinary_1.getAllBinaryNodeChildren(node)
899
+ const callId = infoChild.attrs['call-id']
900
+ const from = infoChild.attrs.from || infoChild.attrs['call-creator']
901
+ const status = Utils_1.getCallStatusFromNode(infoChild)
902
+ const call = {
903
+ chatId: attrs.from,
904
+ from,
905
+ id: callId,
906
+ date: new Date(+attrs.t * 1000),
907
+ offline: !!attrs.offline,
908
+ status,
909
+ }
910
+ if (status === 'offer') {
911
+ call.isVideo = !!WABinary_1.getBinaryNodeChild(infoChild, 'video')
912
+ call.isGroup = infoChild.attrs.type === 'group' || !!infoChild.attrs['group-jid']
913
+ call.groupJid = infoChild.attrs['group-jid']
914
+ callOfferCache.set(call.id, call)
915
+ }
916
+ const existingCall = callOfferCache.get(call.id)
917
+ // use existing call info to populate this event
918
+ if (existingCall) {
919
+ call.isVideo = existingCall.isVideo
920
+ call.isGroup = existingCall.isGroup
921
+ }
922
+ // delete data once call has ended
923
+ if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
924
+ callOfferCache.del(call.id)
925
+ }
926
+ ev.emit('call', [call])
927
+ await sendMessageAck(node)
928
+ }
929
+ const handleBadAck = async ({ attrs }) => {
930
+ const key = { remoteJid: attrs.from, fromMe: true, id: attrs.id, newsletter_server_id: attrs?.server_id }
931
+ // WARNING: REFRAIN FROM ENABLING THIS FOR NOW. IT WILL CAUSE A LOOP
932
+ // // current hypothesis is that if pash is sent in the ack
933
+ // // it means -- the message hasn't reached all devices yet
934
+ // // we'll retry sending the message here
935
+ // if(attrs.phash) {
936
+ // logger.info({ attrs }, 'received phash in ack, resending message...')
937
+ // const msg = await getMessage(key)
938
+ // if(msg) {
939
+ // await relayMessage(key.remoteJid!, msg, { messageId: key.id!, useUserDevicesCache: false })
940
+ // } else {
941
+ // logger.warn({ attrs }, 'could not send message again, as it was not found')
942
+ // }
943
+ // }
944
+ // error in acknowledgement,
945
+ // device could not display the message
946
+ if (attrs.error) {
947
+ logger.warn({ attrs }, 'received error in ack')
948
+ ev.emit('messages.update', [
949
+ {
950
+ key,
951
+ update: {
952
+ status: Types_1.WAMessageStatus.ERROR,
953
+ messageStubParameters: [
954
+ attrs.error
955
+ ]
956
+ }
957
+ }
958
+ ])
959
+ }
960
+ }
961
+ /// processes a node with the given function
962
+ /// and adds the task to the existing buffer if we're buffering events
963
+ const processNodeWithBuffer = async (node, identifier, exec) => {
964
+ ev.buffer()
965
+ await execTask()
966
+ ev.flush()
967
+ function execTask() {
968
+ return exec(node, false)
969
+ .catch(err => onUnexpectedError(err, identifier))
970
+ }
971
+ }
972
+ const makeOfflineNodeProcessor = () => {
973
+ const nodeProcessorMap = new Map([
974
+ ['message', handleMessage],
975
+ ['call', handleCall],
976
+ ['receipt', handleReceipt],
977
+ ['notification', handleNotification]
978
+ ])
979
+ const nodes = []
980
+ let isProcessing = false
981
+ const enqueue = (type, node) => {
982
+ nodes.push({ type, node })
983
+ if (isProcessing) {
984
+ return
985
+ }
986
+ isProcessing = true
987
+ const promise = async () => {
988
+ while (nodes.length && ws.isOpen) {
989
+ const { type, node } = nodes.shift()
990
+ const nodeProcessor = nodeProcessorMap.get(type)
991
+ if (!nodeProcessor) {
992
+ onUnexpectedError(new Error(`unknown offline node type: ${type}`), 'processing offline node')
993
+ continue
994
+ }
995
+ await nodeProcessor(node)
996
+ }
997
+ isProcessing = false
998
+ }
999
+ promise().catch(error => onUnexpectedError(error, 'processing offline nodes'))
1000
+ }
1001
+ return { enqueue }
1002
+ }
1003
+ const offlineNodeProcessor = makeOfflineNodeProcessor()
1004
+ const processNode = (type, node, identifier, exec) => {
1005
+ const isOffline = !!node.attrs.offline
1006
+ if (isOffline) {
1007
+ offlineNodeProcessor.enqueue(type, node)
1008
+ }
1009
+ else {
1010
+ processNodeWithBuffer(node, identifier, exec)
1011
+ }
1012
+ }
1013
+ // recv a message
1014
+ ws.on('CB:message', (node) => {
1015
+ processNode('message', node, 'processing message', handleMessage)
1016
+ })
1017
+ ws.on('CB:call', async (node) => {
1018
+ processNode('call', node, 'handling call', handleCall)
1019
+ })
1020
+ ws.on('CB:receipt', node => {
1021
+ processNode('receipt', node, 'handling receipt', handleReceipt)
1022
+ })
1023
+ ws.on('CB:notification', async (node) => {
1024
+ processNode('notification', node, 'handling notification', handleNotification)
1025
+ })
1026
+ ws.on('CB:ack,class:message', (node) => {
1027
+ handleBadAck(node)
1028
+ .catch(error => onUnexpectedError(error, 'handling bad ack'))
1029
+ })
1030
+ ev.on('call', ([call]) => {
1031
+ // missed call + group call notification message generation
1032
+ if (call.status === 'timeout' || (call.status === 'offer' && call.isGroup)) {
1033
+ const msg = {
1034
+ key: {
1035
+ remoteJid: call.chatId,
1036
+ id: call.id,
1037
+ fromMe: false
1038
+ },
1039
+ messageTimestamp: Utils_1.unixTimestampSeconds(call.date),
1040
+ }
1041
+ if (call.status === 'timeout') {
1042
+ if (call.isGroup) {
1043
+ msg.messageStubType = call.isVideo ? Types_1.WAMessageStubType.CALL_MISSED_GROUP_VIDEO : Types_1.WAMessageStubType.CALL_MISSED_GROUP_VOICE
1044
+ }
1045
+ else {
1046
+ msg.messageStubType = call.isVideo ? Types_1.WAMessageStubType.CALL_MISSED_VIDEO : Types_1.WAMessageStubType.CALL_MISSED_VOICE
1047
+ }
1048
+ }
1049
+ else {
1050
+ msg.message = { call: { callKey: Buffer.from(call.id) } }
1051
+ }
1052
+ const protoMsg = WAProto_1.proto.WebMessageInfo.fromObject(msg)
1053
+ upsertMessage(protoMsg, call.offline ? 'append' : 'notify')
1054
+ }
1055
+ })
1056
+ ev.on('connection.update', ({ isOnline }) => {
1057
+ if (typeof isOnline !== 'undefined') {
1058
+ sendActiveReceipts = isOnline
1059
+ logger.trace(`sendActiveReceipts set to "${sendActiveReceipts}"`)
1060
+ }
1061
+ })
1062
+ return {
1063
+ ...sock,
1064
+ sendMessageAck,
1065
+ sendRetryRequest,
1066
+ offerCall,
1067
+ rejectCall,
1068
+ fetchMessageHistory,
1069
+ requestPlaceholderResend,
1070
+ }
1071
+ }
1072
+ module.exports = {
1073
+ makeMessagesRecvSocket
1074
+ }