@hansaka02/baileys 7.3.2 → 7.3.6

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 (210) hide show
  1. package/lib/Defaults/baileys-version.json +2 -2
  2. package/lib/Defaults/connection.js +51 -0
  3. package/lib/Defaults/constants.js +74 -0
  4. package/lib/Defaults/history.js +19 -0
  5. package/lib/Defaults/index.js +36 -142
  6. package/lib/Defaults/media.js +48 -0
  7. package/lib/Defaults/prefix.js +18 -0
  8. package/lib/Signal/Group/group-session-builder.js +10 -42
  9. package/lib/Signal/Group/group_cipher.js +9 -6
  10. package/lib/Signal/Group/index.js +39 -53
  11. package/lib/Signal/Group/keyhelper.js +8 -41
  12. package/lib/Signal/Group/sender-chain-key.js +5 -18
  13. package/lib/Signal/Group/sender-key-distribution-message.js +7 -7
  14. package/lib/Signal/Group/sender-key-message.js +12 -8
  15. package/lib/Signal/Group/sender-key-record.js +7 -16
  16. package/lib/Signal/Group/sender-key-state.js +15 -61
  17. package/lib/Signal/Group/sender-message-key.js +2 -2
  18. package/lib/Signal/libsignal.js +237 -177
  19. package/lib/Signal/lid-mapping.js +128 -71
  20. package/lib/Socket/Client/types.js +2 -2
  21. package/lib/Socket/Client/websocket.js +25 -16
  22. package/lib/Socket/business.js +46 -33
  23. package/lib/Socket/chats.js +286 -170
  24. package/lib/Socket/community.js +215 -77
  25. package/lib/Socket/groups.js +77 -61
  26. package/lib/Socket/index.js +4 -4
  27. package/lib/Socket/messages-recv.js +629 -457
  28. package/lib/Socket/messages-send.js +645 -656
  29. package/lib/Socket/mex.js +61 -0
  30. package/lib/Socket/newsletter.js +166 -245
  31. package/lib/Socket/socket.js +396 -170
  32. package/lib/Store/index.js +27 -11
  33. package/lib/Store/make-cache-manager-store.js +14 -15
  34. package/lib/Store/make-in-memory-store.js +28 -24
  35. package/lib/Types/LabelAssociation.js +2 -2
  36. package/lib/Types/Message.js +6 -6
  37. package/lib/Types/MexUpdates.js +5 -5
  38. package/lib/Types/Newsletter.js +32 -25
  39. package/lib/Types/State.js +4 -4
  40. package/lib/Types/index.js +28 -12
  41. package/lib/Utils/auth-utils.js +212 -375
  42. package/lib/Utils/baileys-event-stream.js +68 -69
  43. package/lib/Utils/browser-utils.js +43 -0
  44. package/lib/Utils/business.js +63 -53
  45. package/lib/Utils/chat-utils.js +241 -106
  46. package/lib/Utils/crypto.js +25 -45
  47. package/lib/Utils/decode-wa-message.js +361 -311
  48. package/lib/Utils/event-buffer.js +97 -42
  49. package/lib/Utils/generics.js +90 -207
  50. package/lib/Utils/history.js +29 -27
  51. package/lib/Utils/index.js +28 -14
  52. package/lib/Utils/link-preview.js +24 -62
  53. package/lib/Utils/logger.js +5 -5
  54. package/lib/Utils/lt-hash.js +29 -23
  55. package/lib/Utils/make-mutex.js +26 -28
  56. package/lib/Utils/message-retry-manager.js +55 -7
  57. package/lib/Utils/messages-media.js +434 -247
  58. package/lib/Utils/messages.js +963 -917
  59. package/lib/Utils/noise-handler.js +60 -20
  60. package/lib/Utils/pre-key-manager.js +126 -0
  61. package/lib/Utils/process-message.js +216 -141
  62. package/lib/Utils/signal.js +75 -37
  63. package/lib/Utils/use-multi-file-auth-state.js +18 -22
  64. package/lib/Utils/validate-connection.js +96 -66
  65. package/lib/WABinary/constants.js +1268 -1268
  66. package/lib/WABinary/decode.js +62 -34
  67. package/lib/WABinary/encode.js +57 -36
  68. package/lib/WABinary/generic-utils.js +4 -4
  69. package/lib/WABinary/index.js +27 -11
  70. package/lib/WABinary/jid-utils.js +58 -11
  71. package/lib/WAM/constants.js +19064 -11563
  72. package/lib/WAM/encode.js +71 -14
  73. package/lib/WAM/index.js +27 -11
  74. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +20 -16
  75. package/lib/WAUSync/Protocols/USyncContactProtocol.js +2 -2
  76. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +7 -4
  77. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +2 -2
  78. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +0 -2
  79. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +2 -2
  80. package/lib/WAUSync/Protocols/index.js +27 -11
  81. package/lib/WAUSync/USyncQuery.js +51 -28
  82. package/lib/WAUSync/index.js +27 -11
  83. package/lib/index.js +60 -31
  84. package/package.json +12 -17
  85. package/WAProto/AICommon/AICommon.d.ts +0 -11702
  86. package/WAProto/Adv/Adv.d.ts +0 -643
  87. package/WAProto/BotMetadata/BotMetadata.d.ts +0 -5654
  88. package/WAProto/Cert/Cert.d.ts +0 -613
  89. package/WAProto/ChatLockSettings/ChatLockSettings.d.ts +0 -476
  90. package/WAProto/CompanionReg/CompanionReg.d.ts +0 -1361
  91. package/WAProto/DeviceCapabilities/DeviceCapabilities.d.ts +0 -577
  92. package/WAProto/E2E/E2E.d.ts +0 -41724
  93. package/WAProto/Ephemeral/Ephemeral.d.ts +0 -114
  94. package/WAProto/HistorySync/HistorySync.d.ts +0 -51700
  95. package/WAProto/LidMigrationSyncPayload/LidMigrationSyncPayload.d.ts +0 -229
  96. package/WAProto/MdStorageChatRowOpaqueData/MdStorageChatRowOpaqueData.d.ts +0 -583
  97. package/WAProto/MdStorageMsgRowOpaqueData/MdStorageMsgRowOpaqueData.d.ts +0 -42897
  98. package/WAProto/MmsRetry/MmsRetry.d.ts +0 -243
  99. package/WAProto/Protocol/Protocol.d.ts +0 -270
  100. package/WAProto/Reporting/Reporting.d.ts +0 -371
  101. package/WAProto/ServerSync/ServerSync.d.ts +0 -1285
  102. package/WAProto/SignalLocalStorageProtocol/SignalLocalStorageProtocol.d.ts +0 -1868
  103. package/WAProto/SignalWhisperTextProtocol/SignalWhisperTextProtocol.d.ts +0 -767
  104. package/WAProto/StatusAttributions/StatusAttributions.d.ts +0 -1027
  105. package/WAProto/SyncAction/SyncAction.d.ts +0 -11193
  106. package/WAProto/UserPassword/UserPassword.d.ts +0 -363
  107. package/WAProto/VnameCert/VnameCert.d.ts +0 -821
  108. package/WAProto/Wa6/Wa6.d.ts +0 -2128
  109. package/WAProto/Web/Web.d.ts +0 -46383
  110. package/WAProto/index.d.ts +0 -55
  111. package/lib/Defaults/index.d.ts +0 -77
  112. package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
  113. package/lib/Signal/Group/group-session-builder.d.ts +0 -17
  114. package/lib/Signal/Group/group_cipher.d.ts +0 -19
  115. package/lib/Signal/Group/index.d.ts +0 -11
  116. package/lib/Signal/Group/keyhelper.d.ts +0 -16
  117. package/lib/Signal/Group/sender-chain-key.d.ts +0 -14
  118. package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -17
  119. package/lib/Signal/Group/sender-key-message.d.ts +0 -19
  120. package/lib/Signal/Group/sender-key-name.d.ts +0 -19
  121. package/lib/Signal/Group/sender-key-record.d.ts +0 -32
  122. package/lib/Signal/Group/sender-key-state.d.ts +0 -44
  123. package/lib/Signal/Group/sender-message-key.d.ts +0 -11
  124. package/lib/Signal/libsignal.d.ts +0 -8
  125. package/lib/Signal/lid-mapping.d.ts +0 -28
  126. package/lib/Socket/Client/index.d.ts +0 -2
  127. package/lib/Socket/Client/types.d.ts +0 -16
  128. package/lib/Socket/Client/websocket.d.ts +0 -13
  129. package/lib/Socket/business.d.ts +0 -187
  130. package/lib/Socket/chats.d.ts +0 -97
  131. package/lib/Socket/community.d.ts +0 -129
  132. package/lib/Socket/groups.d.ts +0 -129
  133. package/lib/Socket/index.d.ts +0 -191
  134. package/lib/Socket/messages-recv.d.ts +0 -174
  135. package/lib/Socket/messages-send.d.ts +0 -165
  136. package/lib/Socket/newsletter.d.ts +0 -145
  137. package/lib/Socket/socket.d.ts +0 -45
  138. package/lib/Socket/usync.d.ts +0 -37
  139. package/lib/Socket/usync.js +0 -83
  140. package/lib/Store/index.d.ts +0 -4
  141. package/lib/Store/make-cache-manager-store.d.ts +0 -14
  142. package/lib/Store/make-in-memory-store.d.ts +0 -123
  143. package/lib/Store/make-ordered-dictionary.d.ts +0 -12
  144. package/lib/Store/object-repository.d.ts +0 -10
  145. package/lib/Types/Auth.d.ts +0 -121
  146. package/lib/Types/Bussiness.d.ts +0 -28
  147. package/lib/Types/Call.d.ts +0 -14
  148. package/lib/Types/Chat.d.ts +0 -143
  149. package/lib/Types/Contact.d.ts +0 -23
  150. package/lib/Types/Events.d.ts +0 -226
  151. package/lib/Types/GroupMetadata.d.ts +0 -66
  152. package/lib/Types/Label.d.ts +0 -48
  153. package/lib/Types/LabelAssociation.d.ts +0 -35
  154. package/lib/Types/Message.d.ts +0 -484
  155. package/lib/Types/MexUpdates.d.ts +0 -9
  156. package/lib/Types/Newsletter.d.ts +0 -109
  157. package/lib/Types/Product.d.ts +0 -92
  158. package/lib/Types/Signal.d.ts +0 -98
  159. package/lib/Types/Socket.d.ts +0 -141
  160. package/lib/Types/State.d.ts +0 -41
  161. package/lib/Types/USync.d.ts +0 -26
  162. package/lib/Types/index.d.ts +0 -80
  163. package/lib/Utils/auth-utils.d.ts +0 -21
  164. package/lib/Utils/baileys-event-stream.d.ts +0 -18
  165. package/lib/Utils/business.d.ts +0 -29
  166. package/lib/Utils/chat-utils.d.ts +0 -82
  167. package/lib/Utils/crypto.d.ts +0 -56
  168. package/lib/Utils/decode-wa-message.d.ts +0 -53
  169. package/lib/Utils/event-buffer.d.ts +0 -39
  170. package/lib/Utils/generics.d.ts +0 -117
  171. package/lib/Utils/history.d.ts +0 -23
  172. package/lib/Utils/index.d.ts +0 -20
  173. package/lib/Utils/link-preview.d.ts +0 -23
  174. package/lib/Utils/logger.d.ts +0 -13
  175. package/lib/Utils/lt-hash.d.ts +0 -14
  176. package/lib/Utils/make-mutex.d.ts +0 -9
  177. package/lib/Utils/message-retry-manager.d.ts +0 -88
  178. package/lib/Utils/messages-media.d.ts +0 -135
  179. package/lib/Utils/messages.d.ts +0 -105
  180. package/lib/Utils/noise-handler.d.ts +0 -20
  181. package/lib/Utils/process-message.d.ts +0 -49
  182. package/lib/Utils/signal.d.ts +0 -42
  183. package/lib/Utils/use-mongo-file-auth-state.d.ts +0 -6
  184. package/lib/Utils/use-mongo-file-auth-state.js +0 -84
  185. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
  186. package/lib/Utils/use-single-file-auth-state.d.ts +0 -13
  187. package/lib/Utils/use-single-file-auth-state.js +0 -80
  188. package/lib/Utils/validate-connection.d.ts +0 -13
  189. package/lib/WABinary/constants.d.ts +0 -30
  190. package/lib/WABinary/decode.d.ts +0 -9
  191. package/lib/WABinary/encode.d.ts +0 -3
  192. package/lib/WABinary/generic-utils.d.ts +0 -28
  193. package/lib/WABinary/index.d.ts +0 -5
  194. package/lib/WABinary/jid-utils.d.ts +0 -58
  195. package/lib/WABinary/types.d.ts +0 -22
  196. package/lib/WAM/BinaryInfo.d.ts +0 -16
  197. package/lib/WAM/constants.d.ts +0 -47
  198. package/lib/WAM/encode.d.ts +0 -3
  199. package/lib/WAM/index.d.ts +0 -3
  200. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.d.ts +0 -28
  201. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -10
  202. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -26
  203. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -14
  204. package/lib/WAUSync/Protocols/USyncLIDProtocol.d.ts +0 -10
  205. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -14
  206. package/lib/WAUSync/Protocols/index.d.ts +0 -6
  207. package/lib/WAUSync/USyncQuery.d.ts +0 -31
  208. package/lib/WAUSync/USyncUser.d.ts +0 -12
  209. package/lib/WAUSync/index.d.ts +0 -3
  210. package/lib/index.d.ts +0 -13
