gifted-baileys 1.5.6 → 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 (252) hide show
  1. package/README.md +9 -0
  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/README.md +0 -1
  136. package/src/Signal/libsignal.js +0 -180
  137. package/src/Signal/libsignal.ts +0 -141
  138. package/src/Socket/Client/abstract-socket-client.ts +0 -19
  139. package/src/Socket/Client/index.ts +0 -3
  140. package/src/Socket/Client/mobile-socket-client.js +0 -78
  141. package/src/Socket/Client/mobile-socket-client.ts +0 -66
  142. package/src/Socket/Client/web-socket-client.js +0 -75
  143. package/src/Socket/Client/web-socket-client.ts +0 -57
  144. package/src/Socket/business.ts +0 -281
  145. package/src/Socket/chats.ts +0 -1030
  146. package/src/Socket/groups.ts +0 -356
  147. package/src/Socket/index.ts +0 -13
  148. package/src/Socket/messages-recv.ts +0 -985
  149. package/src/Socket/messages-send.ts +0 -871
  150. package/src/Socket/newsletter.ts +0 -282
  151. package/src/Socket/registration.ts +0 -250
  152. package/src/Socket/socket.ts +0 -777
  153. package/src/Store/index.ts +0 -3
  154. package/src/Store/make-cache-manager-store.ts +0 -100
  155. package/src/Store/make-in-memory-store.ts +0 -475
  156. package/src/Store/make-ordered-dictionary.ts +0 -86
  157. package/src/Store/object-repository.ts +0 -32
  158. package/src/Tests/test.app-state-sync.js +0 -204
  159. package/src/Tests/test.app-state-sync.ts +0 -207
  160. package/src/Tests/test.event-buffer.js +0 -270
  161. package/src/Tests/test.event-buffer.ts +0 -319
  162. package/src/Tests/test.key-store.js +0 -76
  163. package/src/Tests/test.key-store.ts +0 -92
  164. package/src/Tests/test.libsignal.js +0 -141
  165. package/src/Tests/test.libsignal.ts +0 -186
  166. package/src/Tests/test.media-download.js +0 -93
  167. package/src/Tests/test.media-download.ts +0 -76
  168. package/src/Tests/test.messages.js +0 -33
  169. package/src/Tests/test.messages.ts +0 -37
  170. package/src/Tests/utils.js +0 -34
  171. package/src/Tests/utils.ts +0 -36
  172. package/src/Types/Auth.ts +0 -113
  173. package/src/Types/Call.ts +0 -15
  174. package/src/Types/Chat.ts +0 -106
  175. package/src/Types/Events.ts +0 -93
  176. package/src/Types/GroupMetadata.ts +0 -53
  177. package/src/Types/Label.ts +0 -36
  178. package/src/Types/Message.ts +0 -288
  179. package/src/Types/Newsletter.ts +0 -98
  180. package/src/Types/Product.ts +0 -85
  181. package/src/Types/Signal.ts +0 -68
  182. package/src/Types/State.ts +0 -29
  183. package/src/Types/index.ts +0 -59
  184. package/src/Utils/auth-utils.ts +0 -222
  185. package/src/Utils/baileys-event-stream.js +0 -92
  186. package/src/Utils/baileys-event-stream.ts +0 -66
  187. package/src/Utils/business.ts +0 -275
  188. package/src/Utils/chat-utils.ts +0 -860
  189. package/src/Utils/crypto.ts +0 -131
  190. package/src/Utils/decode-wa-message.js +0 -211
  191. package/src/Utils/decode-wa-message.ts +0 -228
  192. package/src/Utils/event-buffer.ts +0 -613
  193. package/src/Utils/generics.ts +0 -434
  194. package/src/Utils/history.ts +0 -112
  195. package/src/Utils/index.ts +0 -17
  196. package/src/Utils/link-preview.ts +0 -122
  197. package/src/Utils/logger.ts +0 -3
  198. package/src/Utils/lt-hash.ts +0 -61
  199. package/src/Utils/make-mutex.ts +0 -44
  200. package/src/Utils/messages-media.ts +0 -847
  201. package/src/Utils/messages.ts +0 -956
  202. package/src/Utils/noise-handler.ts +0 -197
  203. package/src/Utils/process-message.ts +0 -414
  204. package/src/Utils/signal.ts +0 -177
  205. package/src/Utils/use-multi-file-auth-state.ts +0 -90
  206. package/src/Utils/validate-connection.ts +0 -238
  207. package/src/WABinary/constants.ts +0 -42
  208. package/src/WABinary/decode.ts +0 -265
  209. package/src/WABinary/encode.ts +0 -236
  210. package/src/WABinary/generic-utils.ts +0 -121
  211. package/src/WABinary/index.ts +0 -5
  212. package/src/WABinary/jid-utils.ts +0 -68
  213. package/src/WABinary/types.ts +0 -17
  214. package/src/WAM/BinaryInfo.ts +0 -12
  215. package/src/WAM/constants.ts +0 -15382
  216. package/src/WAM/encode.ts +0 -174
  217. package/src/WAM/index.ts +0 -3
  218. package/src/gifted +0 -1
  219. package/src/index.ts +0 -13
  220. /package/{src → lib}/Defaults/phonenumber-mcc.json +0 -0
  221. /package/{src → lib}/Socket/Client/abstract-socket-client.js +0 -0
  222. /package/{src → lib}/Store/index.js +0 -0
  223. /package/{src → lib}/Store/make-ordered-dictionary.js +0 -0
  224. /package/{src → lib}/Types/Auth.js +0 -0
  225. /package/{src → lib}/Types/Call.js +0 -0
  226. /package/{src → lib}/Types/Chat.js +0 -0
  227. /package/{src → lib}/Types/Contact.js +0 -0
  228. /package/{src → lib}/Types/Events.js +0 -0
  229. /package/{src → lib}/Types/GroupMetadata.js +0 -0
  230. /package/{src → lib}/Types/Label.js +0 -0
  231. /package/{src → lib}/Types/LabelAssociation.js +0 -0
  232. /package/{src → lib}/Types/Message.js +0 -0
  233. /package/{src → lib}/Types/Newsletter.js +0 -0
  234. /package/{src → lib}/Types/Product.js +0 -0
  235. /package/{src → lib}/Types/Signal.js +0 -0
  236. /package/{src → lib}/Types/Socket.js +0 -0
  237. /package/{src → lib}/Types/State.js +0 -0
  238. /package/{src/WABinary/types.js → lib/Types/USync.js} +0 -0
  239. /package/{src → lib}/Types/index.js +0 -0
  240. /package/{src → lib}/Utils/index.js +0 -0
  241. /package/{src → lib}/Utils/logger.js +0 -0
  242. /package/{src → lib}/Utils/lt-hash.js +0 -0
  243. /package/{src → lib}/Utils/noise-handler.js +0 -0
  244. /package/{src → lib}/WABinary/constants.js +0 -0
  245. /package/{src → lib}/WABinary/decode.js +0 -0
  246. /package/{src → lib}/WABinary/generic-utils.js +0 -0
  247. /package/{src → lib}/WABinary/index.js +0 -0
  248. /package/{src → lib}/WABinary/jid-utils.js +0 -0
  249. /package/{src → lib}/WAM/BinaryInfo.js +0 -0
  250. /package/{src → lib}/WAM/constants.js +0 -0
  251. /package/{src → lib}/WAM/encode.js +0 -0
  252. /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
- }