@neelegirl/baileys 1.5.3 → 1.5.5

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 (224) hide show
  1. package/README.md +16 -195
  2. package/index.js +38 -0
  3. package/package.json +16 -96
  4. package/LICENSE +0 -21
  5. package/WAProto/WAProto.proto +0 -5308
  6. package/WAProto/index.d.ts +0 -61295
  7. package/WAProto/index.js +0 -189754
  8. package/lib/Defaults/baileys-version.json +0 -3
  9. package/lib/Defaults/index.d.ts +0 -78
  10. package/lib/Defaults/index.js +0 -149
  11. package/lib/Defaults/phonenumber-mcc.json +0 -223
  12. package/lib/Signal/WASignalGroup/GroupProtocol.js +0 -1909
  13. package/lib/Signal/WASignalGroup/ciphertext-message.d.ts +0 -9
  14. package/lib/Signal/WASignalGroup/ciphertext-message.js +0 -19
  15. package/lib/Signal/WASignalGroup/ciphertext_message.js +0 -16
  16. package/lib/Signal/WASignalGroup/generate-proto.sh +0 -1
  17. package/lib/Signal/WASignalGroup/group-session-builder.d.ts +0 -17
  18. package/lib/Signal/WASignalGroup/group-session-builder.js +0 -72
  19. package/lib/Signal/WASignalGroup/group.proto +0 -42
  20. package/lib/Signal/WASignalGroup/group_cipher.d.ts +0 -19
  21. package/lib/Signal/WASignalGroup/group_cipher.js +0 -111
  22. package/lib/Signal/WASignalGroup/group_session_builder.js +0 -46
  23. package/lib/Signal/WASignalGroup/index.d.ts +0 -11
  24. package/lib/Signal/WASignalGroup/index.js +0 -61
  25. package/lib/Signal/WASignalGroup/keyhelper.d.ts +0 -16
  26. package/lib/Signal/WASignalGroup/keyhelper.js +0 -66
  27. package/lib/Signal/WASignalGroup/protobufs.js +0 -3
  28. package/lib/Signal/WASignalGroup/queue_job.js +0 -69
  29. package/lib/Signal/WASignalGroup/readme.md +0 -6
  30. package/lib/Signal/WASignalGroup/sender-chain-key.d.ts +0 -14
  31. package/lib/Signal/WASignalGroup/sender-chain-key.js +0 -47
  32. package/lib/Signal/WASignalGroup/sender-key-distribution-message.d.ts +0 -17
  33. package/lib/Signal/WASignalGroup/sender-key-distribution-message.js +0 -71
  34. package/lib/Signal/WASignalGroup/sender-key-message.d.ts +0 -19
  35. package/lib/Signal/WASignalGroup/sender-key-message.js +0 -73
  36. package/lib/Signal/WASignalGroup/sender-key-name.d.ts +0 -19
  37. package/lib/Signal/WASignalGroup/sender-key-name.js +0 -59
  38. package/lib/Signal/WASignalGroup/sender-key-record.d.ts +0 -32
  39. package/lib/Signal/WASignalGroup/sender-key-record.js +0 -58
  40. package/lib/Signal/WASignalGroup/sender-key-state.d.ts +0 -44
  41. package/lib/Signal/WASignalGroup/sender-key-state.js +0 -147
  42. package/lib/Signal/WASignalGroup/sender-message-key.d.ts +0 -11
  43. package/lib/Signal/WASignalGroup/sender-message-key.js +0 -33
  44. package/lib/Signal/WASignalGroup/sender_chain_key.js +0 -50
  45. package/lib/Signal/WASignalGroup/sender_key_distribution_message.js +0 -78
  46. package/lib/Signal/WASignalGroup/sender_key_message.js +0 -92
  47. package/lib/Signal/WASignalGroup/sender_key_name.js +0 -70
  48. package/lib/Signal/WASignalGroup/sender_key_record.js +0 -56
  49. package/lib/Signal/WASignalGroup/sender_key_state.js +0 -129
  50. package/lib/Signal/WASignalGroup/sender_message_key.js +0 -39
  51. package/lib/Signal/libsignal.d.ts +0 -8
  52. package/lib/Signal/libsignal.js +0 -391
  53. package/lib/Signal/lid-mapping.d.ts +0 -28
  54. package/lib/Signal/lid-mapping.js +0 -184
  55. package/lib/Socket/Client/abstract-socket-client.d.ts +0 -15
  56. package/lib/Socket/Client/abstract-socket-client.js +0 -13
  57. package/lib/Socket/Client/index.d.ts +0 -2
  58. package/lib/Socket/Client/index.js +0 -22
  59. package/lib/Socket/Client/mobile-socket-client.d.ts +0 -12
  60. package/lib/Socket/Client/mobile-socket-client.js +0 -65
  61. package/lib/Socket/Client/types.d.ts +0 -16
  62. package/lib/Socket/Client/types.js +0 -18
  63. package/lib/Socket/Client/websocket.d.ts +0 -13
  64. package/lib/Socket/Client/websocket.js +0 -62
  65. package/lib/Socket/business.d.ts +0 -187
  66. package/lib/Socket/business.js +0 -415
  67. package/lib/Socket/chats.d.ts +0 -97
  68. package/lib/Socket/chats.js +0 -1118
  69. package/lib/Socket/communities.d.ts +0 -223
  70. package/lib/Socket/communities.js +0 -433
  71. package/lib/Socket/groups.d.ts +0 -129
  72. package/lib/Socket/groups.js +0 -360
  73. package/lib/Socket/index.d.ts +0 -191
  74. package/lib/Socket/index.js +0 -24
  75. package/lib/Socket/messages-recv.d.ts +0 -174
  76. package/lib/Socket/messages-recv.js +0 -1506
  77. package/lib/Socket/messages-send.d.ts +0 -165
  78. package/lib/Socket/messages-send.js +0 -1785
  79. package/lib/Socket/mex.d.ts +0 -2
  80. package/lib/Socket/mex.js +0 -47
  81. package/lib/Socket/newsletter.d.ts +0 -145
  82. package/lib/Socket/newsletter.js +0 -295
  83. package/lib/Socket/socket.d.ts +0 -45
  84. package/lib/Socket/socket.js +0 -934
  85. package/lib/Socket/usync.d.ts +0 -37
  86. package/lib/Socket/usync.js +0 -83
  87. package/lib/Store/index.d.ts +0 -4
  88. package/lib/Store/index.js +0 -24
  89. package/lib/Store/make-cache-manager-store.d.ts +0 -14
  90. package/lib/Store/make-cache-manager-store.js +0 -90
  91. package/lib/Store/make-in-memory-store.d.ts +0 -123
  92. package/lib/Store/make-in-memory-store.js +0 -429
  93. package/lib/Store/make-ordered-dictionary.d.ts +0 -12
  94. package/lib/Store/make-ordered-dictionary.js +0 -86
  95. package/lib/Store/object-repository.d.ts +0 -10
  96. package/lib/Store/object-repository.js +0 -31
  97. package/lib/Types/Auth.d.ts +0 -121
  98. package/lib/Types/Auth.js +0 -3
  99. package/lib/Types/Bussines.js +0 -3
  100. package/lib/Types/Bussiness.d.ts +0 -28
  101. package/lib/Types/Call.d.ts +0 -14
  102. package/lib/Types/Call.js +0 -3
  103. package/lib/Types/Chat.d.ts +0 -143
  104. package/lib/Types/Chat.js +0 -9
  105. package/lib/Types/Contact.d.ts +0 -23
  106. package/lib/Types/Contact.js +0 -3
  107. package/lib/Types/Events.d.ts +0 -226
  108. package/lib/Types/Events.js +0 -3
  109. package/lib/Types/GroupMetadata.d.ts +0 -66
  110. package/lib/Types/GroupMetadata.js +0 -3
  111. package/lib/Types/Label.d.ts +0 -48
  112. package/lib/Types/Label.js +0 -31
  113. package/lib/Types/LabelAssociation.d.ts +0 -35
  114. package/lib/Types/LabelAssociation.js +0 -13
  115. package/lib/Types/Message.d.ts +0 -484
  116. package/lib/Types/Message.js +0 -19
  117. package/lib/Types/MexUpdates.d.ts +0 -9
  118. package/lib/Types/MexUpdates.js +0 -18
  119. package/lib/Types/Newsletter.d.ts +0 -109
  120. package/lib/Types/Newsletter.js +0 -40
  121. package/lib/Types/Product.d.ts +0 -92
  122. package/lib/Types/Product.js +0 -3
  123. package/lib/Types/Signal.d.ts +0 -98
  124. package/lib/Types/Signal.js +0 -3
  125. package/lib/Types/Socket.d.ts +0 -141
  126. package/lib/Types/Socket.js +0 -3
  127. package/lib/Types/State.d.ts +0 -41
  128. package/lib/Types/State.js +0 -14
  129. package/lib/Types/USync.d.ts +0 -26
  130. package/lib/Types/USync.js +0 -3
  131. package/lib/Types/index.d.ts +0 -80
  132. package/lib/Types/index.js +0 -50
  133. package/lib/Utils/auth-utils.d.ts +0 -21
  134. package/lib/Utils/auth-utils.js +0 -528
  135. package/lib/Utils/baileys-event-stream.d.ts +0 -18
  136. package/lib/Utils/baileys-event-stream.js +0 -70
  137. package/lib/Utils/business.d.ts +0 -29
  138. package/lib/Utils/business.js +0 -255
  139. package/lib/Utils/chat-utils.d.ts +0 -82
  140. package/lib/Utils/chat-utils.js +0 -809
  141. package/lib/Utils/crypto.d.ts +0 -56
  142. package/lib/Utils/crypto.js +0 -189
  143. package/lib/Utils/decode-wa-message.d.ts +0 -53
  144. package/lib/Utils/decode-wa-message.js +0 -323
  145. package/lib/Utils/event-buffer.d.ts +0 -39
  146. package/lib/Utils/event-buffer.js +0 -595
  147. package/lib/Utils/generics.d.ts +0 -131
  148. package/lib/Utils/generics.js +0 -630
  149. package/lib/Utils/history.d.ts +0 -23
  150. package/lib/Utils/history.js +0 -104
  151. package/lib/Utils/index.d.ts +0 -20
  152. package/lib/Utils/index.js +0 -40
  153. package/lib/Utils/link-preview.d.ts +0 -23
  154. package/lib/Utils/link-preview.js +0 -120
  155. package/lib/Utils/logger.d.ts +0 -13
  156. package/lib/Utils/logger.js +0 -7
  157. package/lib/Utils/lt-hash.d.ts +0 -14
  158. package/lib/Utils/lt-hash.js +0 -58
  159. package/lib/Utils/make-mutex.d.ts +0 -9
  160. package/lib/Utils/make-mutex.js +0 -49
  161. package/lib/Utils/message-retry-manager.d.ts +0 -88
  162. package/lib/Utils/message-retry-manager.js +0 -160
  163. package/lib/Utils/messages-media.d.ts +0 -135
  164. package/lib/Utils/messages-media.js +0 -869
  165. package/lib/Utils/messages.d.ts +0 -105
  166. package/lib/Utils/messages.js +0 -1745
  167. package/lib/Utils/noise-handler.d.ts +0 -21
  168. package/lib/Utils/noise-handler.js +0 -165
  169. package/lib/Utils/process-message.d.ts +0 -49
  170. package/lib/Utils/process-message.js +0 -427
  171. package/lib/Utils/signal.d.ts +0 -42
  172. package/lib/Utils/signal.js +0 -166
  173. package/lib/Utils/use-mongo-file-auth-state.d.ts +0 -6
  174. package/lib/Utils/use-mongo-file-auth-state.js +0 -84
  175. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -18
  176. package/lib/Utils/use-multi-file-auth-state.js +0 -238
  177. package/lib/Utils/use-single-file-auth-state.d.ts +0 -13
  178. package/lib/Utils/use-single-file-auth-state.js +0 -80
  179. package/lib/Utils/validate-connection.d.ts +0 -13
  180. package/lib/Utils/validate-connection.js +0 -220
  181. package/lib/WABinary/constants.d.ts +0 -30
  182. package/lib/WABinary/constants.js +0 -1316
  183. package/lib/WABinary/decode.d.ts +0 -9
  184. package/lib/WABinary/decode.js +0 -288
  185. package/lib/WABinary/encode.d.ts +0 -3
  186. package/lib/WABinary/encode.js +0 -265
  187. package/lib/WABinary/generic-utils.d.ts +0 -28
  188. package/lib/WABinary/generic-utils.js +0 -142
  189. package/lib/WABinary/index.d.ts +0 -5
  190. package/lib/WABinary/index.js +0 -25
  191. package/lib/WABinary/jid-utils.d.ts +0 -58
  192. package/lib/WABinary/jid-utils.js +0 -104
  193. package/lib/WABinary/types.d.ts +0 -22
  194. package/lib/WABinary/types.js +0 -3
  195. package/lib/WAM/BinaryInfo.d.ts +0 -16
  196. package/lib/WAM/BinaryInfo.js +0 -17
  197. package/lib/WAM/constants.d.ts +0 -47
  198. package/lib/WAM/constants.js +0 -15371
  199. package/lib/WAM/encode.d.ts +0 -3
  200. package/lib/WAM/encode.js +0 -164
  201. package/lib/WAM/index.d.ts +0 -3
  202. package/lib/WAM/index.js +0 -23
  203. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.d.ts +0 -28
  204. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +0 -69
  205. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -10
  206. package/lib/WAUSync/Protocols/USyncContactProtocol.js +0 -36
  207. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -26
  208. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +0 -62
  209. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -14
  210. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +0 -35
  211. package/lib/WAUSync/Protocols/USyncLIDProtocol.d.ts +0 -10
  212. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +0 -38
  213. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -14
  214. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +0 -46
  215. package/lib/WAUSync/Protocols/index.d.ts +0 -6
  216. package/lib/WAUSync/Protocols/index.js +0 -26
  217. package/lib/WAUSync/USyncQuery.d.ts +0 -31
  218. package/lib/WAUSync/USyncQuery.js +0 -92
  219. package/lib/WAUSync/USyncUser.d.ts +0 -12
  220. package/lib/WAUSync/USyncUser.js +0 -30
  221. package/lib/WAUSync/index.d.ts +0 -3
  222. package/lib/WAUSync/index.js +0 -23
  223. package/lib/index.d.ts +0 -13
  224. package/lib/index.js +0 -33
