@baileys-md/baileys 10.1.0 → 11.0.0
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.
- package/LICENSE +1 -1
- package/README.md +1303 -2
- package/WAProto/GenerateStatics.sh +3 -0
- package/WAProto/WAProto.proto +4633 -0
- package/WAProto/fix-imports.js +29 -0
- package/WAProto/index.js +13516 -4182
- package/lib/Defaults/baileys-version.js +1 -0
- package/lib/Defaults/index.js +51 -72
- package/lib/Signal/Group/ciphertext-message.js +12 -0
- package/lib/Signal/Group/group-session-builder.js +30 -0
- package/lib/Signal/Group/group_cipher.js +94 -0
- package/lib/Signal/Group/index.js +12 -0
- package/lib/Signal/Group/keyhelper.js +19 -0
- package/lib/Signal/Group/queue-job.js +54 -0
- package/lib/Signal/Group/sender-chain-key.js +32 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +63 -0
- package/lib/Signal/Group/sender-key-message.js +67 -0
- package/lib/Signal/Group/sender-key-name.js +48 -0
- package/lib/Signal/Group/sender-key-record.js +50 -0
- package/lib/Signal/Group/sender-key-state.js +96 -0
- package/{WASignalGroup/sender_message_key.js → lib/Signal/Group/sender-message-key.js} +4 -16
- package/lib/Signal/libsignal.js +41 -61
- package/lib/Socket/Client/index.js +3 -19
- package/lib/Socket/Client/types.js +11 -0
- package/lib/Socket/Client/websocket.js +50 -0
- package/lib/Socket/business.js +37 -42
- package/lib/Socket/chats.js +194 -187
- package/lib/Socket/communities.js +351 -0
- package/lib/Socket/groups.js +87 -90
- package/lib/Socket/index.js +7 -8
- package/lib/Socket/messages-recv.js +360 -335
- package/lib/Socket/messages-send.js +156 -279
- package/lib/Socket/mex.js +42 -0
- package/lib/Socket/newsletter.js +144 -213
- package/lib/Socket/socket.js +128 -161
- package/lib/Socket/usync.js +19 -26
- package/lib/Types/Auth.js +2 -2
- package/lib/Types/Call.js +2 -2
- package/lib/Types/Chat.js +8 -4
- package/lib/Types/Contact.js +2 -2
- package/lib/Types/Events.js +2 -2
- package/lib/Types/GroupMetadata.js +2 -2
- package/lib/Types/Label.js +3 -5
- package/lib/Types/LabelAssociation.js +3 -5
- package/lib/Types/Message.js +7 -7
- package/lib/Types/Newsletter.js +30 -17
- package/lib/Types/Product.js +2 -2
- package/lib/Types/Signal.js +2 -2
- package/lib/Types/Socket.js +3 -2
- package/lib/Types/State.js +2 -2
- package/lib/Types/USync.js +2 -2
- package/lib/Types/index.js +15 -31
- package/lib/Utils/auth-utils.js +31 -47
- package/lib/Utils/baileys-event-stream.js +15 -22
- package/lib/Utils/business.js +66 -69
- package/lib/Utils/chat-utils.js +200 -195
- package/lib/Utils/crypto.js +70 -85
- package/lib/Utils/decode-wa-message.js +47 -51
- package/lib/Utils/event-buffer.js +36 -46
- package/lib/Utils/generics.js +116 -188
- package/lib/Utils/history.js +37 -46
- package/lib/Utils/index.js +19 -33
- package/lib/Utils/link-preview.js +14 -55
- package/lib/Utils/logger.js +3 -7
- package/lib/Utils/lt-hash.js +23 -26
- package/lib/{Store → Utils}/make-in-memory-store.js +19 -27
- package/lib/Utils/make-mutex.js +7 -10
- package/lib/{Store → Utils}/make-ordered-dictionary.js +1 -3
- package/lib/Utils/messages-media.js +236 -368
- package/lib/Utils/messages.js +278 -510
- package/lib/Utils/noise-handler.js +22 -31
- package/lib/{Store → Utils}/object-repository.js +1 -4
- package/lib/Utils/process-message.js +144 -148
- package/lib/Utils/signal.js +71 -64
- package/lib/Utils/use-multi-file-auth-state.js +112 -84
- package/lib/Utils/validate-connection.js +72 -115
- package/lib/WABinary/constants.js +1281 -20
- package/lib/WABinary/decode.js +15 -52
- package/lib/WABinary/encode.js +14 -48
- package/lib/WABinary/generic-utils.js +31 -39
- package/lib/WABinary/index.js +6 -21
- package/lib/WABinary/jid-utils.js +23 -40
- package/lib/WABinary/types.js +2 -2
- package/lib/WAM/BinaryInfo.js +2 -5
- package/lib/WAM/constants.js +2257 -2366
- package/lib/WAM/encode.js +17 -21
- package/lib/WAM/index.js +4 -19
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +8 -11
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +11 -14
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +9 -12
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +9 -13
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +20 -22
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +3 -6
- package/lib/WAUSync/Protocols/index.js +5 -20
- package/lib/WAUSync/USyncQuery.js +34 -32
- package/lib/WAUSync/USyncUser.js +2 -5
- package/lib/WAUSync/index.js +4 -19
- package/lib/index.js +11 -33
- package/package.json +25 -54
- package/WASignalGroup/GroupProtocol.js +0 -1697
- package/WASignalGroup/ciphertext_message.js +0 -16
- package/WASignalGroup/group_cipher.js +0 -120
- package/WASignalGroup/group_session_builder.js +0 -46
- package/WASignalGroup/index.js +0 -5
- package/WASignalGroup/keyhelper.js +0 -21
- package/WASignalGroup/protobufs.js +0 -3
- package/WASignalGroup/queue_job.js +0 -69
- package/WASignalGroup/sender_chain_key.js +0 -50
- package/WASignalGroup/sender_key_distribution_message.js +0 -78
- package/WASignalGroup/sender_key_message.js +0 -92
- package/WASignalGroup/sender_key_name.js +0 -70
- package/WASignalGroup/sender_key_record.js +0 -56
- package/WASignalGroup/sender_key_state.js +0 -129
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Defaults/phonenumber-mcc.json +0 -223
- package/lib/Socket/Client/abstract-socket-client.js +0 -13
- package/lib/Socket/Client/mobile-socket-client.js +0 -65
- package/lib/Socket/Client/web-socket-client.js +0 -62
- package/lib/Socket/registration.js +0 -166
- package/lib/Store/index.js +0 -8
- package/lib/Store/make-cache-manager-store.js +0 -83
- package/lib/Store/make-mongo-store.js +0 -567
package/lib/Socket/socket.js
CHANGED
|
@@ -1,65 +1,62 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const Utils_1 = require("../Utils");
|
|
12
|
-
const WABinary_1 = require("../WABinary");
|
|
13
|
-
const Client_1 = require("./Client");
|
|
1
|
+
import { Boom } from '@hapi/boom';
|
|
2
|
+
import { randomBytes } from 'crypto';
|
|
3
|
+
import { URL } from 'url';
|
|
4
|
+
import { promisify } from 'util';
|
|
5
|
+
import { proto } from '../../WAProto/index.js';
|
|
6
|
+
import { DEF_CALLBACK_PREFIX, DEF_TAG_PREFIX, INITIAL_PREKEY_COUNT, MIN_PREKEY_COUNT, NOISE_WA_HEADER } from '../Defaults/index.js';
|
|
7
|
+
import { DisconnectReason } from '../Types/index.js';
|
|
8
|
+
import { addTransactionCapability, aesEncryptCTR, bindWaitForConnectionUpdate, bytesToCrockford, configureSuccessfulPairing, Curve, derivePairingCodeKey, generateLoginNode, generateMdTagPrefix, generateRegistrationNode, getCodeFromWSError, getErrorCodeFromStreamError, getNextPreKeysNode, getPlatformId, makeEventBuffer, makeNoiseHandler, promiseTimeout } from '../Utils/index.js';
|
|
9
|
+
import { assertNodeErrorFree, binaryNodeToString, encodeBinaryNode, getBinaryNodeChild, getBinaryNodeChildren, jidEncode, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
10
|
+
import { WebSocketClient } from './Client/index.js';
|
|
14
11
|
/**
|
|
15
12
|
* Connects to WA servers and performs:
|
|
16
13
|
* - simple queries (no retry mechanism, wait for connection establishment)
|
|
17
14
|
* - listen to messages and emit events
|
|
18
15
|
* - query phone connection
|
|
19
16
|
*/
|
|
20
|
-
const makeSocket = (config) => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
export const makeSocket = (config) => {
|
|
18
|
+
const { waWebSocketUrl, connectTimeoutMs, logger, keepAliveIntervalMs, browser, auth: authState, printQRInTerminal, defaultQueryTimeoutMs, transactionOpts, qrTimeout, makeSignalRepository } = config;
|
|
19
|
+
if (printQRInTerminal) {
|
|
20
|
+
console.warn('⚠️ The printQRInTerminal option has been deprecated. You will no longer receive QR codes in the terminal automatically. Please listen to the connection.update event yourself and handle the QR your way. You can remove this message by removing this opttion. This message will be removed in a future version.');
|
|
21
|
+
}
|
|
22
|
+
const url = typeof waWebSocketUrl === 'string' ? new URL(waWebSocketUrl) : waWebSocketUrl;
|
|
23
|
+
if (config.mobile || url.protocol === 'tcp:') {
|
|
24
|
+
throw new Boom('Mobile API is not supported anymore', { statusCode: DisconnectReason.loggedOut });
|
|
27
25
|
}
|
|
28
|
-
if (
|
|
26
|
+
if (url.protocol === 'wss' && authState?.creds?.routingInfo) {
|
|
29
27
|
url.searchParams.append('ED', authState.creds.routingInfo.toString('base64url'));
|
|
30
28
|
}
|
|
31
|
-
const ws =
|
|
29
|
+
const ws = new WebSocketClient(url, config);
|
|
32
30
|
ws.connect();
|
|
33
|
-
const ev =
|
|
31
|
+
const ev = makeEventBuffer(logger);
|
|
34
32
|
/** ephemeral key pair used to encrypt/decrypt communication. Unique for each connection */
|
|
35
|
-
const ephemeralKeyPair =
|
|
33
|
+
const ephemeralKeyPair = Curve.generateKeyPair();
|
|
36
34
|
/** WA noise protocol wrapper */
|
|
37
|
-
const noise =
|
|
35
|
+
const noise = makeNoiseHandler({
|
|
38
36
|
keyPair: ephemeralKeyPair,
|
|
39
|
-
NOISE_HEADER:
|
|
40
|
-
mobile: config.mobile,
|
|
37
|
+
NOISE_HEADER: NOISE_WA_HEADER,
|
|
41
38
|
logger,
|
|
42
|
-
routingInfo:
|
|
39
|
+
routingInfo: authState?.creds?.routingInfo
|
|
43
40
|
});
|
|
44
41
|
const { creds } = authState;
|
|
45
42
|
// add transaction capability
|
|
46
|
-
const keys =
|
|
43
|
+
const keys = addTransactionCapability(authState.keys, logger, transactionOpts);
|
|
47
44
|
const signalRepository = makeSignalRepository({ creds, keys });
|
|
48
45
|
let lastDateRecv;
|
|
49
46
|
let epoch = 1;
|
|
50
47
|
let keepAliveReq;
|
|
51
48
|
let qrTimer;
|
|
52
49
|
let closed = false;
|
|
53
|
-
const uqTagId =
|
|
50
|
+
const uqTagId = generateMdTagPrefix();
|
|
54
51
|
const generateMessageTag = () => `${uqTagId}${epoch++}`;
|
|
55
|
-
const sendPromise =
|
|
52
|
+
const sendPromise = promisify(ws.send);
|
|
56
53
|
/** send a raw buffer */
|
|
57
54
|
const sendRawMessage = async (data) => {
|
|
58
55
|
if (!ws.isOpen) {
|
|
59
|
-
throw new
|
|
56
|
+
throw new Boom('Connection Closed', { statusCode: DisconnectReason.connectionClosed });
|
|
60
57
|
}
|
|
61
58
|
const bytes = noise.encodeFrame(data);
|
|
62
|
-
await
|
|
59
|
+
await promiseTimeout(connectTimeoutMs, async (resolve, reject) => {
|
|
63
60
|
try {
|
|
64
61
|
await sendPromise.call(ws, bytes);
|
|
65
62
|
resolve();
|
|
@@ -72,9 +69,9 @@ const makeSocket = (config) => {
|
|
|
72
69
|
/** send a binary node */
|
|
73
70
|
const sendNode = (frame) => {
|
|
74
71
|
if (logger.level === 'trace') {
|
|
75
|
-
logger.trace({ xml:
|
|
72
|
+
logger.trace({ xml: binaryNodeToString(frame), msg: 'xml send' });
|
|
76
73
|
}
|
|
77
|
-
const buff =
|
|
74
|
+
const buff = encodeBinaryNode(frame);
|
|
78
75
|
return sendRawMessage(buff);
|
|
79
76
|
};
|
|
80
77
|
/** log & process any unexpected errors */
|
|
@@ -84,20 +81,19 @@ const makeSocket = (config) => {
|
|
|
84
81
|
/** await the next incoming message */
|
|
85
82
|
const awaitNextMessage = async (sendMsg) => {
|
|
86
83
|
if (!ws.isOpen) {
|
|
87
|
-
throw new
|
|
88
|
-
statusCode:
|
|
84
|
+
throw new Boom('Connection Closed', {
|
|
85
|
+
statusCode: DisconnectReason.connectionClosed
|
|
89
86
|
});
|
|
90
87
|
}
|
|
91
88
|
let onOpen;
|
|
92
89
|
let onClose;
|
|
93
|
-
const result =
|
|
90
|
+
const result = promiseTimeout(connectTimeoutMs, (resolve, reject) => {
|
|
94
91
|
onOpen = resolve;
|
|
95
92
|
onClose = mapWebSocketError(reject);
|
|
96
93
|
ws.on('frame', onOpen);
|
|
97
94
|
ws.on('close', onClose);
|
|
98
95
|
ws.on('error', onClose);
|
|
99
|
-
})
|
|
100
|
-
.finally(() => {
|
|
96
|
+
}).finally(() => {
|
|
101
97
|
ws.off('frame', onOpen);
|
|
102
98
|
ws.off('close', onClose);
|
|
103
99
|
ws.off('error', onClose);
|
|
@@ -116,10 +112,10 @@ const makeSocket = (config) => {
|
|
|
116
112
|
let onRecv;
|
|
117
113
|
let onErr;
|
|
118
114
|
try {
|
|
119
|
-
const result = await
|
|
115
|
+
const result = await promiseTimeout(timeoutMs, (resolve, reject) => {
|
|
120
116
|
onRecv = resolve;
|
|
121
117
|
onErr = err => {
|
|
122
|
-
reject(err || new
|
|
118
|
+
reject(err || new Boom('Connection Closed', { statusCode: DisconnectReason.connectionClosed }));
|
|
123
119
|
};
|
|
124
120
|
ws.on(`TAG:${msgId}`, onRecv);
|
|
125
121
|
ws.on('close', onErr); // if the socket closes, you'll never receive the message
|
|
@@ -139,12 +135,9 @@ const makeSocket = (config) => {
|
|
|
139
135
|
node.attrs.id = generateMessageTag();
|
|
140
136
|
}
|
|
141
137
|
const msgId = node.attrs.id;
|
|
142
|
-
const [result] = await Promise.all([
|
|
143
|
-
waitForMessage(msgId, timeoutMs),
|
|
144
|
-
sendNode(node)
|
|
145
|
-
]);
|
|
138
|
+
const [result] = await Promise.all([waitForMessage(msgId, timeoutMs), sendNode(node)]);
|
|
146
139
|
if ('tag' in result) {
|
|
147
|
-
|
|
140
|
+
assertNodeErrorFree(result);
|
|
148
141
|
}
|
|
149
142
|
return result;
|
|
150
143
|
};
|
|
@@ -153,31 +146,28 @@ const makeSocket = (config) => {
|
|
|
153
146
|
let helloMsg = {
|
|
154
147
|
clientHello: { ephemeral: ephemeralKeyPair.public }
|
|
155
148
|
};
|
|
156
|
-
helloMsg =
|
|
149
|
+
helloMsg = proto.HandshakeMessage.fromObject(helloMsg);
|
|
157
150
|
logger.info({ browser, helloMsg }, 'connected to WA');
|
|
158
|
-
const init =
|
|
151
|
+
const init = proto.HandshakeMessage.encode(helloMsg).finish();
|
|
159
152
|
const result = await awaitNextMessage(init);
|
|
160
|
-
const handshake =
|
|
153
|
+
const handshake = proto.HandshakeMessage.decode(result);
|
|
161
154
|
logger.trace({ handshake }, 'handshake recv from WA');
|
|
162
155
|
const keyEnc = await noise.processHandshake(handshake, creds.noiseKey);
|
|
163
156
|
let node;
|
|
164
|
-
if (
|
|
165
|
-
node = (
|
|
166
|
-
}
|
|
167
|
-
else if (!creds.me) {
|
|
168
|
-
node = (0, Utils_1.generateRegistrationNode)(creds, config);
|
|
157
|
+
if (!creds.me) {
|
|
158
|
+
node = generateRegistrationNode(creds, config);
|
|
169
159
|
logger.info({ node }, 'not logged in, attempting registration...');
|
|
170
160
|
}
|
|
171
161
|
else {
|
|
172
|
-
node =
|
|
162
|
+
node = generateLoginNode(creds.me.id, config);
|
|
173
163
|
logger.info({ node }, 'logging in...');
|
|
174
164
|
}
|
|
175
|
-
const payloadEnc = noise.encrypt(
|
|
176
|
-
await sendRawMessage(
|
|
165
|
+
const payloadEnc = noise.encrypt(proto.ClientPayload.encode(node).finish());
|
|
166
|
+
await sendRawMessage(proto.HandshakeMessage.encode({
|
|
177
167
|
clientFinish: {
|
|
178
168
|
static: keyEnc,
|
|
179
|
-
payload: payloadEnc
|
|
180
|
-
}
|
|
169
|
+
payload: payloadEnc
|
|
170
|
+
}
|
|
181
171
|
}).finish());
|
|
182
172
|
noise.finishInit();
|
|
183
173
|
startKeepAliveRequest();
|
|
@@ -189,20 +179,18 @@ const makeSocket = (config) => {
|
|
|
189
179
|
id: generateMessageTag(),
|
|
190
180
|
xmlns: 'encrypt',
|
|
191
181
|
type: 'get',
|
|
192
|
-
to:
|
|
182
|
+
to: S_WHATSAPP_NET
|
|
193
183
|
},
|
|
194
|
-
content: [
|
|
195
|
-
{ tag: 'count', attrs: {} }
|
|
196
|
-
]
|
|
184
|
+
content: [{ tag: 'count', attrs: {} }]
|
|
197
185
|
});
|
|
198
|
-
const countChild =
|
|
186
|
+
const countChild = getBinaryNodeChild(result, 'count');
|
|
199
187
|
return +countChild.attrs.value;
|
|
200
188
|
};
|
|
201
189
|
/** generates and uploads a set of pre-keys to the server */
|
|
202
|
-
const uploadPreKeys = async (count =
|
|
190
|
+
const uploadPreKeys = async (count = INITIAL_PREKEY_COUNT) => {
|
|
203
191
|
await keys.transaction(async () => {
|
|
204
192
|
logger.info({ count }, 'uploading pre-keys');
|
|
205
|
-
const { update, node } = await
|
|
193
|
+
const { update, node } = await getNextPreKeysNode({ creds, keys }, count);
|
|
206
194
|
await query(node);
|
|
207
195
|
ev.emit('creds.update', update);
|
|
208
196
|
logger.info({ count }, 'uploaded pre-keys');
|
|
@@ -211,13 +199,12 @@ const makeSocket = (config) => {
|
|
|
211
199
|
const uploadPreKeysToServerIfRequired = async () => {
|
|
212
200
|
const preKeyCount = await getAvailablePreKeysOnServer();
|
|
213
201
|
logger.info(`${preKeyCount} pre-keys found on server`);
|
|
214
|
-
if (preKeyCount <=
|
|
202
|
+
if (preKeyCount <= MIN_PREKEY_COUNT) {
|
|
215
203
|
await uploadPreKeys();
|
|
216
204
|
}
|
|
217
205
|
};
|
|
218
206
|
const onMessageReceived = (data) => {
|
|
219
207
|
noise.decodeFrame(data, frame => {
|
|
220
|
-
var _a;
|
|
221
208
|
// reset ping timeout
|
|
222
209
|
lastDateRecv = new Date();
|
|
223
210
|
let anyTriggered = false;
|
|
@@ -226,21 +213,21 @@ const makeSocket = (config) => {
|
|
|
226
213
|
if (!(frame instanceof Uint8Array)) {
|
|
227
214
|
const msgId = frame.attrs.id;
|
|
228
215
|
if (logger.level === 'trace') {
|
|
229
|
-
logger.trace({ xml:
|
|
216
|
+
logger.trace({ xml: binaryNodeToString(frame), msg: 'recv xml' });
|
|
230
217
|
}
|
|
231
218
|
/* Check if this is a response to a message we sent */
|
|
232
|
-
anyTriggered = ws.emit(`${
|
|
219
|
+
anyTriggered = ws.emit(`${DEF_TAG_PREFIX}${msgId}`, frame) || anyTriggered;
|
|
233
220
|
/* Check if this is a response to a message we are expecting */
|
|
234
221
|
const l0 = frame.tag;
|
|
235
222
|
const l1 = frame.attrs || {};
|
|
236
|
-
const l2 = Array.isArray(frame.content) ?
|
|
237
|
-
Object.keys(l1)
|
|
238
|
-
anyTriggered = ws.emit(`${
|
|
239
|
-
anyTriggered = ws.emit(`${
|
|
240
|
-
anyTriggered = ws.emit(`${
|
|
241
|
-
}
|
|
242
|
-
anyTriggered = ws.emit(`${
|
|
243
|
-
anyTriggered = ws.emit(`${
|
|
223
|
+
const l2 = Array.isArray(frame.content) ? frame.content[0]?.tag : '';
|
|
224
|
+
for (const key of Object.keys(l1)) {
|
|
225
|
+
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]},${l2}`, frame) || anyTriggered;
|
|
226
|
+
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]}`, frame) || anyTriggered;
|
|
227
|
+
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}`, frame) || anyTriggered;
|
|
228
|
+
}
|
|
229
|
+
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},,${l2}`, frame) || anyTriggered;
|
|
230
|
+
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0}`, frame) || anyTriggered;
|
|
244
231
|
if (!anyTriggered && logger.level === 'debug') {
|
|
245
232
|
logger.debug({ unhandled: true, msgId, fromMe: false, frame }, 'communication recv');
|
|
246
233
|
}
|
|
@@ -249,22 +236,21 @@ const makeSocket = (config) => {
|
|
|
249
236
|
};
|
|
250
237
|
const end = (error) => {
|
|
251
238
|
if (closed) {
|
|
252
|
-
logger.trace({ trace: error
|
|
239
|
+
logger.trace({ trace: error?.stack }, 'connection already closed');
|
|
253
240
|
return;
|
|
254
241
|
}
|
|
255
242
|
closed = true;
|
|
256
|
-
logger.info({ trace: error
|
|
243
|
+
logger.info({ trace: error?.stack }, error ? 'connection errored' : 'connection closed');
|
|
257
244
|
clearInterval(keepAliveReq);
|
|
258
245
|
clearTimeout(qrTimer);
|
|
259
246
|
ws.removeAllListeners('close');
|
|
260
|
-
ws.removeAllListeners('error');
|
|
261
247
|
ws.removeAllListeners('open');
|
|
262
248
|
ws.removeAllListeners('message');
|
|
263
249
|
if (!ws.isClosed && !ws.isClosing) {
|
|
264
250
|
try {
|
|
265
251
|
ws.close();
|
|
266
252
|
}
|
|
267
|
-
catch
|
|
253
|
+
catch { }
|
|
268
254
|
}
|
|
269
255
|
ev.emit('connection.update', {
|
|
270
256
|
connection: 'close',
|
|
@@ -280,7 +266,7 @@ const makeSocket = (config) => {
|
|
|
280
266
|
return;
|
|
281
267
|
}
|
|
282
268
|
if (ws.isClosed || ws.isClosing) {
|
|
283
|
-
throw new
|
|
269
|
+
throw new Boom('Connection Closed', { statusCode: DisconnectReason.connectionClosed });
|
|
284
270
|
}
|
|
285
271
|
let onOpen;
|
|
286
272
|
let onClose;
|
|
@@ -290,8 +276,7 @@ const makeSocket = (config) => {
|
|
|
290
276
|
ws.on('open', onOpen);
|
|
291
277
|
ws.on('close', onClose);
|
|
292
278
|
ws.on('error', onClose);
|
|
293
|
-
})
|
|
294
|
-
.finally(() => {
|
|
279
|
+
}).finally(() => {
|
|
295
280
|
ws.off('open', onOpen);
|
|
296
281
|
ws.off('close', onClose);
|
|
297
282
|
ws.off('error', onClose);
|
|
@@ -307,7 +292,7 @@ const makeSocket = (config) => {
|
|
|
307
292
|
it could be that the network is down
|
|
308
293
|
*/
|
|
309
294
|
if (diff > keepAliveIntervalMs + 5000) {
|
|
310
|
-
end(new
|
|
295
|
+
end(new Boom('Connection was lost', { statusCode: DisconnectReason.connectionLost }));
|
|
311
296
|
}
|
|
312
297
|
else if (ws.isOpen) {
|
|
313
298
|
// if its all good, send a keep alive request
|
|
@@ -315,13 +300,12 @@ const makeSocket = (config) => {
|
|
|
315
300
|
tag: 'iq',
|
|
316
301
|
attrs: {
|
|
317
302
|
id: generateMessageTag(),
|
|
318
|
-
to:
|
|
303
|
+
to: S_WHATSAPP_NET,
|
|
319
304
|
type: 'get',
|
|
320
|
-
xmlns: 'w:p'
|
|
305
|
+
xmlns: 'w:p'
|
|
321
306
|
},
|
|
322
307
|
content: [{ tag: 'ping', attrs: {} }]
|
|
323
|
-
})
|
|
324
|
-
.catch(err => {
|
|
308
|
+
}).catch(err => {
|
|
325
309
|
logger.error({ trace: err.stack }, 'error in sending keep alive');
|
|
326
310
|
});
|
|
327
311
|
}
|
|
@@ -330,26 +314,23 @@ const makeSocket = (config) => {
|
|
|
330
314
|
}
|
|
331
315
|
}, keepAliveIntervalMs));
|
|
332
316
|
/** i have no idea why this exists. pls enlighten me */
|
|
333
|
-
const sendPassiveIq = (tag) =>
|
|
317
|
+
const sendPassiveIq = (tag) => query({
|
|
334
318
|
tag: 'iq',
|
|
335
319
|
attrs: {
|
|
336
|
-
to:
|
|
320
|
+
to: S_WHATSAPP_NET,
|
|
337
321
|
xmlns: 'passive',
|
|
338
|
-
type: 'set'
|
|
322
|
+
type: 'set'
|
|
339
323
|
},
|
|
340
|
-
content: [
|
|
341
|
-
|
|
342
|
-
]
|
|
343
|
-
}));
|
|
324
|
+
content: [{ tag, attrs: {} }]
|
|
325
|
+
});
|
|
344
326
|
/** logout & invalidate connection */
|
|
345
327
|
const logout = async (msg) => {
|
|
346
|
-
|
|
347
|
-
const jid = (_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id;
|
|
328
|
+
const jid = authState.creds.me?.id;
|
|
348
329
|
if (jid) {
|
|
349
330
|
await sendNode({
|
|
350
331
|
tag: 'iq',
|
|
351
332
|
attrs: {
|
|
352
|
-
to:
|
|
333
|
+
to: S_WHATSAPP_NET,
|
|
353
334
|
type: 'set',
|
|
354
335
|
id: generateMessageTag(),
|
|
355
336
|
xmlns: 'md'
|
|
@@ -365,24 +346,23 @@ const makeSocket = (config) => {
|
|
|
365
346
|
]
|
|
366
347
|
});
|
|
367
348
|
}
|
|
368
|
-
end(new
|
|
349
|
+
end(new Boom(msg || 'Intentional Logout', { statusCode: DisconnectReason.loggedOut }));
|
|
369
350
|
};
|
|
370
|
-
const requestPairingCode = async (phoneNumber,
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
else {
|
|
375
|
-
authState.creds.pairingCode = (0, Utils_1.bytesToCrockford)((0, crypto_1.randomBytes)(5));
|
|
351
|
+
const requestPairingCode = async (phoneNumber, customPairingCode) => {
|
|
352
|
+
const pairingCode = customPairingCode ?? bytesToCrockford(randomBytes(5));
|
|
353
|
+
if (customPairingCode && customPairingCode?.length !== 8) {
|
|
354
|
+
throw new Error('Custom pairing code must be exactly 8 chars');
|
|
376
355
|
}
|
|
356
|
+
authState.creds.pairingCode = pairingCode;
|
|
377
357
|
authState.creds.me = {
|
|
378
|
-
id:
|
|
358
|
+
id: jidEncode(phoneNumber, 's.whatsapp.net'),
|
|
379
359
|
name: '~'
|
|
380
360
|
};
|
|
381
361
|
ev.emit('creds.update', authState.creds);
|
|
382
362
|
await sendNode({
|
|
383
363
|
tag: 'iq',
|
|
384
364
|
attrs: {
|
|
385
|
-
to:
|
|
365
|
+
to: S_WHATSAPP_NET,
|
|
386
366
|
type: 'set',
|
|
387
367
|
id: generateMessageTag(),
|
|
388
368
|
xmlns: 'md'
|
|
@@ -393,7 +373,6 @@ const makeSocket = (config) => {
|
|
|
393
373
|
attrs: {
|
|
394
374
|
jid: authState.creds.me.id,
|
|
395
375
|
stage: 'companion_hello',
|
|
396
|
-
// eslint-disable-next-line camelcase
|
|
397
376
|
should_show_push_notification: 'true'
|
|
398
377
|
},
|
|
399
378
|
content: [
|
|
@@ -410,7 +389,7 @@ const makeSocket = (config) => {
|
|
|
410
389
|
{
|
|
411
390
|
tag: 'companion_platform_id',
|
|
412
391
|
attrs: {},
|
|
413
|
-
content:
|
|
392
|
+
content: getPlatformId(browser[1])
|
|
414
393
|
},
|
|
415
394
|
{
|
|
416
395
|
tag: 'companion_platform_display',
|
|
@@ -429,17 +408,17 @@ const makeSocket = (config) => {
|
|
|
429
408
|
return authState.creds.pairingCode;
|
|
430
409
|
};
|
|
431
410
|
async function generatePairingKey() {
|
|
432
|
-
const salt =
|
|
433
|
-
const randomIv =
|
|
434
|
-
const key = await
|
|
435
|
-
const ciphered =
|
|
411
|
+
const salt = randomBytes(32);
|
|
412
|
+
const randomIv = randomBytes(16);
|
|
413
|
+
const key = await derivePairingCodeKey(authState.creds.pairingCode, salt);
|
|
414
|
+
const ciphered = aesEncryptCTR(authState.creds.pairingEphemeralKeyPair.public, key, randomIv);
|
|
436
415
|
return Buffer.concat([salt, randomIv, ciphered]);
|
|
437
416
|
}
|
|
438
417
|
const sendWAMBuffer = (wamBuffer) => {
|
|
439
418
|
return query({
|
|
440
419
|
tag: 'iq',
|
|
441
420
|
attrs: {
|
|
442
|
-
to:
|
|
421
|
+
to: S_WHATSAPP_NET,
|
|
443
422
|
id: generateMessageTag(),
|
|
444
423
|
xmlns: 'w:stats'
|
|
445
424
|
},
|
|
@@ -463,22 +442,22 @@ const makeSocket = (config) => {
|
|
|
463
442
|
}
|
|
464
443
|
});
|
|
465
444
|
ws.on('error', mapWebSocketError(end));
|
|
466
|
-
ws.on('close', () => end(new
|
|
445
|
+
ws.on('close', () => end(new Boom('Connection Terminated', { statusCode: DisconnectReason.connectionClosed })));
|
|
467
446
|
// the server terminated the connection
|
|
468
|
-
ws.on('CB:xmlstreamend', () => end(new
|
|
447
|
+
ws.on('CB:xmlstreamend', () => end(new Boom('Connection Terminated by Server', { statusCode: DisconnectReason.connectionClosed })));
|
|
469
448
|
// QR gen
|
|
470
449
|
ws.on('CB:iq,type:set,pair-device', async (stanza) => {
|
|
471
450
|
const iq = {
|
|
472
451
|
tag: 'iq',
|
|
473
452
|
attrs: {
|
|
474
|
-
to:
|
|
453
|
+
to: S_WHATSAPP_NET,
|
|
475
454
|
type: 'result',
|
|
476
|
-
id: stanza.attrs.id
|
|
455
|
+
id: stanza.attrs.id
|
|
477
456
|
}
|
|
478
457
|
};
|
|
479
458
|
await sendNode(iq);
|
|
480
|
-
const pairDeviceNode =
|
|
481
|
-
const refNodes =
|
|
459
|
+
const pairDeviceNode = getBinaryNodeChild(stanza, 'pair-device');
|
|
460
|
+
const refNodes = getBinaryNodeChildren(pairDeviceNode, 'ref');
|
|
482
461
|
const noiseKeyB64 = Buffer.from(creds.noiseKey.public).toString('base64');
|
|
483
462
|
const identityKeyB64 = Buffer.from(creds.signedIdentityKey.public).toString('base64');
|
|
484
463
|
const advB64 = creds.advSecretKey;
|
|
@@ -489,7 +468,7 @@ const makeSocket = (config) => {
|
|
|
489
468
|
}
|
|
490
469
|
const refNode = refNodes.shift();
|
|
491
470
|
if (!refNode) {
|
|
492
|
-
end(new
|
|
471
|
+
end(new Boom('QR refs attempts ended', { statusCode: DisconnectReason.timedOut }));
|
|
493
472
|
return;
|
|
494
473
|
}
|
|
495
474
|
const ref = refNode.content.toString('utf-8');
|
|
@@ -505,7 +484,7 @@ const makeSocket = (config) => {
|
|
|
505
484
|
ws.on('CB:iq,,pair-success', async (stanza) => {
|
|
506
485
|
logger.debug('pair success recv');
|
|
507
486
|
try {
|
|
508
|
-
const { reply, creds: updatedCreds } =
|
|
487
|
+
const { reply, creds: updatedCreds } = configureSuccessfulPairing(stanza, creds);
|
|
509
488
|
logger.info({ me: updatedCreds.me, platform: updatedCreds.platform }, 'pairing configured successfully, expect to restart the connection...');
|
|
510
489
|
ev.emit('creds.update', updatedCreds);
|
|
511
490
|
ev.emit('connection.update', { isNewLogin: true, qr: undefined });
|
|
@@ -518,31 +497,25 @@ const makeSocket = (config) => {
|
|
|
518
497
|
});
|
|
519
498
|
// login complete
|
|
520
499
|
ws.on('CB:success', async (node) => {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
ev.emit('connection.update', { connection: 'open' });
|
|
528
|
-
}
|
|
529
|
-
catch (err) {
|
|
530
|
-
logger.error({ err }, 'error opening connection');
|
|
531
|
-
end(err);
|
|
532
|
-
}
|
|
500
|
+
await uploadPreKeysToServerIfRequired();
|
|
501
|
+
await sendPassiveIq('active');
|
|
502
|
+
logger.info('opened connection to WA');
|
|
503
|
+
clearTimeout(qrTimer); // will never happen in all likelyhood -- but just in case WA sends success on first try
|
|
504
|
+
ev.emit('creds.update', { me: { ...authState.creds.me, lid: node.attrs.lid } });
|
|
505
|
+
ev.emit('connection.update', { connection: 'open' });
|
|
533
506
|
});
|
|
534
507
|
ws.on('CB:stream:error', (node) => {
|
|
535
508
|
logger.error({ node }, 'stream errored out');
|
|
536
|
-
const { reason, statusCode } =
|
|
537
|
-
end(new
|
|
509
|
+
const { reason, statusCode } = getErrorCodeFromStreamError(node);
|
|
510
|
+
end(new Boom(`Stream Errored (${reason})`, { statusCode, data: node }));
|
|
538
511
|
});
|
|
539
512
|
// stream fail, possible logout
|
|
540
513
|
ws.on('CB:failure', (node) => {
|
|
541
514
|
const reason = +(node.attrs.reason || 500);
|
|
542
|
-
end(new
|
|
515
|
+
end(new Boom('Connection Failure', { statusCode: reason, data: node.attrs }));
|
|
543
516
|
});
|
|
544
517
|
ws.on('CB:ib,,downgrade_webclient', () => {
|
|
545
|
-
end(new
|
|
518
|
+
end(new Boom('Multi-device beta not joined', { statusCode: DisconnectReason.multideviceMismatch }));
|
|
546
519
|
});
|
|
547
520
|
ws.on('CB:ib,,offline_preview', (node) => {
|
|
548
521
|
logger.info('offline preview received', JSON.stringify(node));
|
|
@@ -553,17 +526,16 @@ const makeSocket = (config) => {
|
|
|
553
526
|
});
|
|
554
527
|
});
|
|
555
528
|
ws.on('CB:ib,,edge_routing', (node) => {
|
|
556
|
-
const edgeRoutingNode =
|
|
557
|
-
const routingInfo =
|
|
558
|
-
if (routingInfo
|
|
559
|
-
authState.creds.routingInfo = Buffer.from(routingInfo
|
|
529
|
+
const edgeRoutingNode = getBinaryNodeChild(node, 'edge_routing');
|
|
530
|
+
const routingInfo = getBinaryNodeChild(edgeRoutingNode, 'routing_info');
|
|
531
|
+
if (routingInfo?.content) {
|
|
532
|
+
authState.creds.routingInfo = Buffer.from(routingInfo?.content);
|
|
560
533
|
ev.emit('creds.update', authState.creds);
|
|
561
534
|
}
|
|
562
535
|
});
|
|
563
536
|
let didStartBuffer = false;
|
|
564
537
|
process.nextTick(() => {
|
|
565
|
-
|
|
566
|
-
if ((_a = creds.me) === null || _a === void 0 ? void 0 : _a.id) {
|
|
538
|
+
if (creds.me?.id) {
|
|
567
539
|
// start buffering important events
|
|
568
540
|
// if we're logged in
|
|
569
541
|
ev.buffer();
|
|
@@ -573,8 +545,8 @@ const makeSocket = (config) => {
|
|
|
573
545
|
});
|
|
574
546
|
// called when all offline notifs are handled
|
|
575
547
|
ws.on('CB:ib,,offline', (node) => {
|
|
576
|
-
const child =
|
|
577
|
-
const offlineNotifs = +(
|
|
548
|
+
const child = getBinaryNodeChild(node, 'offline');
|
|
549
|
+
const offlineNotifs = +(child?.attrs.count || 0);
|
|
578
550
|
logger.info(`handled ${offlineNotifs} offline messages/notifications`);
|
|
579
551
|
if (didStartBuffer) {
|
|
580
552
|
ev.flush();
|
|
@@ -584,24 +556,19 @@ const makeSocket = (config) => {
|
|
|
584
556
|
});
|
|
585
557
|
// update credentials when required
|
|
586
558
|
ev.on('creds.update', update => {
|
|
587
|
-
|
|
588
|
-
const name = (_a = update.me) === null || _a === void 0 ? void 0 : _a.name;
|
|
559
|
+
const name = update.me?.name;
|
|
589
560
|
// if name has just been received
|
|
590
|
-
if (
|
|
561
|
+
if (creds.me?.name !== name) {
|
|
591
562
|
logger.debug({ name }, 'updated pushName');
|
|
592
563
|
sendNode({
|
|
593
564
|
tag: 'presence',
|
|
594
565
|
attrs: { name: name }
|
|
595
|
-
})
|
|
596
|
-
.catch(err => {
|
|
566
|
+
}).catch(err => {
|
|
597
567
|
logger.warn({ trace: err.stack }, 'error in sending presence update on name change');
|
|
598
568
|
});
|
|
599
569
|
}
|
|
600
570
|
Object.assign(creds, update);
|
|
601
571
|
});
|
|
602
|
-
if (printQRInTerminal) {
|
|
603
|
-
(0, Utils_1.printQRIfNecessaryListener)(ev, logger);
|
|
604
|
-
}
|
|
605
572
|
return {
|
|
606
573
|
type: 'md',
|
|
607
574
|
ws,
|
|
@@ -624,17 +591,17 @@ const makeSocket = (config) => {
|
|
|
624
591
|
uploadPreKeysToServerIfRequired,
|
|
625
592
|
requestPairingCode,
|
|
626
593
|
/** Waits for the connection to WA to reach a state */
|
|
627
|
-
waitForConnectionUpdate:
|
|
628
|
-
sendWAMBuffer
|
|
594
|
+
waitForConnectionUpdate: bindWaitForConnectionUpdate(ev),
|
|
595
|
+
sendWAMBuffer
|
|
629
596
|
};
|
|
630
597
|
};
|
|
631
|
-
exports.makeSocket = makeSocket;
|
|
632
598
|
/**
|
|
633
599
|
* map the websocket error to the right type
|
|
634
600
|
* so it can be retried by the caller
|
|
635
601
|
* */
|
|
636
602
|
function mapWebSocketError(handler) {
|
|
637
603
|
return (error) => {
|
|
638
|
-
handler(new
|
|
604
|
+
handler(new Boom(`WebSocket Error (${error?.message})`, { statusCode: getCodeFromWSError(error), data: error }));
|
|
639
605
|
};
|
|
640
606
|
}
|
|
607
|
+
//# sourceMappingURL=socket.js.map
|