@@ -2,17 +2,62 @@
2
2
 
3
3
  Object.defineProperty(exports, "__esModule", { value: true })
4
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")
5
+ const { Boom } = require("@hapi/boom")
6
+ const { randomBytes } = require("crypto")
7
+ const { URL } = require("url")
8
+ const { promisify } = require("util")
9
+ const { proto } = require("../../WAProto")
10
+ const {
11
+ DEF_TAG_PREFIX,
12
+ DEF_CALLBACK_PREFIX
13
+ } = require("../Defaults/prefix")
14
+ const {
15
+ NOISE_WA_HEADER,
16
+ INITIAL_PREKEY_COUNT,
17
+ MIN_UPLOAD_INTERVAL,
18
+ MIN_PREKEY_COUNT,
19
+ UPLOAD_TIMEOUT
20
+ } = require("../Defaults/constants")
21
+ const { DisconnectReason } = require("../Types")
22
+ const {
23
+ addTransactionCapability,
24
+ aesEncryptCTR,
25
+ printQRIfNecessaryListener,
26
+ bindWaitForConnectionUpdate,
27
+ bytesToCrockford,
28
+ configureSuccessfulPairing,
29
+ Curve,
30
+ derivePairingCodeKey,
31
+ generateLoginNode,
32
+ generateMdTagPrefix,
33
+ generateRegistrationNode,
34
+ getCodeFromWSError,
35
+ getErrorCodeFromStreamError,
36
+ getNextPreKeysNode,
37
+ getPlatformId,
38
+ makeEventBuffer,
39
+ makeNoiseHandler,
40
+ promiseTimeout,
41
+ asciiDecode
42
+ } = require("../Utils")
43
+ const {
44
+ assertNodeErrorFree,
45
+ binaryNodeToString,
46
+ encodeBinaryNode,
47
+ getBinaryNodeChild,
48
+ getBinaryNodeChildren,
49
+ getAllBinaryNodeChildren,
50
+ isLidUser,
51
+ jidDecode,
52
+ jidEncode,
53
+ S_WHATSAPP_NET
54
+ } = require("../WABinary")
55
+ const { BinaryInfo } = require("../WAM")
56
+ const {
57
+ USyncUser,
58
+ USyncQuery
59
+ } = require("../WAUSync")
60
+ const { WebSocketClient } = require("./Client")
16
61
 