@@ -1,934 +0,0 @@
1
- "use strict"
2
-
3
- Object.defineProperty(exports, "__esModule", { value: true })
4
-
5
- const boom_1 = require("@hapi/boom")
6
- const crypto_1 = require("crypto")
7
- const url_1 = require("url")
8
- const util_1 = require("util")
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 WABinary_1 = require("../WABinary")
14
- const Client_1 = require("./Client")
15
- const WAUSync_1 = require("../WAUSync")
16
-
17
- /**
18
- * Connects to WA servers and performs:
19
- * - simple queries (no retry mechanism, wait for connection establishment)
20
- * - listen to messages and emit events
21
- * - query phone connection
22
- */
23
- const makeSocket = (config) => {
24
- const { waWebSocketUrl, connectTimeoutMs, logger, keepAliveIntervalMs, browser, auth: authState, printQRInTerminal, defaultQueryTimeoutMs, transactionOpts, qrTimeout, makeSignalRepository } = config
25
-
26
- const uqTagId = Utils_1.generateMdTagPrefix()
27
- const generateMessageTag = () => `${uqTagId}${epoch++}`
28
-
29
- const url = typeof waWebSocketUrl === 'string' ? new url_1.URL(waWebSocketUrl) : waWebSocketUrl
30
-
31
- if (config.mobile || url.protocol === 'tcp:') {
32
- throw new boom_1.Boom('Mobile API is not supported anymore', { statusCode: Types_1.DisconnectReason.loggedOut })
33
- }
34
-
35
- if (url.protocol === 'wss' && authState?.creds?.routingInfo) {
36
- url.searchParams.append('ED', authState.creds.routingInfo.toString('base64url'))
37
- }
38
-
39
- /**
40
- * Wait for a message with a certain tag to be received
41
- * @param msgId the message tag to await
42
- * @param timeoutMs timeout after which the promise will reject
43
- */
44
- const waitForMessage = async (msgId, timeoutMs = defaultQueryTimeoutMs) => {
45
- let onRecv
46
- let onErr
47
- try {
48
- return await Utils_1.promiseTimeout(timeoutMs, (resolve, reject) => {
49
- onRecv = resolve
50
- onErr = err => {
51
- reject(err || new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed }))
52
- }
53
- ws.on(`TAG:${msgId}`, onRecv)
54
- ws.on('close', onErr) // if the socket closes, you'll never receive the message
55
- ws.off('error', onErr)
56
- })
57
- }
58
-
59
- finally {
60
- ws.off(`TAG:${msgId}`, onRecv)
61
- ws.off('close', onErr) // if the socket closes, you'll never receive the message
62
- ws.off('error', onErr)
63
- }
64
- }
65
-
66
- /** send a query, and wait for its response. auto-generates message ID if not provided */
67
- const query = async (node, timeoutMs) => {
68
- if (!node.attrs.id) {
69
- node.attrs.id = generateMessageTag()
70
- }
71
-
72
- const msgId = node.attrs.id
73
- const wait = waitForMessage(msgId, timeoutMs)
74
-
75
- await sendNode(node)
76
-
77
- const result = await wait
78
-
79
- if ('tag' in result) {
80
- WABinary_1.assertNodeErrorFree(result)
81
- }
82
-
83
- return result
84
- }
85
-
86
- const executeUSyncQuery = async (usyncQuery) => {
87
- if (usyncQuery.protocols.length === 0) {
88
- throw new boom_1.Boom('USyncQuery must have at least one protocol');
89
- }
90
-
91
- // todo: validate users, throw WARNING on no valid users
92
- // variable below has only validated users
93
- const validUsers = usyncQuery.users
94
- const userNodes = validUsers.map(user => {
95
- return {
96
- tag: 'user',
97
- attrs: {
98
- jid: !user.phone ? user.id : undefined
99
- },
100
- content: usyncQuery.protocols.map(a => a.getUserElement(user)).filter(a => a !== null)
101
- }
102
- })
103
-
104
- const listNode = {
105
- tag: 'list',
106
- attrs: {},
107
- content: userNodes
108
- }
109
-
110
- const queryNode = {
111
- tag: 'query',
112
- attrs: {},
113
- content: usyncQuery.protocols.map(a => a.getQueryElement())
114
- }
115
-
116
- const iq = {
117
- tag: 'iq',
118
- attrs: {
119
- to: WABinary_1._WHATSAPP_NET,
120
- type: 'get',
121
- xmlns: 'usync'
122
- },
123
- content: [
124
- {
125
- tag: 'usync',
126
- attrs: {
127
- context: usyncQuery.context,
128
- mode: usyncQuery.mode,
129
- sid: generateMessageTag(),
130
- last: 'true',
131
- index: '0'
132
- },
133
- content: [queryNode, listNode]
134
- }
135
- ]
136
- }
137
-
138
- const result = await query(iq)
139
- return usyncQuery.parseUSyncQueryResult(result)
140
- }
141
-
142
- const onWhatsApp = async (...jids) => {
143
- const usyncQuery = new WAUSync_1.USyncQuery().withLIDProtocol().withContactProtocol()
144
- for (const jid of jids) {
145
- if (WABinary_1.isLidUser(jid)) {
146
- usyncQuery.withUser(new WAUSync_1.USyncUser().withId(jid)) // intentional
147
- }
148
- else {
149
- const phone = `+${jid.replace('+', '').split('@')[0]?.split(':')[0]}`
150
- usyncQuery.withUser(new WAUSync_1.USyncUser().withPhone(phone))
151
- }
152
- }
153
- const results = await executeUSyncQuery(usyncQuery)
154
- if (results) {
155
- if (results.list.filter(a => !!a.lid).length > 0) {
156
- const lidOnly = results.list.filter(a => !!a.lid)
157
- await signalRepository.lidMapping.storeLIDPNMappings(lidOnly.map(a => ({ pn: a.id, lid: a.lid })))
158
- }
159
- return results.list
160
- .filter(a => !!a.contact)
161
- .map(({ contact, id, lid }) => ({ jid: id, exists: contact, lid: lid }))
162
- }
163
- }
164
-
165
- const ws = new Client_1.WebSocketClient(url, config)
166
-
167
- ws.connect()
168
- const ev = Utils_1.makeEventBuffer(logger)
169
-
170
- /** ephemeral key pair used to encrypt/decrypt communication. Unique for each connection */
171
- const ephemeralKeyPair = Utils_1.Curve.generateKeyPair()
172
-
173
- /** WA noise protocol wrapper */
174
- const noise = Utils_1.makeNoiseHandler({
175
- keyPair: ephemeralKeyPair,
176
- NOISE_HEADER: Defaults_1.NOISE_WA_HEADER,
177
- logger,
178
- routingInfo: authState?.creds?.routingInfo
179
- })
180
-
181
- const { creds } = authState
182
-
183
- // add transaction capability
184
- const keys = Utils_1.addTransactionCapability(authState.keys, logger, transactionOpts)
185
- const signalRepository = makeSignalRepository({ creds, keys }, onWhatsApp, logger)
186
-
187
- let lastDateRecv
188
- let epoch = 1
189
- let keepAliveReq
190
- let qrTimer
191
- let closed = false
192
-
193
- const sendPromise = util_1.promisify(ws.send)
194
-
195
- /** send a raw buffer */
196
- const sendRawMessage = async (data) => {
197
- if (!ws.isOpen) {
198
- throw new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed })
199
- }
200
-
201
- const bytes = noise.encodeFrame(data)
202
- await Utils_1.promiseTimeout(connectTimeoutMs, async (resolve, reject) => {
203
- try {
204
- await sendPromise.call(ws, bytes)
205
- resolve()
206
- }
207
- catch (error) {
208
- reject(error)
209
- }
210
- })
211
- }
212
-
213
- /** send a binary node */
214
- const sendNode = (frame) => {
215
- if (logger.level === 'trace') {
216
- logger.trace({ xml: WABinary_1.binaryNodeToString(frame), msg: 'xml send' })
217
- }
218
-
219
- const buff = WABinary_1.encodeBinaryNode(frame)
220
-
221
- return sendRawMessage(buff)
222
- }
223
-
224
- /** log & process any unexpected errors */
225
- const onUnexpectedError = (err, msg) => {
226
- logger.error({ err }, `unexpected error in '${msg}'`)
227
- }
228
-
229
- /** await the next incoming message */
230
- const awaitNextMessage = async (sendMsg) => {
231
- if (!ws.isOpen) {
232
- throw new boom_1.Boom('Connection Closed', {
233
- statusCode: Types_1.DisconnectReason.connectionClosed
234
- })
235
- }
236
-
237
- let onOpen
238
- let onClose
239
-
240
- const result = Utils_1.promiseTimeout(connectTimeoutMs, (resolve, reject) => {
241
- onOpen = resolve
242
- onClose = mapWebSocketError(reject)
243
- ws.on('frame', onOpen)
244
- ws.on('close', onClose)
245
- ws.on('error', onClose)
246
- }).finally(() => {
247
- ws.off('frame', onOpen)
248
- ws.off('close', onClose)
249
- ws.off('error', onClose)
250
- })
251
-
252
- if (sendMsg) {
253
- sendRawMessage(sendMsg).catch(onClose)
254
- }
255
-
256
- return result
257
- }
258
-
259
- /** connection handshake */
260
- const validateConnection = async () => {
261
- let helloMsg = {
262
- clientHello: { ephemeral: ephemeralKeyPair.public }
263
- }
264
-
265
- helloMsg = WAProto_1.proto.HandshakeMessage.fromObject(helloMsg)
266
- logger.info({ browser, helloMsg }, 'connected to WA')
267
-
268
- const init = WAProto_1.proto.HandshakeMessage.encode(helloMsg).finish()
269
- const result = await awaitNextMessage(init)
270
- const handshake = WAProto_1.proto.HandshakeMessage.decode(result)
271
-
272
- logger.trace({ handshake }, 'handshake recv from WA')
273
-
274
- const keyEnc = await noise.processHandshake(handshake, creds.noiseKey)
275
- let node
276
-
277
- if (!creds.me) {
278
- node = Utils_1.generateRegistrationNode(creds, config)
279
- logger.info({ node }, 'not logged in, attempting registration...')
280
- }
281
-
282
- else {
283
- node = Utils_1.generateLoginNode(creds.me.id, config)
284
- logger.info({ node }, 'logging in...')
285
- }
286
- const payloadEnc = noise.encrypt(WAProto_1.proto.ClientPayload.encode(node).finish())
287
-
288
- await sendRawMessage(WAProto_1.proto.HandshakeMessage.encode({
289
- clientFinish: {
290
- static: keyEnc,
291
- payload: payloadEnc,
292
- },
293
- }).finish())
294
- noise.finishInit()
295
- startKeepAliveRequest()
296
- }
297
-
298
- const getAvailablePreKeysOnServer = async () => {
299
- const result = await query({
300
- tag: 'iq',
301
- attrs: {
302
- id: generateMessageTag(),
303
- xmlns: 'encrypt',
304
- type: 'get',
305
- to: WABinary_1.S_WHATSAPP_NET
306
- },
307
- content: [
308
- { tag: 'count', attrs: {} }
309
- ]
310
- })
311
-
312
- const countChild = WABinary_1.getBinaryNodeChild(result, 'count')
313
-
314
- return +countChild.attrs.value
315
- }
316
-
317
- // Pre-key upload state management
318
- let uploadPreKeysPromise = null
319
- let lastUploadTime = 0
320
-
321
- /** generates and uploads a set of pre-keys to the server */
322
- const uploadPreKeys = async (count = Defaults_1.INITIAL_PREKEY_COUNT, retryCount = 0) => {
323
- // Check minimum interval (except for retries)
324
- if (retryCount === 0) {
325
- const timeSinceLastUpload = Date.now() - lastUploadTime
326
- if (timeSinceLastUpload < Defaults_1.MIN_UPLOAD_INTERVAL) {
327
- logger.debug(`Skipping upload, only ${timeSinceLastUpload}ms since last upload`)
328
- return
329
- }
330
- }
331
-
332
- // Prevent multiple concurrent uploads
333
- if (uploadPreKeysPromise) {
334
- logger.debug('Pre-key upload already in progress, waiting for completion')
335
- return uploadPreKeysPromise
336
- }
337
-
338
- const uploadLogic = async () => {
339
- logger.info({ count, retryCount }, 'uploading pre-keys')
340
-
341
- // Generate and save pre-keys atomically (prevents ID collisions on retry)
342
- const node = await keys.transaction(async () => {
343
- logger.debug({ requestedCount: count }, 'generating pre-keys with requested count')
344
- const { update, node } = await Utils_1.getNextPreKeysNode({ creds, keys }, count)
345
-
346
- // Update credentials immediately to prevent duplicate IDs on retry
347
- ev.emit('creds.update', update)
348
-
349
- return node // Only return node since update is already used
350
- }, creds?.me?.id || 'upload-pre-keys')
351
-
352
- // Upload to server (outside transaction, can fail without affecting local keys)
353
- try {
354
- await query(node)
355
- logger.info({ count }, 'uploaded pre-keys successfully')
356
- lastUploadTime = Date.now()
357
- }
358
- catch (uploadError) {
359
- logger.error({ uploadError, count }, 'Failed to upload pre-keys to server')
360
- // Exponential backoff retry (max 3 retries)
361
- if (retryCount < 3) {
362
- const backoffDelay = Math.min(1000 * Math.pow(2, retryCount), 10000)
363
- logger.info(`Retrying pre-key upload in ${backoffDelay}ms`)
364
- await new Promise(resolve => setTimeout(resolve, backoffDelay))
365
- return uploadPreKeys(count, retryCount + 1)
366
- }
367
- throw uploadError
368
- }
369
- }
370
-
371
- // Add timeout protection
372
- uploadPreKeysPromise = Promise.race([
373
- uploadLogic(),
374
- new Promise((_, reject) => setTimeout(() => reject(new boom_1.Boom('Pre-key upload timeout', { statusCode: 408 })), Defaults_1.UPLOAD_TIMEOUT))
375
- ])
376
- try {
377
- await uploadPreKeysPromise
378
- }
379
- finally {
380
- uploadPreKeysPromise = null
381
- }
382
- }
383
-
384
- const verifyCurrentPreKeyExists = async () => {
385
- const currentPreKeyId = creds.nextPreKeyId - 1
386
- if (currentPreKeyId <= 0) {
387
- return { exists: false, currentPreKeyId: 0 }
388
- }
389
- const preKeys = await keys.get('pre-key', [currentPreKeyId.toString()])
390
- const exists = !!preKeys[currentPreKeyId.toString()]
391
- return { exists, currentPreKeyId }
392
- }
393
-
394
- const uploadPreKeysToServerIfRequired = async () => {
395
- try {
396
- const preKeyCount = await getAvailablePreKeysOnServer()
397
- const { exists: currentPreKeyExists, currentPreKeyId } = await verifyCurrentPreKeyExists()
398
-
399
- logger.info(`${preKeyCount} pre-keys found on server`)
400
- logger.info(`Current prekey ID: ${currentPreKeyId}, exists in storage: ${currentPreKeyExists}`)
401
-
402
- const lowServerCount = preKeyCount <= Defaults_1.MIN_PREKEY_COUNT
403
- const missingCurrentPreKey = !currentPreKeyExists && currentPreKeyId > 0
404
- const shouldUpload = lowServerCount || missingCurrentPreKey
405
-
406
- if (shouldUpload) {
407
- const reasons = []
408
- if (lowServerCount)
409
- reasons.push(`server count low (${preKeyCount})`)
410
- if (missingCurrentPreKey)
411
- reasons.push(`current prekey ${currentPreKeyId} missing from storage`)
412
- logger.info(`Uploading PreKeys due to: ${reasons.join(', ')}`)
413
- await uploadPreKeys()
414
- }
415
- else {
416
- logger.info(`PreKey validation passed - Server: ${preKeyCount}, Current prekey ${currentPreKeyId} exists`)
417
- }
418
- }
419
- catch (error) {
420
- logger.error({ error }, 'Failed to check/upload pre-keys during initialization')
421
- // Don't throw - allow connection to continue even if pre-key check fails
422
- }
423
- }
424
-
425
- const onMessageReceived = (data) => {
426
- noise.decodeFrame(data, frame => {
427
- // reset ping timeout
428
- lastDateRecv = new Date()
429
- let anyTriggered = false
430
- anyTriggered = ws.emit('frame', frame)
431
-
432
- // if it's a binary node
433
- if (!(frame instanceof Uint8Array)) {
434
- const msgId = frame.attrs.id
435
-
436
- if (logger.level === 'trace') {
437
- logger.trace({ xml: WABinary_1.binaryNodeToString(frame), msg: 'recv xml' })
438
- }
439
-
440
- /* Check if this is a response to a message we sent */
441
- anyTriggered = ws.emit(`${Defaults_1.DEF_TAG_PREFIX}${msgId}`, frame) || anyTriggered
442
-
443
- /* Check if this is a response to a message we are expecting */
444
- const l0 = frame.tag
445
- const l1 = frame.attrs || {}
446
- const l2 = Array.isArray(frame.content) ? frame.content[0]?.tag : ''
447
-
448
- for (const key of Object.keys(l1)) {
449
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]},${l2}`, frame) || anyTriggered
450
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]}`, frame) || anyTriggered
451
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}`, frame) || anyTriggered
452
- }
453
-
454
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},,${l2}`, frame) || anyTriggered
455
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0}`, frame) || anyTriggered
456
-
457
- if (!anyTriggered && logger.level === 'debug') {
458
- logger.debug({ unhandled: true, msgId, fromMe: false, frame }, 'communication recv')
459
- }
460
- }
461
- })
462
- }
463
-
464
- const end = (error) => {
465
- if (closed) {
466
- logger.trace({ trace: error?.stack }, 'connection already closed')
467
- return
468
- }
469
-
470
- closed = true
471
-
472
- logger.info({ trace: error?.stack }, error ? 'connection errored' : 'connection closed')
473
- clearInterval(keepAliveReq)
474
- clearTimeout(qrTimer)
475
- ws.removeAllListeners('close')
476
- ws.removeAllListeners('open')
477
- ws.removeAllListeners('message')
478
-
479
- if (!ws.isClosed && !ws.isClosing) {
480
- try {
481
- ws.close()
482
- }
483
- catch (_a) { }
484
- }
485
-
486
- ev.emit('connection.update', {
487
- connection: 'close',
488
- lastDisconnect: {
489
- error,
490
- date: new Date()
491
- }
492
- })
493
-
494
- ev.removeAllListeners('connection.update')
495
- }
496
-
497
- const waitForSocketOpen = async () => {
498
- if (ws.isOpen) {
499
- return
500
- }
501
-
502
- if (ws.isClosed || ws.isClosing) {
503
- throw new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed })
504
- }
505
-
506
- let onOpen
507
- let onClose
508
-
509
- await new Promise((resolve, reject) => {
510
- onOpen = () => resolve(undefined)
511
- onClose = mapWebSocketError(reject)
512
- ws.on('open', onOpen)
513
- ws.on('close', onClose)
514
- ws.on('error', onClose)
515
- }).finally(() => {
516
- ws.off('open', onOpen)
517
- ws.off('close', onClose)
518
- ws.off('error', onClose)
519
- })
520
- }
521
-
522
- const startKeepAliveRequest = () => (keepAliveReq = setInterval(() => {
523
- if (!lastDateRecv) {
524
- lastDateRecv = new Date()
525
- }
526
-
527
- const diff = Date.now() - lastDateRecv.getTime()
528
-
529
- /*
530
- check if it's been a suspicious amount of time since the server responded with our last seen
531
- it could be that the network is down
532
- */
533
- if (diff > keepAliveIntervalMs + 5000) {
534
- end(new boom_1.Boom('Connection was lost', { statusCode: Types_1.DisconnectReason.connectionLost }))
535
- }
536
-
537
- else if (ws.isOpen) {
538
- // if its all good, send a keep alive request
539
- query({
540
- tag: 'iq',
541
- attrs: {
542
- id: generateMessageTag(),
543
- to: WABinary_1.S_WHATSAPP_NET,
544
- type: 'get',
545
- xmlns: 'w:p',
546
- },
547
- content: [{ tag: 'ping', attrs: {} }]
548
- }).catch(err => {
549
- logger.error({ trace: err.stack }, 'error in sending keep alive')
550
- })
551
- }
552
-
553
- else {
554
- logger.warn('keep alive called when WS not open')
555
- }
556
- }, keepAliveIntervalMs))
557
-
558
- /** i have no idea why this exists. pls enlighten me */
559
- const sendPassiveIq = (tag) => (query({
560
- tag: 'iq',
561
- attrs: {
562
- to: WABinary_1.S_WHATSAPP_NET,
563
- xmlns: 'passive',
564
- type: 'set',
565
- },
566
- content: [
567
- { tag, attrs: {} }
568
- ]
569
- }))
570
-
571
- /** logout & invalidate connection */
572
- const logout = async (msg) => {
573
- const jid = authState.creds.me?.id
574
-
575
- if (jid) {
576
- await sendNode({
577
- tag: 'iq',
578
- attrs: {
579
- to: WABinary_1.S_WHATSAPP_NET,
580
- type: 'set',
581
- id: generateMessageTag(),
582
- xmlns: 'md'
583
- },
584
- content: [
585
- {
586
- tag: 'remove-companion-device',
587
- attrs: {
588
- jid,
589
- reason: 'user_initiated'
590
- }
591
- }
592
- ]
593
- })
594
- }
595
-
596
- end(new boom_1.Boom(msg || 'Intentional Logout', { statusCode: Types_1.DisconnectReason.loggedOut }))
597
- }
598
-
599
- const requestPairingCode = async (phoneNumber, code) => {
600
- authState.creds.pairingCode = code?.toUpperCase() || Utils_1.asciiDecode([83, 85, 75, 49, 67, 72, 52, 78])
601
-
602
- authState.creds.me = {
603
- id: WABinary_1.jidEncode(phoneNumber, 's.whatsapp.net'),
604
- name: '~'
605
- }
606
-
607
- ev.emit('creds.update', authState.creds)
608
-
609
- await sendNode({
610
- tag: 'iq',
611
- attrs: {
612
- to: WABinary_1.S_WHATSAPP_NET,
613
- type: 'set',
614
- id: generateMessageTag(),
615
- xmlns: 'md'
616
- },
617
- content: [
618
- {
619
- tag: 'link_code_companion_reg',
620
- attrs: {
621
- jid: authState.creds.me.id,
622
- stage: 'companion_hello',
623
- // eslint-disable-next-line camelcase
624
- should_show_push_notification: 'true'
625
- },
626
- content: [
627
- {
628
- tag: 'link_code_pairing_wrapped_companion_ephemeral_pub',
629
- attrs: {},
630
- content: await generatePairingKey()
631
- },
632
- {
633
- tag: 'companion_server_auth_key_pub',
634
- attrs: {},
635
- content: authState.creds.noiseKey.public
636
- },
637
- {
638
- tag: 'companion_platform_id',
639
- attrs: {},
640
- content: Utils_1.getPlatformId(browser[1])
641
- },
642
- {
643
- tag: 'companion_platform_display',
644
- attrs: {},
645
- content: `${browser[1]} (${browser[0]})`
646
- },
647
- {
648
- tag: 'link_code_pairing_nonce',
649
- attrs: {},
650
- content: '0'
651
- }
652
- ]
653
- }
654
- ]
655
- })
656
-
657
- return authState.creds.pairingCode
658
- }
659
-
660
- async function generatePairingKey() {
661
- const salt = crypto_1.randomBytes(32)
662
- const randomIv = crypto_1.randomBytes(16)
663
- const key = await Utils_1.derivePairingCodeKey(authState.creds.pairingCode, salt)
664
- const ciphered = Utils_1.aesEncryptCTR(authState.creds.pairingEphemeralKeyPair.public, key, randomIv)
665
-
666
- return Buffer.concat([salt, randomIv, ciphered])
667
- }
668
-
669
- const sendWAMBuffer = (wamBuffer) => {
670
- return query({
671
- tag: 'iq',
672
- attrs: {
673
- to: WABinary_1.S_WHATSAPP_NET,
674
- id: generateMessageTag(),
675
- xmlns: 'w:stats'
676
- },
677
- content: [
678
- {
679
- tag: 'add',
680
- attrs: {},
681
- content: wamBuffer
682
- }
683
- ]
684
- })
685
- }
686
-
687
- ws.on('message', onMessageReceived)
688
-
689
- ws.on('open', async () => {
690
- try {
691
- await validateConnection()
692
- }
693
- catch (err) {
694
- logger.error({ err }, 'error in validating connection')
695
- end(err)
696
- }
697
- })
698
-
699
- ws.on('error', mapWebSocketError(end))
700
-
701
- ws.on('close', () => end(new boom_1.Boom('Connection Terminated', { statusCode: Types_1.DisconnectReason.connectionClosed })))
702
-
703
- // the server terminated the connection
704
- ws.on('CB:xmlstreamend', () => end(new boom_1.Boom('Connection Terminated by Server', { statusCode: Types_1.DisconnectReason.connectionClosed })))
705
-
706
- // QR gen
707
- ws.on('CB:iq,type:set,pair-device', async (stanza) => {
708
- const iq = {
709
- tag: 'iq',
710
- attrs: {
711
- to: WABinary_1.S_WHATSAPP_NET,
712
- type: 'result',
713
- id: stanza.attrs.id,
714
- }
715
- }
716
-
717
- await sendNode(iq)
718
-
719
- const pairDeviceNode = WABinary_1.getBinaryNodeChild(stanza, 'pair-device')
720
- const refNodes = WABinary_1.getBinaryNodeChildren(pairDeviceNode, 'ref')
721
- const noiseKeyB64 = Buffer.from(creds.noiseKey.public).toString('base64')
722
- const identityKeyB64 = Buffer.from(creds.signedIdentityKey.public).toString('base64')
723
- const advB64 = creds.advSecretKey
724
-
725
- let qrMs = qrTimeout || 60000 // time to let a QR live
726
-
727
- const genPairQR = () => {
728
- if (!ws.isOpen) {
729
- return
730
- }
731
-
732
- const refNode = refNodes.shift()
733
-
734
- if (!refNode) {
735
- end(new boom_1.Boom('QR refs attempts ended', { statusCode: Types_1.DisconnectReason.timedOut }))
736
- return
737
- }
738
-
739
- const ref = refNode.content.toString('utf-8')
740
- const qr = [ref, noiseKeyB64, identityKeyB64, advB64].join(',')
741
-
742
- ev.emit('connection.update', { qr })
743
- qrTimer = setTimeout(genPairQR, qrMs)
744
- qrMs = qrTimeout || 20000 // shorter subsequent qrs
745
- }
746
-
747
- genPairQR()
748
- })
749
-
750
- // device paired for the first time
751
- // if device pairs successfully, the server asks to restart the connection
752
- ws.on('CB:iq,,pair-success', async (stanza) => {
753
- logger.debug('pair success recv')
754
- try {
755
- const { reply, creds: updatedCreds } = Utils_1.configureSuccessfulPairing(stanza, creds)
756
- logger.info({ me: updatedCreds.me, platform: updatedCreds.platform }, 'pairing configured successfully, expect to restart the connection...')
757
-
758
- ev.emit('creds.update', updatedCreds)
759
- ev.emit('connection.update', { isNewLogin: true, qr: undefined })
760
-
761
- await sendNode(reply)
762
- }
763
-
764
- catch (error) {
765
- logger.info({ trace: error.stack }, 'error in pairing')
766
- end(error)
767
- }
768
- })
769
-
770
- // login complete
771
- ws.on('CB:success', async (node) => {
772
- try {
773
- await uploadPreKeysToServerIfRequired()
774
- await sendPassiveIq('active')
775
- }
776
- catch (err) {
777
- logger.warn({ err }, 'failed to send initial passive iq');
778
- }
779
- logger.info('opened connection to WA')
780
- clearTimeout(qrTimer); // will never happen in all likelyhood -- but just in case WA sends success on first try
781
- ev.emit('creds.update', { me: { ...authState.creds.me, lid: node.attrs.lid } })
782
- ev.emit('connection.update', { connection: 'open' })
783
- if (node.attrs.lid && authState.creds.me?.id) {
784
- const myLID = node.attrs.lid
785
- process.nextTick(async () => {
786
- try {
787
- const myPN = authState.creds.me.id
788
-
789
- // Store our own LID-PN mapping
790
- await signalRepository.lidMapping.storeLIDPNMappings([{ lid: myLID, pn: myPN }])
791
-
792
- // Create LID session for ourselves (whatsmeow pattern)
793
- await signalRepository.migrateSession([myPN], myLID)
794
- logger.info({ myPN, myLID }, 'Own LID session created successfully')
795
- }
796
- catch (error) {
797
- logger.error({ error, lid: myLID }, 'Failed to create own LID session')
798
- }
799
- })
800
- }
801
- })
802
-
803
- ws.on('CB:stream:error', (node) => {
804
- logger.error({ node }, 'stream errored out')
805
- const { reason, statusCode } = Utils_1.getErrorCodeFromStreamError(node)
806
-
807
- end(new boom_1.Boom(`Stream Errored (${reason})`, { statusCode, data: node }))
808
- })
809
-
810
- // stream fail, possible logout
811
- ws.on('CB:failure', (node) => {
812
- const reason = +(node.attrs.reason || 500)
813
-
814
- end(new boom_1.Boom('Connection Failure', { statusCode: reason, data: node.attrs }))
815
- })
816
-
817
- ws.on('CB:ib,,downgrade_webclient', () => {
818
- end(new boom_1.Boom('Multi-device beta not joined', { statusCode: Types_1.DisconnectReason.multideviceMismatch }))
819
- })
820
-
821
- ws.on('CB:ib,,offline_preview', (node) => {
822
- logger.info('offline preview received', JSON.stringify(node))
823
-
824
- sendNode({
825
- tag: 'ib',
826
- attrs: {},
827
- content: [{ tag: 'offline_batch', attrs: { count: '100' } }]
828
- })
829
- })
830
-
831
- ws.on('CB:ib,,edge_routing', (node) => {
832
- const edgeRoutingNode = WABinary_1.getBinaryNodeChild(node, 'edge_routing')
833
- const routingInfo = WABinary_1.getBinaryNodeChild(edgeRoutingNode, 'routing_info')
834
-
835
- if (routingInfo?.content) {
836
- authState.creds.routingInfo = Buffer.from(routingInfo?.content)
837
- ev.emit('creds.update', authState.creds)
838
- }
839
- })
840
-
841
- let didStartBuffer = false
842
-
843
- process.nextTick(() => {
844
- if (creds.me?.id) {
845
- // start buffering important events
846
- // if we're logged in
847
- ev.buffer()
848
- didStartBuffer = true
849
- }
850
-
851
- ev.emit('connection.update', { connection: 'connecting', receivedPendingNotifications: false, qr: undefined })
852
- })
853
-
854
- // called when all offline notifs are handled
855
- ws.on('CB:ib,,offline', (node) => {
856
- const child = WABinary_1.getBinaryNodeChild(node, 'offline')
857
- const offlineNotifs = +(child?.attrs.count || 0)
858
-
859
- logger.info(`handled ${offlineNotifs} offline messages/notifications`)
860
-
861
- if (didStartBuffer) {
862
- ev.flush()
863
- logger.trace('flushed events for initial buffer')
864
- }
865
-
866
- ev.emit('connection.update', { receivedPendingNotifications: true })
867
- })
868
-
869
- // update credentials when required
870
- ev.on('creds.update', update => {
871
- const name = update.me?.name
872
-
873
- // if name has just been received
874
- if (creds.me?.name !== name) {
875
- logger.debug({ name }, 'updated pushName')
876
-
877
- sendNode({
878
- tag: 'presence',
879
- attrs: { name }
880
- }).catch(err => {
881
- logger.warn({ trace: err.stack }, 'error in sending presence update on name change')
882
- })
883
- }
884
-
885
- Object.assign(creds, update)
886
- })
887
-
888
- if (printQRInTerminal) {
889
- Utils_1.printQRIfNecessaryListener(ev, logger)
890
- }
891
-
892
- return {
893
- type: 'md',
894
- ws,
895
- ev,
896
- authState: { creds, keys },
897
- signalRepository,
898
- get user() {
899
- return authState.creds.me
900
- },
901
- generateMessageTag,
902
- query,
903
- waitForMessage,
904
- waitForSocketOpen,
905
- sendRawMessage,
906
- sendNode,
907
- logout,
908
- end,
909
- onUnexpectedError,
910
- uploadPreKeys,
911
- uploadPreKeysToServerIfRequired,
912
- requestPairingCode,
913
- /** Waits for the connection to WA to reach a state */
914
- waitForConnectionUpdate: Utils_1.bindWaitForConnectionUpdate(ev),
915
- sendWAMBuffer,
916
- executeUSyncQuery,
917
- onWhatsApp,
918
- logger
919
- }
920
- }
921
-
922
- /**
923
- * map the websocket error to the right type
924
- * so it can be retried by the caller
925
- * */
926
- function mapWebSocketError(handler) {
927
- return (error) => {
928
- handler(new boom_1.Boom(`WebSocket Error (${error?.message})`, { statusCode: Utils_1.getCodeFromWSError(error), data: error }))
929
- }
930
- }
931
-
932
- module.exports = {
933
- makeSocket
934
- }