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