17
62
  /**
18
63
  * Connects to WA servers and performs:
@@ -21,21 +66,80 @@ const WAUSync_1 = require("../WAUSync")
21
66
  * - query phone connection
22
67
  */
23
68
  const makeSocket = (config) => {
24
- const { waWebSocketUrl, connectTimeoutMs, logger, keepAliveIntervalMs, browser, auth: authState, printQRInTerminal, defaultQueryTimeoutMs, transactionOpts, qrTimeout, makeSignalRepository } = config
69
+ const {
70
+ waWebSocketUrl,
71
+ connectTimeoutMs,
72
+ logger,
73
+ keepAliveIntervalMs,
74
+ browser,
75
+ auth: authState,
76
+ printQRInTerminal,
77
+ defaultQueryTimeoutMs,
78
+ transactionOpts,
79
+ qrTimeout,
80
+ makeSignalRepository
81
+ } = config
25
82
 
26
- const uqTagId = Utils_1.generateMdTagPrefix()
83
+ const uqTagId = generateMdTagPrefix()
27
84
  const generateMessageTag = () => `${uqTagId}${epoch++}`
28
-
29
- const url = typeof waWebSocketUrl === 'string' ? new url_1.URL(waWebSocketUrl) : waWebSocketUrl
85
+ const publicWAMBuffer = new BinaryInfo()
86
+ const url = typeof waWebSocketUrl === 'string' ? new URL(waWebSocketUrl) : waWebSocketUrl
30
87
 
31
88
  if (config.mobile || url.protocol === 'tcp:') {
32
- throw new boom_1.Boom('Mobile API is not supported anymore', { statusCode: Types_1.DisconnectReason.loggedOut })
89
+ throw new Boom('Mobile API is not supported anymore', { statusCode: DisconnectReason.loggedOut })
33
90
  }
34
91
 
35
92
  if (url.protocol === 'wss' && authState?.creds?.routingInfo) {
36
93
  url.searchParams.append('ED', authState.creds.routingInfo.toString('base64url'))
37
94
  }
38
95
 
96
+ /** ephemeral key pair used to encrypt/decrypt communication. Unique for each connection */
97
+ const ephemeralKeyPair = Curve.generateKeyPair()
98
+
99
+ /** WA noise protocol wrapper */
100
+ const noise = makeNoiseHandler({
101
+ keyPair: ephemeralKeyPair,
102
+ NOISE_HEADER: NOISE_WA_HEADER,
103
+ logger,
104
+ routingInfo: authState?.creds?.routingInfo
105
+ })
106
+
107
+ const ws = new WebSocketClient(url, config)
108
+
109
+ ws.connect()
110
+
111
+ const sendPromise = promisify(ws.send)
112
+
113
+ /** send a raw buffer */
114
+ const sendRawMessage = async (data) => {
115
+ if (!ws.isOpen) {
116
+ throw new Boom('Connection Closed', { statusCode: DisconnectReason.connectionClosed })
117
+ }
118
+
119
+ const bytes = noise.encodeFrame(data)
120
+
121
+ await promiseTimeout(connectTimeoutMs, async (resolve, reject) => {
122
+ try {
123
+ await sendPromise.call(ws, bytes)
124
+ resolve()
125
+ }
126
+ catch (error) {
127
+ reject(error)
128
+ }
129
+ })
130
+ }
131
+
132
+ /** send a binary node */
133
+ const sendNode = (frame) => {
134
+ if (logger.level === 'trace') {
135
+ logger.trace({ xml: binaryNodeToString(frame), msg: 'xml send' })
136
+ }
137
+
138
+ const buff = encodeBinaryNode(frame)
139
+
140
+ return sendRawMessage(buff)
141
+ }
142
+
39
143
  /**
40
144
  * Wait for a message with a certain tag to be received
41
145
  * @param msgId the message tag to await
@@ -44,22 +148,47 @@ const makeSocket = (config) => {
44
148
  const waitForMessage = async (msgId, timeoutMs = defaultQueryTimeoutMs) => {
45
149
  let onRecv
46
150
  let onErr
151
+
47
152
  try {
48
- return await Utils_1.promiseTimeout(timeoutMs, (resolve, reject) => {
49
- onRecv = resolve
153
+ const result = await promiseTimeout(timeoutMs, (resolve, reject) => {
154
+ onRecv = data => {
155
+ resolve(data)
156
+ }
157
+
50
158
  onErr = err => {
51
- reject(err || new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed }))
159
+ reject(err ||
160
+ new Boom('Connection Closed', {
161
+ statusCode: DisconnectReason.connectionClosed
162
+ }))
52
163
  }
164
+
53
165
  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)
166
+ ws.on('close', onErr)
167
+ ws.on('error', onErr)
168
+
169
+ return () => reject(new Boom('Query Cancelled'))
56
170
  })
171
+
172
+ return result
173
+ }
174
+
175
+ catch (error) {
176
+ // Catch timeout and return undefined instead of throwing
177
+ if (error instanceof Boom && error.output?.statusCode === DisconnectReason.timedOut) {
178
+ logger?.warn?.({ msgId }, 'timed out waiting for message')
179
+ return undefined
180
+ }
181
+
182
+ throw error
57
183
  }
58
184
 
59
185
  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)
186
+ if (onRecv)
187
+ ws.off(`TAG:${msgId}`, onRecv)
188
+ if (onErr) {
189
+ ws.off('close', onErr)
190
+ ws.off('error', onErr)
191
+ }
63
192
  }
64
193
  }
65
194
 
@@ -70,22 +199,60 @@ const makeSocket = (config) => {
70
199
  }
71
200
 
72
201
  const msgId = node.attrs.id
73
- const wait = waitForMessage(msgId, timeoutMs)
202
+ const result = await promiseTimeout(timeoutMs, async (resolve, reject) => {
203
+ const result = waitForMessage(msgId, timeoutMs).catch(reject)
204
+ sendNode(node)
205
+ .then(async () => resolve(await result))
206
+ .catch(reject)
207
+ })
74
208
 
75
- await sendNode(node)
209
+ if (result && 'tag' in result) {
210
+ assertNodeErrorFree(result)
211
+ }
212
+
213
+ return result
214
+ }
215
+
216
+ // Validate current key-bundle on server; on failure, trigger pre-key upload and rethrow
217
+ const digestKeyBundle = async () => {
218
+ const res = await query({
219
+ tag: 'iq',
220
+ attrs: { to: S_WHATSAPP_NET, type: 'get', xmlns: 'encrypt' },
221
+ content: [{ tag: 'digest', attrs: {} }]
222
+ })
76
223
 
77
- const result = await wait
224
+ const digestNode = getBinaryNodeChild(res, 'digest')
78
225
 
79
- if ('tag' in result) {
80
- WABinary_1.assertNodeErrorFree(result)
226
+ if (!digestNode) {
227
+ await uploadPreKeys()
228
+ throw new Error('encrypt/get digest returned no digest node')
81
229
  }
230
+ }
231
+
232
+ // Rotate our signed pre-key on server; on failure, run digest as fallback and rethrow
233
+ const rotateSignedPreKey = async () => {
234
+ const newId = (creds.signedPreKey.keyId || 0) + 1
235
+ const skey = await signedKeyPair(creds.signedIdentityKey, newId)
82
236
 
83
- return result
237
+ await query({
238
+ tag: 'iq',
239
+ attrs: { to: S_WHATSAPP_NET, type: 'set', xmlns: 'encrypt' },
240
+ content: [
241
+ {
242
+ tag: 'rotate',
243
+ attrs: {},
244
+ content: [xmppSignedPreKey(skey)]
245
+ }
246
+ ]
247
+ })
248
+
249
+ // Persist new signed pre-key in creds
250
+ ev.emit('creds.update', { signedPreKey: skey })
84
251
  }
85
252
 
86
253
  const executeUSyncQuery = async (usyncQuery) => {
87
254
  if (usyncQuery.protocols.length === 0) {
88
- throw new boom_1.Boom('USyncQuery must have at least one protocol');
255
+ throw new Boom('USyncQuery must have at least one protocol')
89
256
  }
90
257
 
91
258
  // todo: validate users, throw WARNING on no valid users
@@ -116,7 +283,7 @@ const makeSocket = (config) => {
116
283
  const iq = {
117
284
  tag: 'iq',
118
285
  attrs: {
119
- to: WABinary_1._WHATSAPP_NET,
286
+ to: S_WHATSAPP_NET,
120
287
  type: 'get',
121
288
  xmlns: 'usync'
122
289
  },
@@ -136,53 +303,74 @@ const makeSocket = (config) => {
136
303
  }
137
304
 
138
305
  const result = await query(iq)
306
+
139
307
  return usyncQuery.parseUSyncQueryResult(result)
140
308
  }
141
309
 
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
310
+ const onWhatsApp = async (...phoneNumber) => {
311
+ let usyncQuery = new USyncQuery()
312
+ let contactEnabled = false
313
+
314
+ for (const jid of phoneNumber) {
315
+ if (isLidUser(jid)) {
316
+ logger?.warn('LIDs are not supported with onWhatsApp')
317
+ continue
147
318
  }
319
+
148
320
  else {
321
+ if (!contactEnabled) {
322
+ contactEnabled = true
323
+ usyncQuery = usyncQuery.withContactProtocol()
324
+ }
325
+
149
326
  const phone = `+${jid.replace('+', '').split('@')[0]?.split(':')[0]}`
150
- usyncQuery.withUser(new WAUSync_1.USyncUser().withPhone(phone))
327
+ usyncQuery.withUser(new USyncUser().withPhone(phone))
151
328
  }
152
329
  }
330
+
331
+ if (usyncQuery.users.length === 0) {
332
+ return [] // return early without forcing an empty query
333
+ }
334
+
153
335
  const results = await executeUSyncQuery(usyncQuery)
336
+
154
337
  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 }))
338
+ return results.list.filter(a => !!a.contact).map(({ contact, id }) => ({ jid: id, exists: contact }))
162
339
  }
163
340
  }
164
341
 
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
- })
342
+ const pnFromLIDUSync = async (jids) => {
343
+ const usyncQuery = new USyncQuery().withLIDProtocol().withContext('background')
344
+ for (const jid of jids) {
345
+ if (isLidUser(jid)) {
346
+ logger?.warn('LID user found in LID fetch call')
347
+ continue
348
+ }
349
+
350
+ else {
351
+ usyncQuery.withUser(new USyncUser().withId(jid))
352
+ }
353
+ }
354
+
355
+ if (usyncQuery.users.length === 0) {
356
+ return [] // return early without forcing an empty query
357
+ }
358
+
359
+ const results = await executeUSyncQuery(usyncQuery)
360
+
361
+ if (results) {
362
+ return results.list.filter(a => !!a.lid).map(({ lid, id }) => ({ pn: id, lid: lid }))
363
+ }
364
+
365
+ return []
366
+ }
180
367
 
368
+ const ev = makeEventBuffer(logger)
181
369
  const { creds } = authState
182
370
 
183
371
  // add transaction capability
184
- const keys = Utils_1.addTransactionCapability(authState.keys, logger, transactionOpts)
185
- const signalRepository = makeSignalRepository({ creds, keys }, onWhatsApp, logger)
372
+ const keys = addTransactionCapability(authState.keys, logger, transactionOpts)
373
+ const signalRepository = makeSignalRepository({ creds, keys }, logger, pnFromLIDUSync)
186
374
 
187
375
  let lastDateRecv
188
376
  let epoch = 1
@@ -190,37 +378,6 @@ const makeSocket = (config) => {
190
378
  let qrTimer
191
379
  let closed = false
192
380
 
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
381
  /** log & process any unexpected errors */
225
382
  const onUnexpectedError = (err, msg) => {
226
383
  logger.error({ err }, `unexpected error in '${msg}'`)
@@ -229,17 +386,18 @@ const makeSocket = (config) => {
229
386
  /** await the next incoming message */
230
387
  const awaitNextMessage = async (sendMsg) => {
231
388
  if (!ws.isOpen) {
232
- throw new boom_1.Boom('Connection Closed', {
233
- statusCode: Types_1.DisconnectReason.connectionClosed
389
+ throw new Boom('Connection Closed', {
390
+ statusCode: DisconnectReason.connectionClosed
234
391
  })
235
392
  }
236
393
 
237
394
  let onOpen
238
395
  let onClose
239
396
 
240
- const result = Utils_1.promiseTimeout(connectTimeoutMs, (resolve, reject) => {
397
+ const result = promiseTimeout(connectTimeoutMs, (resolve, reject) => {
241
398
  onOpen = resolve
242
399
  onClose = mapWebSocketError(reject)
400
+
243
401
  ws.on('frame', onOpen)
244
402
  ws.on('close', onClose)
245
403
  ws.on('error', onClose)
@@ -262,36 +420,41 @@ const makeSocket = (config) => {
262
420
  clientHello: { ephemeral: ephemeralKeyPair.public }
263
421
  }
264
422
 
265
- helloMsg = WAProto_1.proto.HandshakeMessage.fromObject(helloMsg)
423
+ helloMsg = proto.HandshakeMessage.fromObject(helloMsg)
424
+
266
425
  logger.info({ browser, helloMsg }, 'connected to WA')
267
426
 
268
- const init = WAProto_1.proto.HandshakeMessage.encode(helloMsg).finish()
427
+ const init = proto.HandshakeMessage.encode(helloMsg).finish()
269
428
  const result = await awaitNextMessage(init)
270
- const handshake = WAProto_1.proto.HandshakeMessage.decode(result)
429
+ const handshake = proto.HandshakeMessage.decode(result)
271
430
 
272
431
  logger.trace({ handshake }, 'handshake recv from WA')
273
432
 
274
433
  const keyEnc = await noise.processHandshake(handshake, creds.noiseKey)
434
+
275
435
  let node
276
436
 
277
437
  if (!creds.me) {
278
- node = Utils_1.generateRegistrationNode(creds, config)
438
+ node = generateRegistrationNode(creds, config)
279
439
  logger.info({ node }, 'not logged in, attempting registration...')
280
440
  }
281
441
 
282
442
  else {
283
- node = Utils_1.generateLoginNode(creds.me.id, config)
443
+ node = generateLoginNode(creds.me.id, config)
284
444
  logger.info({ node }, 'logging in...')
285
445
  }
286
- const payloadEnc = noise.encrypt(WAProto_1.proto.ClientPayload.encode(node).finish())
287
446
 
288
- await sendRawMessage(WAProto_1.proto.HandshakeMessage.encode({
447
+ const payloadEnc = noise.encrypt(proto.ClientPayload.encode(node).finish())
448
+
449
+ await sendRawMessage(proto.HandshakeMessage.encode({
289
450
  clientFinish: {
290
451
  static: keyEnc,
291
- payload: payloadEnc,
292
- },
452
+ payload: payloadEnc
453
+ }
293
454
  }).finish())
294
- noise.finishInit()
455
+
456
+ await noise.finishInit()
457
+
295
458
  startKeepAliveRequest()
296
459
  }
297
460
 
@@ -302,14 +465,14 @@ const makeSocket = (config) => {
302
465
  id: generateMessageTag(),
303
466
  xmlns: 'encrypt',
304
467
  type: 'get',
305
- to: WABinary_1.S_WHATSAPP_NET
468
+ to: S_WHATSAPP_NET
306
469
  },
307
470
  content: [
308
471
  { tag: 'count', attrs: {} }
309
472
  ]
310
473
  })
311
474
 
312
- const countChild = WABinary_1.getBinaryNodeChild(result, 'count')
475
+ const countChild = getBinaryNodeChild(result, 'count')
313
476
 
314
477
  return +countChild.attrs.value
315
478
  }
@@ -319,11 +482,12 @@ const makeSocket = (config) => {
319
482
  let lastUploadTime = 0
320
483
 
321
484
  /** generates and uploads a set of pre-keys to the server */
322
- const uploadPreKeys = async (count = Defaults_1.INITIAL_PREKEY_COUNT, retryCount = 0) => {
485
+ const uploadPreKeys = async (count = MIN_PREKEY_COUNT, retryCount = 0) => {
323
486
  // Check minimum interval (except for retries)
324
487
  if (retryCount === 0) {
325
488
  const timeSinceLastUpload = Date.now() - lastUploadTime
326
- if (timeSinceLastUpload < Defaults_1.MIN_UPLOAD_INTERVAL) {
489
+
490
+ if (timeSinceLastUpload < MIN_UPLOAD_INTERVAL) {
327
491
  logger.debug(`Skipping upload, only ${timeSinceLastUpload}ms since last upload`)
328
492
  return
329
493
  }
@@ -332,7 +496,7 @@ const makeSocket = (config) => {
332
496
  // Prevent multiple concurrent uploads
333
497
  if (uploadPreKeysPromise) {
334
498
  logger.debug('Pre-key upload already in progress, waiting for completion')
335
- return uploadPreKeysPromise
499
+ await uploadPreKeysPromise
336
500
  }
337
501
 
338
502
  const uploadLogic = async () => {
@@ -341,7 +505,8 @@ const makeSocket = (config) => {
341
505
  // Generate and save pre-keys atomically (prevents ID collisions on retry)
342
506
  const node = await keys.transaction(async () => {
343
507
  logger.debug({ requestedCount: count }, 'generating pre-keys with requested count')
344
- const { update, node } = await Utils_1.getNextPreKeysNode({ creds, keys }, count)
508
+
509
+ const { update, node } = await getNextPreKeysNode({ creds, keys }, count)
345
510
 
346
511
  // Update credentials immediately to prevent duplicate IDs on retry
347
512
  ev.emit('creds.update', update)
@@ -355,15 +520,21 @@ const makeSocket = (config) => {
355
520
  logger.info({ count }, 'uploaded pre-keys successfully')
356
521
  lastUploadTime = Date.now()
357
522
  }
523
+
358
524
  catch (uploadError) {
359
- logger.error({ uploadError, count }, 'Failed to upload pre-keys to server')
525
+ logger.error({ uploadError: uploadError.toString(), count }, 'Failed to upload pre-keys to server')
526
+
360
527
  // Exponential backoff retry (max 3 retries)
361
528
  if (retryCount < 3) {
362
529
  const backoffDelay = Math.min(1000 * Math.pow(2, retryCount), 10000)
530
+
363
531
  logger.info(`Retrying pre-key upload in ${backoffDelay}ms`)
532
+
364
533
  await new Promise(resolve => setTimeout(resolve, backoffDelay))
534
+
365
535
  return uploadPreKeys(count, retryCount + 1)
366
536
  }
537
+
367
538
  throw uploadError
368
539
  }
369
540
  }
@@ -371,11 +542,13 @@ const makeSocket = (config) => {
371
542
  // Add timeout protection
372
543
  uploadPreKeysPromise = Promise.race([
373
544
  uploadLogic(),
374
- new Promise((_, reject) => setTimeout(() => reject(new boom_1.Boom('Pre-key upload timeout', { statusCode: 408 })), Defaults_1.UPLOAD_TIMEOUT))
545
+ new Promise((_, reject) => setTimeout(() => reject(new Boom('Pre-key upload timeout', { statusCode: 408 })), UPLOAD_TIMEOUT))
375
546
  ])
547
+
376
548
  try {
377
549
  await uploadPreKeysPromise
378
550
  }
551
+
379
552
  finally {
380
553
  uploadPreKeysPromise = null
381
554
  }
@@ -383,50 +556,69 @@ const makeSocket = (config) => {
383
556
 
384
557
  const verifyCurrentPreKeyExists = async () => {
385
558
  const currentPreKeyId = creds.nextPreKeyId - 1
559
+
386
560
  if (currentPreKeyId <= 0) {
387
561
  return { exists: false, currentPreKeyId: 0 }
388
562
  }
563
+
389
564
  const preKeys = await keys.get('pre-key', [currentPreKeyId.toString()])
390
565
  const exists = !!preKeys[currentPreKeyId.toString()]
566
+
391
567
  return { exists, currentPreKeyId }
392
568
  }
393
569
 
394
570
  const uploadPreKeysToServerIfRequired = async () => {
395
571
  try {
572
+ let count = 0
573
+
396
574
  const preKeyCount = await getAvailablePreKeysOnServer()
575
+
576
+ if (preKeyCount === 0)
577
+ count = INITIAL_PREKEY_COUNT
578
+ else
579
+ count = MIN_PREKEY_COUNT
580
+
397
581
  const { exists: currentPreKeyExists, currentPreKeyId } = await verifyCurrentPreKeyExists()
398
582
 
399
583
  logger.info(`${preKeyCount} pre-keys found on server`)
400
584
  logger.info(`Current prekey ID: ${currentPreKeyId}, exists in storage: ${currentPreKeyExists}`)
401
585
 
402
- const lowServerCount = preKeyCount <= Defaults_1.MIN_PREKEY_COUNT
586
+ const lowServerCount = preKeyCount <= count
403
587
  const missingCurrentPreKey = !currentPreKeyExists && currentPreKeyId > 0
404
588
  const shouldUpload = lowServerCount || missingCurrentPreKey
405
589
 
406
590
  if (shouldUpload) {
407
591
  const reasons = []
592
+
408
593
  if (lowServerCount)
409
594
  reasons.push(`server count low (${preKeyCount})`)
595
+
410
596
  if (missingCurrentPreKey)
411
597
  reasons.push(`current prekey ${currentPreKeyId} missing from storage`)
598
+
412
599
  logger.info(`Uploading PreKeys due to: ${reasons.join(', ')}`)
413
- await uploadPreKeys()
600
+
601
+ await uploadPreKeys(count)
414
602
  }
603
+
415
604
  else {
416
605
  logger.info(`PreKey validation passed - Server: ${preKeyCount}, Current prekey ${currentPreKeyId} exists`)
417
606
  }
418
607
  }
608
+
419
609
  catch (error) {
420
610
  logger.error({ error }, 'Failed to check/upload pre-keys during initialization')
421
611
  // Don't throw - allow connection to continue even if pre-key check fails
422
612
  }
423
613
  }
424
614
 
425
- const onMessageReceived = (data) => {
426
- noise.decodeFrame(data, frame => {
615
+ const onMessageReceived = async (data) => {
616
+ await noise.decodeFrame(data, frame => {
427
617
  // reset ping timeout
428
618
  lastDateRecv = new Date()
619
+
429
620
  let anyTriggered = false
621
+
430
622
  anyTriggered = ws.emit('frame', frame)
431
623
 
432
624
  // if it's a binary node
@@ -434,11 +626,11 @@ const makeSocket = (config) => {
434
626
  const msgId = frame.attrs.id
435
627
 
436
628
  if (logger.level === 'trace') {
437
- logger.trace({ xml: WABinary_1.binaryNodeToString(frame), msg: 'recv xml' })
629
+ logger.trace({ xml: binaryNodeToString(frame), msg: 'recv xml' })
438
630
  }
439
631
 
440
632
  /* Check if this is a response to a message we sent */
441
- anyTriggered = ws.emit(`${Defaults_1.DEF_TAG_PREFIX}${msgId}`, frame) || anyTriggered
633
+ anyTriggered = ws.emit(`${DEF_TAG_PREFIX}${msgId}`, frame) || anyTriggered
442
634
 
443
635
  /* Check if this is a response to a message we are expecting */
444
636
  const l0 = frame.tag
@@ -446,13 +638,13 @@ const makeSocket = (config) => {
446
638
  const l2 = Array.isArray(frame.content) ? frame.content[0]?.tag : ''
447
639
 
448
640
  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
641
+ anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]},${l2}`, frame) || anyTriggered
642
+ anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]}`, frame) || anyTriggered
643
+ anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}`, frame) || anyTriggered
452
644
  }
453
645
 
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
646
+ anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},,${l2}`, frame) || anyTriggered
647
+ anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0}`, frame) || anyTriggered
456
648
 
457
649
  if (!anyTriggered && logger.level === 'debug') {
458
650
  logger.debug({ unhandled: true, msgId, fromMe: false, frame }, 'communication recv')
@@ -470,8 +662,10 @@ const makeSocket = (config) => {
470
662
  closed = true
471
663
 
472
664
  logger.info({ trace: error?.stack }, error ? 'connection errored' : 'connection closed')
665
+
473
666
  clearInterval(keepAliveReq)
474
667
  clearTimeout(qrTimer)
668
+
475
669
  ws.removeAllListeners('close')
476
670
  ws.removeAllListeners('open')
477
671
  ws.removeAllListeners('message')
@@ -480,7 +674,7 @@ const makeSocket = (config) => {
480
674
  try {
481
675
  ws.close()
482
676
  }
483
- catch (_a) { }
677
+ catch { }
484
678
  }
485
679
 
486
680
  ev.emit('connection.update', {
@@ -500,7 +694,7 @@ const makeSocket = (config) => {
500
694
  }
501
695
 
502
696
  if (ws.isClosed || ws.isClosing) {
503
- throw new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed })
697
+ throw new Boom('Connection Closed', { statusCode: DisconnectReason.connectionClosed });
504
698
  }
505
699
 
506
700
  let onOpen
@@ -509,6 +703,7 @@ const makeSocket = (config) => {
509
703
  await new Promise((resolve, reject) => {
510
704
  onOpen = () => resolve(undefined)
511
705
  onClose = mapWebSocketError(reject)
706
+
512
707
  ws.on('open', onOpen)
513
708
  ws.on('close', onClose)
514
709
  ws.on('error', onClose)
@@ -531,7 +726,7 @@ const makeSocket = (config) => {
531
726
  it could be that the network is down
532
727
  */
533
728
  if (diff > keepAliveIntervalMs + 5000) {
534
- end(new boom_1.Boom('Connection was lost', { statusCode: Types_1.DisconnectReason.connectionLost }))
729
+ end(new Boom('Connection was lost', { statusCode: DisconnectReason.connectionLost }))
535
730
  }
536
731
 
537
732
  else if (ws.isOpen) {
@@ -540,7 +735,7 @@ const makeSocket = (config) => {
540
735
  tag: 'iq',
541
736
  attrs: {
542
737
  id: generateMessageTag(),
543
- to: WABinary_1.S_WHATSAPP_NET,
738
+ to: S_WHATSAPP_NET,
544
739
  type: 'get',
545
740
  xmlns: 'w:p',
546
741
  },
@@ -559,7 +754,7 @@ const makeSocket = (config) => {
559
754
  const sendPassiveIq = (tag) => (query({
560
755
  tag: 'iq',
561
756
  attrs: {
562
- to: WABinary_1.S_WHATSAPP_NET,
757
+ to: S_WHATSAPP_NET,
563
758
  xmlns: 'passive',
564
759
  type: 'set',
565
760
  },
@@ -576,7 +771,7 @@ const makeSocket = (config) => {
576
771
  await sendNode({
577
772
  tag: 'iq',
578
773
  attrs: {
579
- to: WABinary_1.S_WHATSAPP_NET,
774
+ to: S_WHATSAPP_NET,
580
775
  type: 'set',
581
776
  id: generateMessageTag(),
582
777
  xmlns: 'md'
@@ -593,14 +788,14 @@ const makeSocket = (config) => {
593
788
  })
594
789
  }
595
790
 
596
- end(new boom_1.Boom(msg || 'Intentional Logout', { statusCode: Types_1.DisconnectReason.loggedOut }))
791
+ end(new Boom(msg || 'Intentional Logout', { statusCode: DisconnectReason.loggedOut }))
597
792
  }
598
793
 
599
794
  const requestPairingCode = async (phoneNumber, code) => {
600
- authState.creds.pairingCode = code?.toUpperCase() || Utils_1.asciiDecode([83, 85, 75, 49, 67, 72, 52, 78])
795
+ authState.creds.pairingCode = code?.toUpperCase() || asciiDecode([83, 85, 75, 49, 67, 72, 52, 78])
601
796
 
602
797
  authState.creds.me = {
603
- id: WABinary_1.jidEncode(phoneNumber, 's.whatsapp.net'),
798
+ id: jidEncode(phoneNumber, 's.whatsapp.net'),
604
799
  name: '~'
605
800
  }
606
801
 
@@ -609,7 +804,7 @@ const makeSocket = (config) => {
609
804
  await sendNode({
610
805
  tag: 'iq',
611
806
  attrs: {
612
- to: WABinary_1.S_WHATSAPP_NET,
807
+ to: S_WHATSAPP_NET,
613
808
  type: 'set',
614
809
  id: generateMessageTag(),
615
810
  xmlns: 'md'
@@ -620,7 +815,6 @@ const makeSocket = (config) => {
620
815
  attrs: {
621
816
  jid: authState.creds.me.id,
622
817
  stage: 'companion_hello',
623
- // eslint-disable-next-line camelcase
624
818
  should_show_push_notification: 'true'
625
819
  },
626
820
  content: [
@@ -637,7 +831,7 @@ const makeSocket = (config) => {
637
831
  {
638
832
  tag: 'companion_platform_id',
639
833
  attrs: {},
640
- content: Utils_1.getPlatformId(browser[1])
834
+ content: getPlatformId(browser[1])
641
835
  },
642
836
  {
643
837
  tag: 'companion_platform_display',
@@ -658,10 +852,10 @@ const makeSocket = (config) => {
658
852
  }
659
853
 
660
854
  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)
855
+ const salt = randomBytes(32)
856
+ const randomIv = randomBytes(16)
857
+ const key = await derivePairingCodeKey(authState.creds.pairingCode, salt)
858
+ const ciphered = aesEncryptCTR(authState.creds.pairingEphemeralKeyPair.public, key, randomIv)
665
859
 
666
860
  return Buffer.concat([salt, randomIv, ciphered])
667
861
  }
@@ -670,14 +864,14 @@ const makeSocket = (config) => {
670
864
  return query({
671
865
  tag: 'iq',
672
866
  attrs: {
673
- to: WABinary_1.S_WHATSAPP_NET,
867
+ to: S_WHATSAPP_NET,
674
868
  id: generateMessageTag(),
675
869
  xmlns: 'w:stats'
676
870
  },
677
871
  content: [
678
872
  {
679
873
  tag: 'add',
680
- attrs: {},
874
+ attrs: { t: Math.round(Date.now() / 1000) + '' },
681
875
  content: wamBuffer
682
876
  }
683
877
  ]
@@ -698,17 +892,17 @@ const makeSocket = (config) => {
698
892
 
699
893
  ws.on('error', mapWebSocketError(end))
700
894
 
701
- ws.on('close', () => end(new boom_1.Boom('Connection Terminated', { statusCode: Types_1.DisconnectReason.connectionClosed })))
895
+ ws.on('close', () => end(new Boom('Connection Terminated', { statusCode: DisconnectReason.connectionClosed })))
702
896
 
703
897
  // the server terminated the connection
704
- ws.on('CB:xmlstreamend', () => end(new boom_1.Boom('Connection Terminated by Server', { statusCode: Types_1.DisconnectReason.connectionClosed })))
898
+ ws.on('CB:xmlstreamend', () => end(new Boom('Connection Terminated by Server', { statusCode: DisconnectReason.connectionClosed })))
705
899
 
706
900
  // QR gen
707
901
  ws.on('CB:iq,type:set,pair-device', async (stanza) => {
708
902
  const iq = {
709
903
  tag: 'iq',
710
904
  attrs: {
711
- to: WABinary_1.S_WHATSAPP_NET,
905
+ to: S_WHATSAPP_NET,
712
906
  type: 'result',
713
907
  id: stanza.attrs.id,
714
908
  }
@@ -716,8 +910,8 @@ const makeSocket = (config) => {
716
910
 
717
911
  await sendNode(iq)
718
912
 
719
- const pairDeviceNode = WABinary_1.getBinaryNodeChild(stanza, 'pair-device')
720
- const refNodes = WABinary_1.getBinaryNodeChildren(pairDeviceNode, 'ref')
913
+ const pairDeviceNode = getBinaryNodeChild(stanza, 'pair-device')
914
+ const refNodes = getBinaryNodeChildren(pairDeviceNode, 'ref')
721
915
  const noiseKeyB64 = Buffer.from(creds.noiseKey.public).toString('base64')
722
916
  const identityKeyB64 = Buffer.from(creds.signedIdentityKey.public).toString('base64')
723
917
  const advB64 = creds.advSecretKey
@@ -732,7 +926,7 @@ const makeSocket = (config) => {
732
926
  const refNode = refNodes.shift()
733
927
 
734
928
  if (!refNode) {
735
- end(new boom_1.Boom('QR refs attempts ended', { statusCode: Types_1.DisconnectReason.timedOut }))
929
+ end(new Boom('QR refs attempts ended', { statusCode: DisconnectReason.timedOut }))
736
930
  return
737
931
  }
738
932
 
@@ -752,7 +946,7 @@ const makeSocket = (config) => {
752
946
  ws.on('CB:iq,,pair-success', async (stanza) => {
753
947
  logger.debug('pair success recv')
754
948
  try {
755
- const { reply, creds: updatedCreds } = Utils_1.configureSuccessfulPairing(stanza, creds)
949
+ const { reply, creds: updatedCreds } = configureSuccessfulPairing(stanza, creds)
756
950
  logger.info({ me: updatedCreds.me, platform: updatedCreds.platform }, 'pairing configured successfully, expect to restart the connection...')
757
951
 
758
952
  ev.emit('creds.update', updatedCreds)
@@ -767,21 +961,37 @@ const makeSocket = (config) => {
767
961
  }
768
962
  })
769
963
 
964
+ // login complete
770
965
  // login complete
771
966
  ws.on('CB:success', async (node) => {
772
967
  try {
773
968
  await uploadPreKeysToServerIfRequired()
774
969
  await sendPassiveIq('active')
970
+
971
+ // After successful login, validate our key-bundle against server
972
+ try {
973
+ await digestKeyBundle()
974
+ }
975
+
976
+ catch (e) {
977
+ logger.warn({ e }, 'failed to run digest after login');
978
+ }
775
979
  }
980
+
776
981
  catch (err) {
777
- logger.warn({ err }, 'failed to send initial passive iq');
982
+ logger.warn({ err }, 'failed to send initial passive iq')
778
983
  }
984
+
779
985
  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
986
+
987
+ clearTimeout(qrTimer) // will never happen in all likelyhood -- but just in case WA sends success on first try
988
+
781
989
  ev.emit('creds.update', { me: { ...authState.creds.me, lid: node.attrs.lid } })
782
990
  ev.emit('connection.update', { connection: 'open' })
991
+
783
992
  if (node.attrs.lid && authState.creds.me?.id) {
784
993
  const myLID = node.attrs.lid
994
+
785
995
  process.nextTick(async () => {
786
996
  try {
787
997
  const myPN = authState.creds.me.id
@@ -789,10 +999,21 @@ const makeSocket = (config) => {
789
999
  // Store our own LID-PN mapping
790
1000
  await signalRepository.lidMapping.storeLIDPNMappings([{ lid: myLID, pn: myPN }])
791
1001
 
792
- // Create LID session for ourselves (whatsmeow pattern)
793
- await signalRepository.migrateSession([myPN], myLID)
1002
+ // Create device list for our own user (needed for bulk migration)
1003
+ const { user, device } = jidDecode(myPN)
1004
+
1005
+ await authState.keys.set({
1006
+ 'device-list': {
1007
+ [user]: [device?.toString() || '0']
1008
+ }
1009
+ })
1010
+
1011
+ // migrate our own session
1012
+ await signalRepository.migrateSession(myPN, myLID)
1013
+
794
1014
  logger.info({ myPN, myLID }, 'Own LID session created successfully')
795
1015
  }
1016
+
796
1017
  catch (error) {
797
1018
  logger.error({ error, lid: myLID }, 'Failed to create own LID session')
798
1019
  }
@@ -801,21 +1022,24 @@ const makeSocket = (config) => {
801
1022
  })
802
1023
 
803
1024
  ws.on('CB:stream:error', (node) => {
804
- logger.error({ node }, 'stream errored out')
805
- const { reason, statusCode } = Utils_1.getErrorCodeFromStreamError(node)
1025
+ const [reasonNode] = getAllBinaryNodeChildren(node)
806
1026
 
807
- end(new boom_1.Boom(`Stream Errored (${reason})`, { statusCode, data: node }))
808
- })
1027
+ logger.error({ reasonNode, fullErrorNode: node }, 'stream errored out')
1028
+
1029
+ const { reason, statusCode } = getErrorCodeFromStreamError(node)
1030
+
1031
+ end(new Boom(`Stream Errored (${reason})`, { statusCode, data: reasonNode || node }))
1032
+ });
809
1033
 
810
1034
  // stream fail, possible logout
811
1035
  ws.on('CB:failure', (node) => {
812
1036
  const reason = +(node.attrs.reason || 500)
813
1037
 
814
- end(new boom_1.Boom('Connection Failure', { statusCode: reason, data: node.attrs }))
1038
+ end(new Boom('Connection Failure', { statusCode: reason, data: node.attrs }))
815
1039
  })
816
1040
 
817
1041
  ws.on('CB:ib,,downgrade_webclient', () => {
818
- end(new boom_1.Boom('Multi-device beta not joined', { statusCode: Types_1.DisconnectReason.multideviceMismatch }))
1042
+ end(new Boom('Multi-device beta not joined', { statusCode: DisconnectReason.multideviceMismatch }))
819
1043
  })
820
1044
 
821
1045
  ws.on('CB:ib,,offline_preview', (node) => {
@@ -829,8 +1053,8 @@ const makeSocket = (config) => {
829
1053
  })
830
1054
 
831
1055
  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')
1056
+ const edgeRoutingNode = getBinaryNodeChild(node, 'edge_routing')
1057
+ const routingInfo = getBinaryNodeChild(edgeRoutingNode, 'routing_info')
834
1058
 
835
1059
  if (routingInfo?.content) {
836
1060
  authState.creds.routingInfo = Buffer.from(routingInfo?.content)
@@ -853,7 +1077,7 @@ const makeSocket = (config) => {
853
1077
 
854
1078
  // called when all offline notifs are handled
855
1079
  ws.on('CB:ib,,offline', (node) => {
856
- const child = WABinary_1.getBinaryNodeChild(node, 'offline')
1080
+ const child = getBinaryNodeChild(node, 'offline')
857
1081
  const offlineNotifs = +(child?.attrs.count || 0)
858
1082
 
859
1083
  logger.info(`handled ${offlineNotifs} offline messages/notifications`)
@@ -886,7 +1110,7 @@ const makeSocket = (config) => {
886
1110
  })
887
1111
 
888
1112
  if (printQRInTerminal) {
889
- Utils_1.printQRIfNecessaryListener(ev, logger)
1113
+ printQRIfNecessaryListener(ev, logger)
890
1114
  }
891
1115
 
892
1116
  return {
@@ -896,7 +1120,7 @@ const makeSocket = (config) => {
896
1120
  authState: { creds, keys },
897
1121
  signalRepository,
898
1122
  get user() {
899
- return authState.creds.me
1123
+ return authState.creds.me;
900
1124
  },
901
1125
  generateMessageTag,
902
1126
  query,
@@ -909,13 +1133,15 @@ const makeSocket = (config) => {
909
1133
  onUnexpectedError,
910
1134
  uploadPreKeys,
911
1135
  uploadPreKeysToServerIfRequired,
1136
+ digestKeyBundle,
1137
+ rotateSignedPreKey,
912
1138
  requestPairingCode,
1139
+ wamBuffer: publicWAMBuffer,
913
1140
  /** Waits for the connection to WA to reach a state */
914
- waitForConnectionUpdate: Utils_1.bindWaitForConnectionUpdate(ev),
1141
+ waitForConnectionUpdate: bindWaitForConnectionUpdate(ev),
915
1142
  sendWAMBuffer,
916
- executeUSyncQuery,
917
- onWhatsApp,
918
- logger
1143
+ executeUSyncQuery,
1144
+ onWhatsApp
919
1145
  }
920
1146
  }
921
1147
 
@@ -925,7 +1151,7 @@ const makeSocket = (config) => {
925
1151
  * */
926
1152
  function mapWebSocketError(handler) {
927
1153
  return (error) => {
928
- handler(new boom_1.Boom(`WebSocket Error (${error?.message})`, { statusCode: Utils_1.getCodeFromWSError(error), data: error }))
1154
+ handler(new Boom(`WebSocket Error (${error?.message})`, { statusCode: getCodeFromWSError(error), data: error }))
929
1155
  }
930
1156
  }
931
1157