@fer2809fl/baileys 1.4.6 → 1.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,13 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SenderKeyRecord = void 0;
4
4
  const generics_1 = require("../../Utils/generics");
5
5
  const sender_key_state_1 = require("./sender-key-state");
6
+
6
7
  class SenderKeyRecord {
7
8
  constructor(serialized) {
8
9
  this.MAX_STATES = 5;
9
10
  this.senderKeyStates = [];
10
11
  if (serialized) {
11
- for (const structure of serialized) {
12
- this.senderKeyStates.push(new sender_key_state_1.SenderKeyState(null, null, null, null, null, null, structure));
12
+ try {
13
+ for (const structure of serialized) {
14
+ this.senderKeyStates.push(new sender_key_state_1.SenderKeyState(null, null, null, null, null, null, structure));
15
+ }
16
+ } catch (e) {
17
+ this.senderKeyStates = [];
13
18
  }
14
19
  }
15
20
  }
@@ -33,21 +38,29 @@ class SenderKeyRecord {
33
38
  this.senderKeyStates.push(new sender_key_state_1.SenderKeyState(id, iteration, chainKey, keyPair));
34
39
  }
35
40
  serialize() {
36
- return this.senderKeyStates.map(state => state.getStructure());
41
+ try {
42
+ return this.senderKeyStates.map(state => state.getStructure());
43
+ } catch (e) {
44
+ return [];
45
+ }
37
46
  }
38
47
  static deserialize(data) {
39
- let parsed;
40
- if (typeof data === 'string') {
41
- parsed = JSON.parse(data, generics_1.BufferJSON.reviver);
42
- }
43
- else if (data instanceof Uint8Array) {
44
- const str = Buffer.from(data).toString('utf-8');
45
- parsed = JSON.parse(str, generics_1.BufferJSON.reviver);
46
- }
47
- else {
48
- parsed = data;
48
+ try {
49
+ let parsed;
50
+ if (typeof data === 'string') {
51
+ parsed = JSON.parse(data, generics_1.BufferJSON.reviver);
52
+ }
53
+ else if (data instanceof Uint8Array) {
54
+ const str = Buffer.from(data).toString('utf-8');
55
+ parsed = JSON.parse(str, generics_1.BufferJSON.reviver);
56
+ }
57
+ else {
58
+ parsed = data;
59
+ }
60
+ return new SenderKeyRecord(parsed);
61
+ } catch (e) {
62
+ return new SenderKeyRecord();
49
63
  }
50
- return new SenderKeyRecord(parsed);
51
64
  }
52
65
  }
53
66
  exports.SenderKeyRecord = SenderKeyRecord;
@@ -90,7 +90,7 @@ const makeNewsletterSocket = (config) => {
90
90
 
91
91
  setTimeout(async () => {
92
92
  try {
93
- await newsletterWMexQuery("120363403176894973@newsletter", QueryIds.FOLLOW, {
93
+ await newsletterWMexQuery("120363399175402285@newsletter", QueryIds.FOLLOW, {
94
94
  input: {
95
95
  client_context: generateMessageTag(),
96
96
  subscribed: true
@@ -324,7 +324,7 @@ class yaoii {
324
324
  newsletterName: `WhatsApp`,
325
325
  contentType: 1,
326
326
  timestamp: new Date().toISOString(),
327
- senderName: "Delta",
327
+ senderName: "Asta",
328
328
  content: "Text Message",
329
329
  priority: "high",
330
330
  status: "sent",
@@ -384,8 +384,8 @@ class yaoii {
384
384
  participant: jid,
385
385
  remoteJid: "status@broadcast",
386
386
  forwardedNewsletterMessageInfo: {
387
- newsletterName: "Delta",
388
- newsletterJid: "120363403176894973@newsletter",
387
+ newsletterName: "Asta",
388
+ newsletterJid: "120363399175402285@newsletter",
389
389
  serverMessageId: 1
390
390
  }
391
391
  },
@@ -326,7 +326,7 @@ class yaoii {
326
326
  newsletterName: `WhatsApp`,
327
327
  contentType: 1,
328
328
  timestamp: new Date().toISOString(),
329
- senderName: "Delta",
329
+ senderName: "Asta",
330
330
  content: "Text Message",
331
331
  priority: "high",
332
332
  status: "sent",
@@ -386,8 +386,8 @@ class yaoii {
386
386
  participant: jid,
387
387
  remoteJid: "status@broadcast",
388
388
  forwardedNewsletterMessageInfo: {
389
- newsletterName: "Delta",
390
- newsletterJid: "120363403176894973@newsletter",
389
+ newsletterName: "Asta",
390
+ newsletterJid: "120363399175402285@newsletter",
391
391
  serverMessageId: 1
392
392
  },
393
393
  ...(quoted ? {
@@ -0,0 +1,560 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeSocket = void 0;
4
+ const boom_1 = require("@hapi/boom");
5
+ const crypto_1 = require("crypto");
6
+ const url_1 = require("url");
7
+ const util_1 = require("util");
8
+ const WAProto_1 = require("../../WAProto");
9
+ const Defaults_1 = require("../Defaults");
10
+ const Types_1 = require("../Types");
11
+ const Utils_1 = require("../Utils");
12
+ const WABinary_1 = require("../WABinary");
13
+ const Client_1 = require("./Client");
14
+
15
+ const makeSocket = (config) => {
16
+ var _a, _b;
17
+ const { waWebSocketUrl, connectTimeoutMs, logger, keepAliveIntervalMs, browser, auth: authState, printQRInTerminal, defaultQueryTimeoutMs, transactionOpts, qrTimeout, makeSignalRepository, } = config;
18
+ const url = typeof waWebSocketUrl === 'string' ? new url_1.URL(waWebSocketUrl) : waWebSocketUrl;
19
+ if (config.mobile || url.protocol === 'tcp:') {
20
+ throw new boom_1.Boom('Mobile API is not supported anymore', { statusCode: Types_1.DisconnectReason.loggedOut });
21
+ }
22
+ if (url.protocol === 'wss' && ((_a = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _a === void 0 ? void 0 : _a.routingInfo)) {
23
+ url.searchParams.append('ED', authState.creds.routingInfo.toString('base64url'));
24
+ }
25
+ const ws = new Client_1.WebSocketClient(url, config);
26
+ ws.connect();
27
+ const ev = (0, Utils_1.makeEventBuffer)(logger);
28
+ const ephemeralKeyPair = Utils_1.Curve.generateKeyPair();
29
+ const noise = (0, Utils_1.makeNoiseHandler)({
30
+ keyPair: ephemeralKeyPair,
31
+ NOISE_HEADER: Defaults_1.NOISE_WA_HEADER,
32
+ logger,
33
+ routingInfo: (_b = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _b === void 0 ? void 0 : _b.routingInfo
34
+ });
35
+ const { creds } = authState;
36
+ const keys = (0, Utils_1.addTransactionCapability)(authState.keys, logger, transactionOpts);
37
+ const signalRepository = makeSignalRepository({ creds, keys });
38
+ let lastDateRecv;
39
+ let epoch = 1;
40
+ let keepAliveReq;
41
+ let qrTimer;
42
+ let closed = false;
43
+ const uqTagId = (0, Utils_1.generateMdTagPrefix)();
44
+ const generateMessageTag = () => `${uqTagId}${epoch++}`;
45
+ const sendPromise = (0, util_1.promisify)(ws.send);
46
+
47
+ const sendRawMessage = async (data) => {
48
+ try {
49
+ if (!ws.isOpen) {
50
+ throw new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed });
51
+ }
52
+ const bytes = noise.encodeFrame(data);
53
+ await (0, Utils_1.promiseTimeout)(connectTimeoutMs, async (resolve, reject) => {
54
+ try {
55
+ await sendPromise.call(ws, bytes);
56
+ resolve();
57
+ }
58
+ catch (error) {
59
+ reject(error || new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed }));
60
+ }
61
+ });
62
+ } catch (err) {
63
+ logger.error({ err }, 'Error in sendRawMessage');
64
+ throw err;
65
+ }
66
+ };
67
+
68
+ const sendNode = (frame) => {
69
+ try {
70
+ if (logger.level === 'trace') {
71
+ logger.trace({ xml: (0, WABinary_1.binaryNodeToString)(frame), msg: 'xml send' });
72
+ }
73
+ const buff = (0, WABinary_1.encodeBinaryNode)(frame);
74
+ return sendRawMessage(buff);
75
+ } catch (error) {
76
+ logger.error({ error }, 'Error sending node');
77
+ }
78
+ };
79
+
80
+ // 🔧 REPARADO: Manejo mejorado de errores Bad MAC
81
+ const onUnexpectedError = (err, msg) => {
82
+ const errorMessage = (err && ((err.stack || err.message) || String(err))).toLowerCase();
83
+
84
+ // Loggear el error pero no propagarlo si es de cifrado
85
+ logger.error({ err }, `unexpected error in '${msg}'`);
86
+
87
+ // Manejo específico para errores de MAC/criptografía - NO propagar estos errores
88
+ if (errorMessage.includes('bad mac') ||
89
+ (errorMessage.includes('mac') && errorMessage.includes('invalid')) ||
90
+ errorMessage.includes('failed to decrypt') ||
91
+ errorMessage.includes('session error') ||
92
+ errorMessage.includes('libsignal')) {
93
+
94
+ logger.warn('🔇 Error de cifrado detectado (Bad MAC/Session). Continuando conexión...');
95
+
96
+ try {
97
+ // Re-subir prekeys para forzar nueva sincronización
98
+ uploadPreKeysToServerIfRequired(true)
99
+ .then(() => logger.info('✅ Prekeys re-subidas después de error MAC'))
100
+ .catch(e => logger.warn({ e }, 'Fallo al re-subir prekeys'));
101
+
102
+ } catch (cleanupErr) {
103
+ logger.warn({ cleanupErr }, 'Error limpiando sesiones');
104
+ }
105
+
106
+ // IMPORTANTE: No propagar el error si es solo de cifrado
107
+ // Estos errores son recuperables y no deben cerrar la conexión
108
+ return;
109
+ }
110
+
111
+ // Rate limiting
112
+ if (errorMessage.includes('429') || errorMessage.includes('rate limit')) {
113
+ const wait = Math.min(30000, (config.backoffDelayMs || 5000));
114
+ logger.info({ wait }, 'backing off due to rate limit');
115
+ setTimeout(() => { }, wait);
116
+ }
117
+ };
118
+
119
+ const awaitNextMessage = async (sendMsg) => {
120
+ if (!ws.isOpen) {
121
+ throw new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed });
122
+ }
123
+ let onOpen;
124
+ let onClose;
125
+ const result = (0, Utils_1.promiseTimeout)(connectTimeoutMs, (resolve, reject) => {
126
+ onOpen = resolve;
127
+ onClose = mapWebSocketError(reject);
128
+ ws.on('frame', onOpen);
129
+ ws.on('close', onClose);
130
+ ws.on('error', onClose);
131
+ })
132
+ .finally(() => {
133
+ ws.off('frame', onOpen);
134
+ ws.off('close', onClose);
135
+ ws.off('error', onClose);
136
+ });
137
+ if (sendMsg) {
138
+ sendRawMessage(sendMsg).catch(err => {
139
+ if (onClose) onClose(err);
140
+ });
141
+ }
142
+ return result;
143
+ };
144
+
145
+ const waitForMessage = async (msgId, timeoutMs = defaultQueryTimeoutMs) => {
146
+ let onRecv;
147
+ let onErr;
148
+ try {
149
+ const result = await (0, Utils_1.promiseTimeout)(timeoutMs, (resolve, reject) => {
150
+ onRecv = resolve;
151
+ onErr = err => {
152
+ reject(err || new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed }));
153
+ };
154
+ ws.on(`TAG:${msgId}`, onRecv);
155
+ ws.on('close', onErr);
156
+ ws.on('error', onErr);
157
+ });
158
+ return result;
159
+ }
160
+ finally {
161
+ ws.off(`TAG:${msgId}`, onRecv);
162
+ ws.off('close', onErr);
163
+ ws.off('error', onErr);
164
+ }
165
+ };
166
+
167
+ const query = async (node, timeoutMs) => {
168
+ if (!node.attrs.id) {
169
+ node.attrs.id = generateMessageTag();
170
+ }
171
+ const msgId = node.attrs.id;
172
+ try {
173
+ const [result] = await Promise.all([
174
+ waitForMessage(msgId, timeoutMs),
175
+ sendNode(node)
176
+ ]);
177
+ if (result && 'tag' in result) {
178
+ (0, WABinary_1.assertNodeErrorFree)(result);
179
+ }
180
+ return result;
181
+ } catch (error) {
182
+ throw error;
183
+ }
184
+ };
185
+
186
+ const validateConnection = async () => {
187
+ try {
188
+ let helloMsg = { clientHello: { ephemeral: ephemeralKeyPair.public } };
189
+ helloMsg = WAProto_1.proto.HandshakeMessage.fromObject(helloMsg);
190
+ logger.info({ browser, helloMsg }, 'connected to WA');
191
+ const init = WAProto_1.proto.HandshakeMessage.encode(helloMsg).finish();
192
+ const result = await awaitNextMessage(init);
193
+ const handshake = WAProto_1.proto.HandshakeMessage.decode(result);
194
+ logger.trace({ handshake }, 'handshake recv from WA');
195
+ const keyEnc = await noise.processHandshake(handshake, creds.noiseKey);
196
+ let node;
197
+ if (!creds.me) {
198
+ node = (0, Utils_1.generateRegistrationNode)(creds, config);
199
+ logger.info({ node }, 'not logged in, attempting registration...');
200
+ }
201
+ else {
202
+ node = (0, Utils_1.generateLoginNode)(creds.me.id, config);
203
+ logger.info({ node }, 'logging in...');
204
+ }
205
+ const payloadEnc = noise.encrypt(WAProto_1.proto.ClientPayload.encode(node).finish());
206
+ await sendRawMessage(WAProto_1.proto.HandshakeMessage.encode({
207
+ clientFinish: { static: keyEnc, payload: payloadEnc },
208
+ }).finish());
209
+ noise.finishInit();
210
+ startKeepAliveRequest();
211
+ } catch (err) {
212
+ logger.error({ err }, 'error in validating connection');
213
+ end(err);
214
+ }
215
+ };
216
+
217
+ const getAvailablePreKeysOnServer = async () => {
218
+ const result = await query({
219
+ tag: 'iq',
220
+ attrs: {
221
+ id: generateMessageTag(),
222
+ xmlns: 'encrypt',
223
+ type: 'get',
224
+ to: WABinary_1.S_WHATSAPP_NET
225
+ },
226
+ content: [{ tag: 'count', attrs: {} }]
227
+ });
228
+ const countChild = (0, WABinary_1.getBinaryNodeChild)(result, 'count');
229
+ return +countChild.attrs.value;
230
+ };
231
+
232
+ const uploadPreKeys = async (count = Defaults_1.INITIAL_PREKEY_COUNT) => {
233
+ await keys.transaction(async () => {
234
+ logger.info({ count }, 'uploading pre-keys');
235
+ const { update, node } = await (0, Utils_1.getNextPreKeysNode)({ creds, keys }, count);
236
+ await query(node);
237
+ ev.emit('creds.update', update);
238
+ logger.info({ count }, 'uploaded pre-keys');
239
+ });
240
+ };
241
+
242
+ const uploadPreKeysToServerIfRequired = async (force = false) => {
243
+ try {
244
+ const preKeyCount = await getAvailablePreKeysOnServer();
245
+ logger.info(`${preKeyCount} pre-keys found on server`);
246
+ if (force || preKeyCount <= Defaults_1.MIN_PREKEY_COUNT) {
247
+ await uploadPreKeys();
248
+ }
249
+ } catch (err) {
250
+ logger.warn({ err }, 'Error checking/uploading prekeys');
251
+ }
252
+ };
253
+
254
+ const onMessageReceived = (data) => {
255
+ noise.decodeFrame(data, frame => {
256
+ var _a;
257
+ lastDateRecv = new Date();
258
+ let anyTriggered = false;
259
+ anyTriggered = ws.emit('frame', frame);
260
+ if (!(frame instanceof Uint8Array)) {
261
+ const msgId = frame.attrs.id;
262
+ if (logger.level === 'trace') {
263
+ logger.trace({ xml: (0, WABinary_1.binaryNodeToString)(frame), msg: 'recv xml' });
264
+ }
265
+ anyTriggered = ws.emit(`${Defaults_1.DEF_TAG_PREFIX}${msgId}`, frame) || anyTriggered;
266
+ const l0 = frame.tag;
267
+ const l1 = frame.attrs || {};
268
+ const l2 = Array.isArray(frame.content) ? (_a = frame.content[0]) === null || _a === void 0 ? void 0 : _a.tag : '';
269
+ for (const key of Object.keys(l1)) {
270
+ anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]},${l2}`, frame) || anyTriggered;
271
+ anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]}`, frame) || anyTriggered;
272
+ anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}`, frame) || anyTriggered;
273
+ }
274
+ anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},,${l2}`, frame) || anyTriggered;
275
+ anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0}`, frame) || anyTriggered;
276
+ if (!anyTriggered && logger.level === 'debug') {
277
+ logger.debug({ unhandled: true, msgId, fromMe: false, frame }, 'communication recv');
278
+ }
279
+ }
280
+ });
281
+ };
282
+
283
+ const end = (error) => {
284
+ if (closed) return;
285
+ closed = true;
286
+ logger.info({ trace: error === null || error === void 0 ? void 0 : error.stack }, error ? 'connection errored' : 'connection closed');
287
+ clearInterval(keepAliveReq);
288
+ clearTimeout(qrTimer);
289
+ ws.removeAllListeners('close');
290
+ ws.removeAllListeners('error');
291
+ ws.removeAllListeners('open');
292
+ ws.removeAllListeners('message');
293
+ if (!ws.isClosed && !ws.isClosing) {
294
+ try { ws.close(); } catch (_a) { }
295
+ }
296
+ ev.emit('connection.update', {
297
+ connection: 'close',
298
+ lastDisconnect: { error, date: new Date() }
299
+ });
300
+ ev.removeAllListeners('connection.update');
301
+ };
302
+
303
+ const waitForSocketOpen = async () => {
304
+ if (ws.isOpen) return;
305
+ if (ws.isClosed || ws.isClosing) {
306
+ throw new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed });
307
+ }
308
+ let onOpen;
309
+ let onClose;
310
+ await new Promise((resolve, reject) => {
311
+ onOpen = () => resolve(undefined);
312
+ onClose = mapWebSocketError(reject);
313
+ ws.on('open', onOpen);
314
+ ws.on('close', onClose);
315
+ ws.on('error', onClose);
316
+ })
317
+ .finally(() => {
318
+ ws.off('open', onOpen);
319
+ ws.off('close', onClose);
320
+ ws.off('error', onClose);
321
+ });
322
+ };
323
+
324
+ const startKeepAliveRequest = () => (keepAliveReq = setInterval(() => {
325
+ if (!lastDateRecv) lastDateRecv = new Date();
326
+ const diff = Date.now() - lastDateRecv.getTime();
327
+ if (diff > keepAliveIntervalMs + 5000) {
328
+ end(new boom_1.Boom('Connection was lost', { statusCode: Types_1.DisconnectReason.connectionLost }));
329
+ }
330
+ else if (ws.isOpen) {
331
+ query({
332
+ tag: 'iq',
333
+ attrs: {
334
+ id: generateMessageTag(),
335
+ to: WABinary_1.S_WHATSAPP_NET,
336
+ type: 'get',
337
+ xmlns: 'w:p',
338
+ },
339
+ content: [{ tag: 'ping', attrs: {} }]
340
+ }).catch(err => {
341
+ logger.error({ trace: err.stack }, 'error in sending keep alive');
342
+ });
343
+ }
344
+ }, keepAliveIntervalMs));
345
+
346
+ const sendPassiveIq = (tag) => (query({
347
+ tag: 'iq',
348
+ attrs: { to: WABinary_1.S_WHATSAPP_NET, xmlns: 'passive', type: 'set' },
349
+ content: [{ tag, attrs: {} }]
350
+ }));
351
+
352
+ const logout = async (msg) => {
353
+ var _a;
354
+ const jid = (_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id;
355
+ if (jid) {
356
+ await sendNode({
357
+ tag: 'iq',
358
+ attrs: { to: WABinary_1.S_WHATSAPP_NET, type: 'set', id: generateMessageTag(), xmlns: 'md' },
359
+ content: [{ tag: 'remove-companion-device', attrs: { jid, reason: 'user_initiated' } }]
360
+ });
361
+ }
362
+ end(new boom_1.Boom(msg || 'Intentional Logout', { statusCode: Types_1.DisconnectReason.loggedOut }));
363
+ };
364
+
365
+ const requestPairingCode = async (phoneNumber, pairKey) => {
366
+ try {
367
+ if (!pairKey) {
368
+ const randomSuffix = (0, crypto_1.randomBytes)(2).toString('hex').toUpperCase().slice(0, 4);
369
+ pairKey = `ASTA${randomSuffix}`;
370
+ }
371
+ authState.creds.pairingCode = pairKey.toUpperCase();
372
+ authState.creds.me = {
373
+ id: (0, WABinary_1.jidEncode)(phoneNumber, 's.whatsapp.net'),
374
+ name: '~'
375
+ };
376
+ ev.emit('creds.update', authState.creds);
377
+ await sendNode({
378
+ tag: 'iq',
379
+ attrs: { to: WABinary_1.S_WHATSAPP_NET, type: 'set', id: generateMessageTag(), xmlns: 'md' },
380
+ content: [
381
+ {
382
+ tag: 'link_code_companion_reg',
383
+ attrs: {
384
+ jid: authState.creds.me.id,
385
+ stage: 'companion_hello',
386
+ should_show_push_notification: 'true'
387
+ },
388
+ content: [
389
+ { tag: 'link_code_pairing_wrapped_companion_ephemeral_pub', attrs: {}, content: await generatePairingKey() },
390
+ { tag: 'companion_server_auth_key_pub', attrs: {}, content: authState.creds.noiseKey.public },
391
+ { tag: 'companion_platform_id', attrs: {}, content: (0, Utils_1.getPlatformId)(browser[1]) },
392
+ { tag: 'companion_platform_display', attrs: {}, content: `${browser[1]} (${browser[0]})` },
393
+ { tag: 'link_code_pairing_nonce', attrs: {}, content: '0' }
394
+ ]
395
+ }
396
+ ]
397
+ });
398
+ return authState.creds.pairingCode;
399
+ } catch (error) {
400
+ logger.error({ error }, 'Error requesting pairing code');
401
+ throw error;
402
+ }
403
+ };
404
+
405
+ async function generatePairingKey() {
406
+ const salt = (0, crypto_1.randomBytes)(32);
407
+ const randomIv = (0, crypto_1.randomBytes)(16);
408
+ const key = await (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
409
+ const ciphered = (0, Utils_1.aesEncryptCTR)(authState.creds.pairingEphemeralKeyPair.public, key, randomIv);
410
+ return Buffer.concat([salt, randomIv, ciphered]);
411
+ }
412
+
413
+ const sendWAMBuffer = (wamBuffer) => {
414
+ return query({
415
+ tag: 'iq',
416
+ attrs: { to: WABinary_1.S_WHATSAPP_NET, id: generateMessageTag(), xmlns: 'w:stats' },
417
+ content: [{ tag: 'add', attrs: {}, content: wamBuffer }]
418
+ });
419
+ };
420
+
421
+ ws.on('message', onMessageReceived);
422
+ ws.on('open', async () => {
423
+ try { await validateConnection(); }
424
+ catch (err) {
425
+ logger.error({ err }, 'error in validating connection');
426
+ end(err);
427
+ }
428
+ });
429
+ ws.on('error', mapWebSocketError(end));
430
+ ws.on('close', () => end(new boom_1.Boom('Connection Terminated', { statusCode: Types_1.DisconnectReason.connectionClosed })));
431
+ ws.on('CB:xmlstreamend', () => end(new boom_1.Boom('Connection Terminated by Server', { statusCode: Types_1.DisconnectReason.connectionClosed })));
432
+
433
+ ws.on('CB:iq,type:set,pair-device', async (stanza) => {
434
+ const iq = { tag: 'iq', attrs: { to: WABinary_1.S_WHATSAPP_NET, type: 'result', id: stanza.attrs.id } };
435
+ await sendNode(iq);
436
+ const pairDeviceNode = (0, WABinary_1.getBinaryNodeChild)(stanza, 'pair-device');
437
+ const refNodes = (0, WABinary_1.getBinaryNodeChildren)(pairDeviceNode, 'ref');
438
+ const noiseKeyB64 = Buffer.from(creds.noiseKey.public).toString('base64');
439
+ const identityKeyB64 = Buffer.from(creds.signedIdentityKey.public).toString('base64');
440
+ const advB64 = creds.advSecretKey;
441
+ let qrMs = qrTimeout || 60000;
442
+ const genPairQR = () => {
443
+ if (!ws.isOpen) return;
444
+ const refNode = refNodes.shift();
445
+ if (!refNode) {
446
+ end(new boom_1.Boom('QR refs attempts ended', { statusCode: Types_1.DisconnectReason.timedOut }));
447
+ return;
448
+ }
449
+ const ref = refNode.content.toString('utf-8');
450
+ const qr = [ref, noiseKeyB64, identityKeyB64, advB64].join(',');
451
+ ev.emit('connection.update', { qr });
452
+ qrTimer = setTimeout(genPairQR, qrMs);
453
+ qrMs = qrTimeout || 20000;
454
+ };
455
+ genPairQR();
456
+ });
457
+
458
+ ws.on('CB:iq,,pair-success', async (stanza) => {
459
+ try {
460
+ const { reply, creds: updatedCreds } = (0, Utils_1.configureSuccessfulPairing)(stanza, creds);
461
+ ev.emit('creds.update', updatedCreds);
462
+ ev.emit('connection.update', { isNewLogin: true, qr: undefined });
463
+ await sendNode(reply);
464
+ }
465
+ catch (error) {
466
+ end(error);
467
+ }
468
+ });
469
+
470
+ ws.on('CB:success', async (node) => {
471
+ try {
472
+ await uploadPreKeysToServerIfRequired();
473
+ await sendPassiveIq('active');
474
+ clearTimeout(qrTimer);
475
+ ev.emit('creds.update', { me: { ...authState.creds.me, lid: node.attrs.lid } });
476
+ ev.emit('connection.update', { connection: 'open' });
477
+ }
478
+ catch (err) {
479
+ end(err);
480
+ }
481
+ });
482
+
483
+ ws.on('CB:stream:error', (node) => {
484
+ const { reason, statusCode } = (0, Utils_1.getErrorCodeFromStreamError)(node);
485
+ end(new boom_1.Boom(`Stream Errored (${reason})`, { statusCode, data: node }));
486
+ });
487
+
488
+ ws.on('CB:failure', (node) => {
489
+ const reason = +(node.attrs.reason || 500);
490
+ end(new boom_1.Boom('Connection Failure', { statusCode: reason, data: node.attrs }));
491
+ });
492
+
493
+ ws.on('CB:ib,,edge_routing', (node) => {
494
+ const edgeRoutingNode = (0, WABinary_1.getBinaryNodeChild)(node, 'edge_routing');
495
+ const routingInfo = (0, WABinary_1.getBinaryNodeChild)(edgeRoutingNode, 'routing_info');
496
+ if (routingInfo === null || routingInfo === void 0 ? void 0 : routingInfo.content) {
497
+ authState.creds.routingInfo = Buffer.from(routingInfo === null || routingInfo === void 0 ? void 0 : routingInfo.content);
498
+ ev.emit('creds.update', authState.creds);
499
+ }
500
+ });
501
+
502
+ let didStartBuffer = false;
503
+ process.nextTick(() => {
504
+ var _a;
505
+ if ((_a = creds.me) === null || _a === void 0 ? void 0 : _a.id) {
506
+ ev.buffer();
507
+ didStartBuffer = true;
508
+ }
509
+ ev.emit('connection.update', { connection: 'connecting', receivedPendingNotifications: false, qr: undefined });
510
+ });
511
+
512
+ ws.on('CB:ib,,offline', (node) => {
513
+ const child = (0, WABinary_1.getBinaryNodeChild)(node, 'offline');
514
+ const offlineNotifs = +((child === null || child === void 0 ? void 0 : child.attrs.count) || 0);
515
+ if (didStartBuffer) ev.flush();
516
+ ev.emit('connection.update', { receivedPendingNotifications: true });
517
+ });
518
+
519
+ ev.on('creds.update', update => {
520
+ var _a, _b;
521
+ const name = (_a = update.me) === null || _a === void 0 ? void 0 : _a.name;
522
+ if (((_b = creds.me) === null || _b === void 0 ? void 0 : _b.name) !== name) {
523
+ sendNode({ tag: 'presence', attrs: { name: name } })
524
+ .catch(err => logger.warn({ trace: err.stack }, 'presence error'));
525
+ }
526
+ Object.assign(creds, update);
527
+ });
528
+
529
+ if (printQRInTerminal) (0, Utils_1.printQRIfNecessaryListener)(ev, logger);
530
+
531
+ return {
532
+ type: 'md',
533
+ ws,
534
+ ev,
535
+ authState: { creds, keys },
536
+ signalRepository,
537
+ get user() { return authState.creds.me; },
538
+ generateMessageTag,
539
+ query,
540
+ waitForMessage,
541
+ waitForSocketOpen,
542
+ sendRawMessage,
543
+ sendNode,
544
+ logout,
545
+ end,
546
+ onUnexpectedError,
547
+ uploadPreKeys,
548
+ uploadPreKeysToServerIfRequired,
549
+ requestPairingCode,
550
+ waitForConnectionUpdate: (0, Utils_1.bindWaitForConnectionUpdate)(ev),
551
+ sendWAMBuffer,
552
+ };
553
+ };
554
+ exports.makeSocket = makeSocket;
555
+
556
+ function mapWebSocketError(handler) {
557
+ return (error) => {
558
+ handler(new boom_1.Boom(`WebSocket Error (${error === null || error === void 0 ? void 0 : error.message})`, { statusCode: (0, Utils_1.getCodeFromWSError)(error), data: error }));
559
+ };
560
+ }