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