@shenira/baileysx 7.0.4
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.
Potentially problematic release.
This version of @shenira/baileysx might be problematic. Click here for more details.
- package/WAProto/index.js +169661 -0
- package/engine-requirements.js +10 -0
- package/lib/Defaults/baileys-version.json +3 -0
- package/lib/Defaults/index.d.ts +53 -0
- package/lib/Defaults/index.js +147 -0
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Signal/Group/ciphertext-message.d.ts +9 -0
- package/lib/Signal/Group/ciphertext-message.js +15 -0
- package/lib/Signal/Group/group-session-builder.d.ts +14 -0
- package/lib/Signal/Group/group-session-builder.js +64 -0
- package/lib/Signal/Group/group_cipher.d.ts +17 -0
- package/lib/Signal/Group/group_cipher.js +96 -0
- package/lib/Signal/Group/index.d.ts +11 -0
- package/lib/Signal/Group/index.js +57 -0
- package/lib/Signal/Group/keyhelper.d.ts +10 -0
- package/lib/Signal/Group/keyhelper.js +55 -0
- package/lib/Signal/Group/queue-job.d.ts +1 -0
- package/lib/Signal/Group/queue-job.js +57 -0
- package/lib/Signal/Group/sender-chain-key.d.ts +13 -0
- package/lib/Signal/Group/sender-chain-key.js +34 -0
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +66 -0
- package/lib/Signal/Group/sender-key-message.d.ts +18 -0
- package/lib/Signal/Group/sender-key-message.js +69 -0
- package/lib/Signal/Group/sender-key-name.d.ts +17 -0
- package/lib/Signal/Group/sender-key-name.js +51 -0
- package/lib/Signal/Group/sender-key-record.d.ts +30 -0
- package/lib/Signal/Group/sender-key-record.js +53 -0
- package/lib/Signal/Group/sender-key-state.d.ts +38 -0
- package/lib/Signal/Group/sender-key-state.js +99 -0
- package/lib/Signal/Group/sender-message-key.d.ts +11 -0
- package/lib/Signal/Group/sender-message-key.js +29 -0
- package/lib/Signal/libsignal.d.ts +3 -0
- package/lib/Signal/libsignal.js +174 -0
- package/lib/Socket/Client/abstract-socket-client.d.ts +17 -0
- package/lib/Socket/Client/abstract-socket-client.js +13 -0
- package/lib/Socket/Client/index.d.ts +3 -0
- package/lib/Socket/Client/index.js +19 -0
- 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/web-socket-client.d.ts +12 -0
- package/lib/Socket/Client/web-socket-client.js +62 -0
- package/lib/Socket/business.d.ts +171 -0
- package/lib/Socket/business.js +260 -0
- package/lib/Socket/chats.d.ts +267 -0
- package/lib/Socket/chats.js +1018 -0
- package/lib/Socket/dugong.d.ts +254 -0
- package/lib/Socket/dugong.js +514 -0
- package/lib/Socket/groups.d.ts +115 -0
- package/lib/Socket/groups.js +317 -0
- package/lib/Socket/index.d.ts +173 -0
- package/lib/Socket/index.js +11 -0
- package/lib/Socket/messages-recv.d.ts +161 -0
- package/lib/Socket/messages-recv.js +1110 -0
- package/lib/Socket/messages-send.d.ts +149 -0
- package/lib/Socket/messages-send.js +909 -0
- package/lib/Socket/newsletter.d.ts +134 -0
- package/lib/Socket/newsletter.js +347 -0
- package/lib/Socket/registration.d.ts +267 -0
- package/lib/Socket/registration.js +166 -0
- package/lib/Socket/socket.d.ts +43 -0
- package/lib/Socket/socket.js +727 -0
- package/lib/Socket/usync.d.ts +36 -0
- package/lib/Socket/usync.js +70 -0
- 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 +110 -0
- package/lib/Types/Auth.js +2 -0
- package/lib/Types/Call.d.ts +13 -0
- package/lib/Types/Call.js +2 -0
- package/lib/Types/Chat.d.ts +102 -0
- package/lib/Types/Chat.js +4 -0
- package/lib/Types/Contact.d.ts +19 -0
- package/lib/Types/Contact.js +2 -0
- package/lib/Types/Events.d.ts +157 -0
- package/lib/Types/Events.js +2 -0
- package/lib/Types/GroupMetadata.d.ts +55 -0
- package/lib/Types/GroupMetadata.js +2 -0
- package/lib/Types/Label.d.ts +35 -0
- package/lib/Types/Label.js +27 -0
- package/lib/Types/LabelAssociation.d.ts +29 -0
- package/lib/Types/LabelAssociation.js +9 -0
- package/lib/Types/Message.d.ts +273 -0
- package/lib/Types/Message.js +9 -0
- package/lib/Types/Newsletter.d.ts +103 -0
- package/lib/Types/Newsletter.js +38 -0
- package/lib/Types/Product.d.ts +78 -0
- package/lib/Types/Product.js +2 -0
- package/lib/Types/Signal.d.ts +57 -0
- package/lib/Types/Signal.js +2 -0
- package/lib/Types/Socket.d.ts +111 -0
- package/lib/Types/Socket.js +2 -0
- package/lib/Types/State.d.ts +27 -0
- package/lib/Types/State.js +2 -0
- package/lib/Types/USync.d.ts +25 -0
- package/lib/Types/USync.js +2 -0
- package/lib/Types/index.d.ts +57 -0
- package/lib/Types/index.js +42 -0
- package/lib/Utils/auth-utils.d.ts +18 -0
- package/lib/Utils/auth-utils.js +206 -0
- package/lib/Utils/baileys-event-stream.d.ts +16 -0
- package/lib/Utils/baileys-event-stream.js +63 -0
- package/lib/Utils/business.d.ts +22 -0
- package/lib/Utils/business.js +234 -0
- package/lib/Utils/chat-utils.d.ts +71 -0
- package/lib/Utils/chat-utils.js +729 -0
- package/lib/Utils/crypto.d.ts +41 -0
- package/lib/Utils/crypto.js +151 -0
- package/lib/Utils/decode-wa-message.d.ts +19 -0
- package/lib/Utils/decode-wa-message.js +198 -0
- package/lib/Utils/event-buffer.d.ts +35 -0
- package/lib/Utils/event-buffer.js +514 -0
- package/lib/Utils/generics.d.ts +92 -0
- package/lib/Utils/generics.js +423 -0
- package/lib/Utils/history.d.ts +15 -0
- package/lib/Utils/history.js +96 -0
- package/lib/Utils/index.d.ts +17 -0
- package/lib/Utils/index.js +33 -0
- package/lib/Utils/link-preview.d.ts +21 -0
- package/lib/Utils/link-preview.js +93 -0
- package/lib/Utils/logger.d.ts +4 -0
- package/lib/Utils/logger.js +7 -0
- package/lib/Utils/lt-hash.d.ts +12 -0
- package/lib/Utils/lt-hash.js +51 -0
- package/lib/Utils/make-mutex.d.ts +7 -0
- package/lib/Utils/make-mutex.js +43 -0
- package/lib/Utils/messages-media.d.ts +116 -0
- package/lib/Utils/messages-media.js +819 -0
- package/lib/Utils/messages.d.ts +77 -0
- package/lib/Utils/messages.js +816 -0
- package/lib/Utils/noise-handler.d.ts +21 -0
- package/lib/Utils/noise-handler.js +155 -0
- package/lib/Utils/process-message.d.ts +41 -0
- package/lib/Utils/process-message.js +321 -0
- package/lib/Utils/signal.d.ts +32 -0
- package/lib/Utils/signal.js +153 -0
- package/lib/Utils/use-multi-file-auth-state.d.ts +13 -0
- package/lib/Utils/use-multi-file-auth-state.js +119 -0
- package/lib/Utils/validate-connection.d.ts +11 -0
- package/lib/Utils/validate-connection.js +229 -0
- package/lib/WABinary/constants.d.ts +30 -0
- package/lib/WABinary/constants.js +40 -0
- package/lib/WABinary/decode.d.ts +7 -0
- package/lib/WABinary/decode.js +252 -0
- package/lib/WABinary/encode.d.ts +3 -0
- package/lib/WABinary/encode.js +265 -0
- package/lib/WABinary/generic-utils.d.ts +17 -0
- package/lib/WABinary/generic-utils.js +198 -0
- package/lib/WABinary/index.d.ts +5 -0
- package/lib/WABinary/index.js +21 -0
- package/lib/WABinary/jid-utils.d.ts +31 -0
- package/lib/WABinary/jid-utils.js +62 -0
- package/lib/WABinary/types.d.ts +18 -0
- package/lib/WABinary/types.js +2 -0
- package/lib/WAM/BinaryInfo.d.ts +17 -0
- package/lib/WAM/BinaryInfo.js +13 -0
- package/lib/WAM/constants.d.ts +38 -0
- package/lib/WAM/constants.js +15350 -0
- package/lib/WAM/encode.d.ts +3 -0
- package/lib/WAM/encode.js +155 -0
- package/lib/WAM/index.d.ts +3 -0
- package/lib/WAM/index.js +19 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +32 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +57 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +30 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +42 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +25 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +53 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +8 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +24 -0
- package/lib/WAUSync/Protocols/index.d.ts +4 -0
- package/lib/WAUSync/Protocols/index.js +20 -0
- package/lib/WAUSync/USyncQuery.d.ts +28 -0
- package/lib/WAUSync/USyncQuery.js +89 -0
- package/lib/WAUSync/USyncUser.d.ts +12 -0
- package/lib/WAUSync/USyncUser.js +26 -0
- package/lib/WAUSync/index.d.ts +3 -0
- package/lib/WAUSync/index.js +19 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.js +90 -0
- package/package.json +114 -0
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const boom_1 = require("@hapi/boom");
|
|
3
|
+
const crypto_1 = require("crypto");
|
|
4
|
+
const url_1 = require("url");
|
|
5
|
+
const util_1 = require("util");
|
|
6
|
+
const WAProto_1 = require("../../WAProto");
|
|
7
|
+
const Defaults_1 = require("../Defaults");
|
|
8
|
+
const Types_1 = require("../Types");
|
|
9
|
+
const Utils_1 = require("../Utils");
|
|
10
|
+
const WABinary_1 = require("../WABinary");
|
|
11
|
+
const Client_1 = require("./Client");
|
|
12
|
+
|
|
13
|
+
const makeSocket = (config) => {
|
|
14
|
+
const {
|
|
15
|
+
waWebSocketUrl,
|
|
16
|
+
connectTimeoutMs,
|
|
17
|
+
logger,
|
|
18
|
+
keepAliveIntervalMs,
|
|
19
|
+
browser,
|
|
20
|
+
authState,
|
|
21
|
+
printQRInTerminal,
|
|
22
|
+
defaultQueryTimeoutMs,
|
|
23
|
+
transactionOpts,
|
|
24
|
+
qrTimeout,
|
|
25
|
+
makeSignalRepository
|
|
26
|
+
} = config;
|
|
27
|
+
|
|
28
|
+
const url = typeof waWebSocketUrl === 'string'
|
|
29
|
+
? new url_1.URL(waWebSocketUrl)
|
|
30
|
+
: waWebSocketUrl;
|
|
31
|
+
|
|
32
|
+
// Validasi URL
|
|
33
|
+
if (config.rejectUnauthorized || url.protocol === 'http:') {
|
|
34
|
+
throw new boom_1.Boom('Invalid WebSocket URL', {
|
|
35
|
+
statusCode: Types_1.DisconnectReason.badSession
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Tambahkan auth state ke URL jika ada
|
|
40
|
+
if (url.protocol === 'ws:' && authState?.creds?.deviceSecret) {
|
|
41
|
+
url.searchParams.set('ED', authState.creds.deviceSecret.toString('base64'));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Inisialisasi WebSocket
|
|
45
|
+
const ws = new Client_1.WebSocketClient(url, config);
|
|
46
|
+
ws.connect();
|
|
47
|
+
|
|
48
|
+
// Event emitter
|
|
49
|
+
const ev = Utils_1.makeEventEmitter(logger);
|
|
50
|
+
|
|
51
|
+
// Generate ephemeral key pair untuk noise handshake
|
|
52
|
+
const ephemeralKeyPair = Utils_1.Curve.generateKeyPair();
|
|
53
|
+
|
|
54
|
+
// Inisialisasi noise protocol
|
|
55
|
+
const noise = Utils_1.makeNoiseHandler({
|
|
56
|
+
ephemeralKeyPair,
|
|
57
|
+
staticKeyPairs: Defaults_1.KEY_BUNDLE_TYPE,
|
|
58
|
+
logger,
|
|
59
|
+
deviceSecret: authState?.creds?.deviceSecret
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const { creds } = authState;
|
|
63
|
+
const keys = Utils_1.makeKeyStore(authState.keys, logger, transactionOpts);
|
|
64
|
+
const signalRepository = makeSignalRepository({ creds, keys });
|
|
65
|
+
|
|
66
|
+
let lastDateRecv;
|
|
67
|
+
let epoch = 1;
|
|
68
|
+
let keepAliveReq;
|
|
69
|
+
let qrTimer;
|
|
70
|
+
let closed = false;
|
|
71
|
+
|
|
72
|
+
// Generate unique tag ID untuk message
|
|
73
|
+
const uqTagId = Utils_1.generateMessageTag();
|
|
74
|
+
const generateMessageTag = () => {
|
|
75
|
+
return `${uqTagId}${epoch++}`;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Promisify websocket send
|
|
79
|
+
const sendPromise = util_1.promisify(ws.send);
|
|
80
|
+
|
|
81
|
+
const sendRawMessage = async (data) => {
|
|
82
|
+
if (!ws.isOpen) {
|
|
83
|
+
throw new boom_1.Boom('Connection closed', {
|
|
84
|
+
statusCode: Types_1.DisconnectReason.connectionClosed
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const bytes = noise.encodeFrame(data);
|
|
89
|
+
|
|
90
|
+
await Utils_1.promiseWithTimeout(connectTimeoutMs, async (resolve, reject) => {
|
|
91
|
+
try {
|
|
92
|
+
await sendPromise.call(ws, bytes);
|
|
93
|
+
resolve();
|
|
94
|
+
} catch (error) {
|
|
95
|
+
reject(error);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const sendNode = (frame) => {
|
|
101
|
+
if (logger.level === 'trace') {
|
|
102
|
+
logger.trace({
|
|
103
|
+
node: WABinary_1.getBinaryNodeString(frame),
|
|
104
|
+
from: 'sendNode'
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const buff = WABinary_1.encodeBinaryNode(frame);
|
|
109
|
+
return sendRawMessage(buff);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const onUnexpectedError = (err, msg) => {
|
|
113
|
+
logger.warn({ err }, `'${msg}' errored`);
|
|
114
|
+
|
|
115
|
+
const message = (err && (err.message || err.reason || String(err))).toLowerCase();
|
|
116
|
+
|
|
117
|
+
if (message.includes('pre-key') ||
|
|
118
|
+
message.includes('session') && message.includes('404')) {
|
|
119
|
+
try {
|
|
120
|
+
uploadPreKeysToServerIfRequired(true).catch(e => {
|
|
121
|
+
return logger.warn({ e }, 'failed to upload prekeys');
|
|
122
|
+
});
|
|
123
|
+
} catch (_e) {}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (message.includes('rate-overlimit') || message.includes('rate-overlimit')) {
|
|
127
|
+
const wait = Math.min(30000, config.retryRequestDelayMs || 5000);
|
|
128
|
+
logger.warn({ wait }, 'rate limiting hit, waiting...');
|
|
129
|
+
setTimeout(() => {}, wait);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const awaitNextMessage = async (sendMsg) => {
|
|
134
|
+
if (!ws.isOpen) {
|
|
135
|
+
throw new boom_1.Boom('Connection not open', {
|
|
136
|
+
statusCode: Types_1.DisconnectReason.connectionClosed
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
let onOpen, onClose;
|
|
141
|
+
|
|
142
|
+
const result = Utils_1.promiseWithTimeout(
|
|
143
|
+
connectTimeoutMs,
|
|
144
|
+
(resolve, reject) => {
|
|
145
|
+
onOpen = resolve;
|
|
146
|
+
onClose = mapWebSocketError(reject);
|
|
147
|
+
ws.on('open', onOpen);
|
|
148
|
+
ws.on('close', onClose);
|
|
149
|
+
ws.on('error', onClose);
|
|
150
|
+
}
|
|
151
|
+
).finally(() => {
|
|
152
|
+
ws.off('open', onOpen);
|
|
153
|
+
ws.off('close', onClose);
|
|
154
|
+
ws.off('error', onClose);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (sendMsg) {
|
|
158
|
+
sendRawMessage(sendMsg).catch(onClose);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return result;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const waitForMessage = async (msgId, timeoutMs = defaultQueryTimeoutMs) => {
|
|
165
|
+
let onRecv, onErr;
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const result = await Utils_1.promiseWithTimeout(
|
|
169
|
+
timeoutMs,
|
|
170
|
+
(resolve, reject) => {
|
|
171
|
+
onRecv = resolve;
|
|
172
|
+
onErr = (err) => {
|
|
173
|
+
reject(err || new boom_1.Boom('Timed out', {
|
|
174
|
+
statusCode: Types_1.DisconnectReason.timedOut
|
|
175
|
+
}));
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
ws.on(`response:${msgId}`, onRecv);
|
|
179
|
+
ws.on('close', onErr);
|
|
180
|
+
ws.on('error', onErr);
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
return result;
|
|
185
|
+
} finally {
|
|
186
|
+
ws.off(`response:${msgId}`, onRecv);
|
|
187
|
+
ws.off('close', onErr);
|
|
188
|
+
ws.off('error', onErr);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const query = async (node, timeoutMs) => {
|
|
193
|
+
if (!node.attrs.id) {
|
|
194
|
+
node.attrs.id = generateMessageTag();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const msgId = node.attrs.id;
|
|
198
|
+
const [result] = await Promise.all([
|
|
199
|
+
waitForMessage(msgId, timeoutMs),
|
|
200
|
+
sendNode(node)
|
|
201
|
+
]);
|
|
202
|
+
|
|
203
|
+
if ('error' in result) {
|
|
204
|
+
WABinary_1.assertNodeErrorFree(result);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return result;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const validateConnection = async () => {
|
|
211
|
+
// Buat hello message untuk handshake
|
|
212
|
+
let helloMsg = {
|
|
213
|
+
clientHello: {
|
|
214
|
+
ephemeral: ephemeralKeyPair.public
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
helloMsg = WAProto_1.proto.HandshakeMessage.ClientHello.encode(helloMsg);
|
|
219
|
+
logger.trace({ browser, helloMsg }, 'sending client hello');
|
|
220
|
+
|
|
221
|
+
const init = WAProto_1.proto.HandshakeMessage.ClientHello.encode(helloMsg).finish();
|
|
222
|
+
const result = await awaitNextMessage(init);
|
|
223
|
+
const handshake = WAProto_1.proto.HandshakeMessage.decode(result);
|
|
224
|
+
|
|
225
|
+
logger.debug({ handshake }, 'received handshake');
|
|
226
|
+
|
|
227
|
+
const keyEnc = await noise.processHandshake(handshake, creds.signedKeyPair);
|
|
228
|
+
|
|
229
|
+
let node;
|
|
230
|
+
|
|
231
|
+
if (!creds.me) {
|
|
232
|
+
node = Utils_1.newLoginPayload(creds, config);
|
|
233
|
+
logger.debug({ node }, 'sending login payload');
|
|
234
|
+
} else {
|
|
235
|
+
node = Utils_1.newRegisteredPayload(creds.me.id, config);
|
|
236
|
+
logger.debug({ node }, 'sending registered payload');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const payloadEnc = noise.encrypt(
|
|
240
|
+
WAProto_1.proto.HandshakeMessage.ClientFinish.encode(node).finish()
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
await sendRawMessage(
|
|
244
|
+
WAProto_1.proto.HandshakeMessage.encode({
|
|
245
|
+
clientFinish: {
|
|
246
|
+
key: keyEnc,
|
|
247
|
+
payload: payloadEnc
|
|
248
|
+
}
|
|
249
|
+
}).finish()
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
noise.finishInit();
|
|
253
|
+
startKeepAliveRequest();
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const getAvailablePreKeysOnServer = async () => {
|
|
257
|
+
const result = await query({
|
|
258
|
+
tag: 'iq',
|
|
259
|
+
attrs: {
|
|
260
|
+
id: generateMessageTag(),
|
|
261
|
+
xmlns: 'encrypt',
|
|
262
|
+
type: 'get',
|
|
263
|
+
to: WABinary_1.S_WHATSAPP_NET
|
|
264
|
+
},
|
|
265
|
+
content: [
|
|
266
|
+
{ tag: 'key', attrs: {} }
|
|
267
|
+
]
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
const countChild = WABinary_1.getBinaryNodeChild(result, 'key');
|
|
271
|
+
return +countChild.attrs.count;
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const uploadPreKeys = async (count = Defaults_1.INITIAL_PREKEY_COUNT) => {
|
|
275
|
+
await keys.transaction(async () => {
|
|
276
|
+
logger.debug({ count }, 'uploading pre keys');
|
|
277
|
+
|
|
278
|
+
const { update, node } = await Utils_1.generatePreKeys({
|
|
279
|
+
creds,
|
|
280
|
+
keys
|
|
281
|
+
}, count);
|
|
282
|
+
|
|
283
|
+
await query(node);
|
|
284
|
+
ev.emit('creds.update', update);
|
|
285
|
+
logger.debug({ count }, 'pre keys uploaded');
|
|
286
|
+
});
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const uploadPreKeysToServerIfRequired = async () => {
|
|
290
|
+
const preKeyCount = await getAvailablePreKeysOnServer();
|
|
291
|
+
logger.debug(`${preKeyCount} pre keys available on server`);
|
|
292
|
+
|
|
293
|
+
if (preKeyCount <= Defaults_1.MIN_PREKEY_COUNT) {
|
|
294
|
+
await uploadPreKeys();
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const onMessageReceived = (data) => {
|
|
299
|
+
noise.processIncomingData(data, (frame) => {
|
|
300
|
+
let anyTriggered = false;
|
|
301
|
+
anyTriggered = ws.emit('frame', frame);
|
|
302
|
+
|
|
303
|
+
if (!(frame instanceof Uint8Array)) {
|
|
304
|
+
const msgId = frame.attrs?.id;
|
|
305
|
+
|
|
306
|
+
if (logger.level === 'silly') {
|
|
307
|
+
logger.silly({
|
|
308
|
+
node: WABinary_1.getBinaryNodeString(frame),
|
|
309
|
+
from: 'onMessageReceived'
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
anyTriggered = ws.emit(`response:${Defaults_1.DEFAULT_ORIGIN}${msgId}`, frame) || anyTriggered;
|
|
314
|
+
|
|
315
|
+
const l0 = frame.tag;
|
|
316
|
+
const l1 = frame.attrs || {};
|
|
317
|
+
const l2 = Array.isArray(frame.content) ? frame.content[0]?.tag : '';
|
|
318
|
+
|
|
319
|
+
for (const key of Object.keys(l1)) {
|
|
320
|
+
anyTriggered = ws.emit(`${Defaults_1.DEFAULT_ORIGIN}${l0},${key}:${l1[key]},${l2}`, frame) || anyTriggered;
|
|
321
|
+
anyTriggered = ws.emit(`${Defaults_1.DEFAULT_ORIGIN}${l0},${key}:${l1[key]}`, frame) || anyTriggered;
|
|
322
|
+
anyTriggered = ws.emit(`${Defaults_1.DEFAULT_ORIGIN}${l0},${key}`, frame) || anyTriggered;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
anyTriggered = ws.emit(`${Defaults_1.DEFAULT_ORIGIN}${l0},,${l2}`, frame) || anyTriggered;
|
|
326
|
+
anyTriggered = ws.emit(`${Defaults_1.DEFAULT_ORIGIN}${l0}`, frame) || anyTriggered;
|
|
327
|
+
|
|
328
|
+
if (!anyTriggered && logger.level === 'silly') {
|
|
329
|
+
logger.silly({
|
|
330
|
+
unhandled: true,
|
|
331
|
+
msgId,
|
|
332
|
+
triggered: false,
|
|
333
|
+
frame
|
|
334
|
+
}, 'unhandled message');
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
const end = (error) => {
|
|
341
|
+
if (closed) {
|
|
342
|
+
logger.warn({ error: error?.message }, 'end already closed');
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
closed = true;
|
|
347
|
+
logger.debug({ error: error?.message }, error ? 'socket errored' : 'socket ended');
|
|
348
|
+
|
|
349
|
+
clearInterval(keepAliveReq);
|
|
350
|
+
clearTimeout(qrTimer);
|
|
351
|
+
ws.removeAllListeners('open');
|
|
352
|
+
ws.removeAllListeners('close');
|
|
353
|
+
ws.removeAllListeners('error');
|
|
354
|
+
ws.removeAllListeners('frame');
|
|
355
|
+
|
|
356
|
+
if (!ws.isClosed && !ws.isClosing) {
|
|
357
|
+
try {
|
|
358
|
+
ws.terminate();
|
|
359
|
+
} catch (_a) {}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
ev.emit('connection.update', {
|
|
363
|
+
connection: 'close',
|
|
364
|
+
lastDisconnect: { error, date: new Date }
|
|
365
|
+
});
|
|
366
|
+
ev.removeAllListeners('connection.update');
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
const waitForSocketOpen = async () => {
|
|
370
|
+
if (ws.isOpen) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (ws.isClosing || ws.isClosed) {
|
|
375
|
+
throw new boom_1.Boom('Connection closed', {
|
|
376
|
+
statusCode: Types_1.DisconnectReason.connectionClosed
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
let onOpen, onClose;
|
|
381
|
+
|
|
382
|
+
await new Promise((resolve, reject) => {
|
|
383
|
+
onOpen = () => { return resolve(true); };
|
|
384
|
+
onClose = mapWebSocketError(reject);
|
|
385
|
+
|
|
386
|
+
ws.on('open', onOpen);
|
|
387
|
+
ws.on('close', onClose);
|
|
388
|
+
ws.on('error', onClose);
|
|
389
|
+
}).finally(() => {
|
|
390
|
+
ws.off('open', onOpen);
|
|
391
|
+
ws.off('close', onClose);
|
|
392
|
+
ws.off('error', onClose);
|
|
393
|
+
});
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
const startKeepAliveRequest = () => {
|
|
397
|
+
return keepAliveReq = setInterval(() => {
|
|
398
|
+
if (!lastDateRecv) {
|
|
399
|
+
lastDateRecv = new Date();
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const diff = Date.now() - lastDateRecv.getTime();
|
|
403
|
+
|
|
404
|
+
if (diff > keepAliveIntervalMs + 5000) {
|
|
405
|
+
end(new boom_1.Boom('Keep alive timeout', {
|
|
406
|
+
statusCode: Types_1.DisconnectReason.connectionLost
|
|
407
|
+
}));
|
|
408
|
+
} else {
|
|
409
|
+
if (ws.isOpen) {
|
|
410
|
+
query({
|
|
411
|
+
tag: 'iq',
|
|
412
|
+
attrs: {
|
|
413
|
+
id: generateMessageTag(),
|
|
414
|
+
to: WABinary_1.S_WHATSAPP_NET,
|
|
415
|
+
type: 'get',
|
|
416
|
+
xmlns: 'w:keepalive'
|
|
417
|
+
},
|
|
418
|
+
content: [
|
|
419
|
+
{ tag: 'pong', attrs: {} }
|
|
420
|
+
]
|
|
421
|
+
}).catch(err => {
|
|
422
|
+
logger.warn({ error: err.message }, 'keep alive failed');
|
|
423
|
+
});
|
|
424
|
+
} else {
|
|
425
|
+
logger.debug('keep alive skipped, socket closed');
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}, keepAliveIntervalMs);
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
const sendPassiveIq = (tag) => {
|
|
432
|
+
return query({
|
|
433
|
+
tag: 'iq',
|
|
434
|
+
attrs: {
|
|
435
|
+
to: WABinary_1.S_WHATSAPP_NET,
|
|
436
|
+
type: 'get',
|
|
437
|
+
xmlns: 'passive',
|
|
438
|
+
xml: 'passive'
|
|
439
|
+
},
|
|
440
|
+
content: [
|
|
441
|
+
{ tag: tag, attrs: {} }
|
|
442
|
+
]
|
|
443
|
+
});
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
const logout = async (msg) => {
|
|
447
|
+
const jid = authState.creds?.me?.id;
|
|
448
|
+
|
|
449
|
+
if (jid) {
|
|
450
|
+
await sendNode({
|
|
451
|
+
tag: 'iq',
|
|
452
|
+
attrs: {
|
|
453
|
+
to: WABinary_1.S_WHATSAPP_NET,
|
|
454
|
+
type: 'set',
|
|
455
|
+
id: generateMessageTag(),
|
|
456
|
+
xmlns: 'md'
|
|
457
|
+
},
|
|
458
|
+
content: [{
|
|
459
|
+
tag: 'remove-companion-device',
|
|
460
|
+
attrs: {
|
|
461
|
+
jid: jid,
|
|
462
|
+
reason: 'user_initiated'
|
|
463
|
+
}
|
|
464
|
+
}]
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
end(new boom_1.Boom(msg || 'logout', {
|
|
469
|
+
statusCode: Types_1.DisconnectReason.loggedOut
|
|
470
|
+
}));
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
const requestPairingCode = async (phoneNumber, pairKey) => {
|
|
474
|
+
if (pairKey) {
|
|
475
|
+
authState.creds.pairingKey = pairKey.publicKey();
|
|
476
|
+
} else {
|
|
477
|
+
authState.creds.pairingEphemeralKey = Utils_1.Curve.generateKeyPair(
|
|
478
|
+
crypto_1.randomBytes(32)
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
authState.creds.me = {
|
|
483
|
+
id: WABinary_1.jidNormalizedUser(phoneNumber, 's.whatsapp.net'),
|
|
484
|
+
lid: '~'
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
ev.emit('creds.update', authState.creds);
|
|
488
|
+
|
|
489
|
+
await sendNode({
|
|
490
|
+
tag: 'iq',
|
|
491
|
+
attrs: {
|
|
492
|
+
to: WABinary_1.S_WHATSAPP_NET,
|
|
493
|
+
type: 'set',
|
|
494
|
+
id: generateMessageTag(),
|
|
495
|
+
xmlns: 'md'
|
|
496
|
+
},
|
|
497
|
+
content: [{
|
|
498
|
+
tag: 'pair-device',
|
|
499
|
+
attrs: {
|
|
500
|
+
jid: authState.creds.me.id,
|
|
501
|
+
ref: 'link_code',
|
|
502
|
+
action: 'request'
|
|
503
|
+
},
|
|
504
|
+
content: [
|
|
505
|
+
{ tag: 'link_code', attrs: {}, content: await generatePairingKey() },
|
|
506
|
+
{ tag: 'ephemeral_key', attrs: {}, content: authState.creds.pairingEphemeralKey.public },
|
|
507
|
+
{ tag: 'companion_props', attrs: {}, content: Utils_1.encodeCompanionProps(browser[1]) },
|
|
508
|
+
{ tag: 'companion_os', attrs: {}, content: `${browser[1]} (${browser[0]})` },
|
|
509
|
+
{ tag: 'companion_version', attrs: {}, content: '0' }
|
|
510
|
+
]
|
|
511
|
+
}]
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
return authState.creds.pairingCode;
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
async function generatePairingKey() {
|
|
518
|
+
const salt = crypto_1.randomBytes(32);
|
|
519
|
+
const randomIv = crypto_1.randomBytes(16);
|
|
520
|
+
const key = await Utils_1.hkdf(
|
|
521
|
+
authState.creds.pairingEphemeralKey.sharedSecret,
|
|
522
|
+
salt
|
|
523
|
+
);
|
|
524
|
+
const ciphered = Utils_1.aes256GcmEncrypt(
|
|
525
|
+
authState.creds.pairingEphemeralKey.publicKey,
|
|
526
|
+
key,
|
|
527
|
+
randomIv
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
return Buffer.concat([salt, randomIv, ciphered]);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const sendWAMBuffer = (wamBuffer) => {
|
|
534
|
+
return query({
|
|
535
|
+
tag: 'iq',
|
|
536
|
+
attrs: {
|
|
537
|
+
to: WABinary_1.S_WHATSAPP_NET,
|
|
538
|
+
id: generateMessageTag(),
|
|
539
|
+
type: 'set',
|
|
540
|
+
xmlns: 'w:stats:wam'
|
|
541
|
+
},
|
|
542
|
+
content: [
|
|
543
|
+
{ tag: 'wam', attrs: {}, content: wamBuffer }
|
|
544
|
+
]
|
|
545
|
+
});
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
// Register event handlers
|
|
549
|
+
ws.on('message', onMessageReceived);
|
|
550
|
+
ws.on('open', async () => {
|
|
551
|
+
try {
|
|
552
|
+
await validateConnection();
|
|
553
|
+
} catch (err) {
|
|
554
|
+
logger.error({ err }, 'connection validation failed');
|
|
555
|
+
end(err);
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
ws.on('error', mapWebSocketError(end));
|
|
560
|
+
ws.on('upgradeError', () => {
|
|
561
|
+
return end(new boom_1.Boom('Upgrade error', {
|
|
562
|
+
statusCode: Types_1.DisconnectReason.upgradeError
|
|
563
|
+
}));
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
ws.on('close', () => {
|
|
567
|
+
return end(new boom_1.Boom('Connection closed', {
|
|
568
|
+
statusCode: Types_1.DisconnectReason.connectionClosed
|
|
569
|
+
}));
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
ws.on('stream', async (stanza) => {
|
|
573
|
+
try {
|
|
574
|
+
await uploadPreKeysToServerIfRequired();
|
|
575
|
+
await sendPassiveIq('active');
|
|
576
|
+
logger.debug('stream resumed');
|
|
577
|
+
clearTimeout(qrTimer);
|
|
578
|
+
|
|
579
|
+
ev.emit('creds.update', {
|
|
580
|
+
me: {
|
|
581
|
+
...authState.creds.me,
|
|
582
|
+
lid: stanza.attrs.lid
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
ev.emit('connection.update', {
|
|
587
|
+
connection: 'open'
|
|
588
|
+
});
|
|
589
|
+
} catch (err) {
|
|
590
|
+
logger.error({ err }, 'stream error');
|
|
591
|
+
end(err);
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
ws.on('failure', (node) => {
|
|
596
|
+
logger.error({ node }, 'failure received');
|
|
597
|
+
const { reason, statusCode } = Utils_1.extractFailureReason(node);
|
|
598
|
+
end(new boom_1.Boom(`Failure: ${reason}`, {
|
|
599
|
+
statusCode: statusCode,
|
|
600
|
+
data: node
|
|
601
|
+
}));
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
ws.on('streamError', (node) => {
|
|
605
|
+
const reason = +(node.attrs.code || 500);
|
|
606
|
+
end(new boom_1.Boom('Stream error', {
|
|
607
|
+
data: reason,
|
|
608
|
+
node: node.content
|
|
609
|
+
}));
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
ws.on('timeout', () => {
|
|
613
|
+
end(new boom_1.Boom('WebSocket timeout', {
|
|
614
|
+
statusCode: Types_1.DisconnectReason.connectionTimeout
|
|
615
|
+
}));
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
ws.on('ping', (node) => {
|
|
619
|
+
logger.debug('ping received', JSON.stringify(node));
|
|
620
|
+
sendNode({
|
|
621
|
+
tag: 'ib',
|
|
622
|
+
attrs: {},
|
|
623
|
+
content: [
|
|
624
|
+
{ tag: 'd', attrs: { ping: 'pong' } }
|
|
625
|
+
]
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
ws.on('edge_routing', (node) => {
|
|
630
|
+
const edgeRoutingNode = WABinary_1.getBinaryNodeChild(node, 'edge_routing');
|
|
631
|
+
const routingInfo = WABinary_1.getBinaryNodeChild(edgeRoutingNode, 'routing_info');
|
|
632
|
+
|
|
633
|
+
if (routingInfo?.content) {
|
|
634
|
+
authState.creds.routingInfo = Buffer.from(routingInfo.content);
|
|
635
|
+
ev.emit('creds.update', authState.creds);
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
let didStartBuffer = false;
|
|
640
|
+
|
|
641
|
+
process.nextTick(() => {
|
|
642
|
+
if (creds?.me?.id) {
|
|
643
|
+
ev.flush();
|
|
644
|
+
didStartBuffer = true;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
ev.emit('connection.update', {
|
|
648
|
+
connection: 'connecting',
|
|
649
|
+
receivedPendingNotifications: false,
|
|
650
|
+
qr: null
|
|
651
|
+
});
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
ws.on('stream:resumed', (node) => {
|
|
655
|
+
const child = WABinary_1.getBinaryNodeChild(node, 'stream');
|
|
656
|
+
const offlineNotifs = +((child?.attrs?.count) || 0);
|
|
657
|
+
|
|
658
|
+
logger.debug(`stream resumed, pending notifs: ${offlineNotifs}`);
|
|
659
|
+
|
|
660
|
+
if (didStartBuffer) {
|
|
661
|
+
ev.flush();
|
|
662
|
+
logger.debug('flushed buffer');
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
ev.emit('connection.update', { receivedPendingNotifications: true });
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
ev.on('creds.update', (update) => {
|
|
669
|
+
const name = update.me?.name;
|
|
670
|
+
|
|
671
|
+
if (creds.me?.name !== name) {
|
|
672
|
+
logger.debug({ name }, 'sending pushname update');
|
|
673
|
+
sendNode({
|
|
674
|
+
tag: 'presence',
|
|
675
|
+
attrs: { name: name }
|
|
676
|
+
}).catch(err => {
|
|
677
|
+
logger.warn({ error: err.message }, 'failed to send pushname update');
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
Object.assign(creds, update);
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
// Print QR di terminal jika diminta
|
|
685
|
+
if (printQRInTerminal) {
|
|
686
|
+
Utils_1.printQRIfNecessaryListener(ev, logger);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
return {
|
|
690
|
+
type: 'md',
|
|
691
|
+
ws,
|
|
692
|
+
ev,
|
|
693
|
+
authState: { creds, keys },
|
|
694
|
+
signalRepository,
|
|
695
|
+
get user() {
|
|
696
|
+
return authState.creds.me;
|
|
697
|
+
},
|
|
698
|
+
generateMessageTag,
|
|
699
|
+
query,
|
|
700
|
+
waitForMessage,
|
|
701
|
+
waitForSocketOpen,
|
|
702
|
+
sendRawMessage,
|
|
703
|
+
sendNode,
|
|
704
|
+
logout,
|
|
705
|
+
end,
|
|
706
|
+
onUnexpectedError,
|
|
707
|
+
uploadPreKeys,
|
|
708
|
+
uploadPreKeysToServerIfRequired,
|
|
709
|
+
requestPairingCode,
|
|
710
|
+
createBufferedFunction: Utils_1.createBufferedFunction(ev),
|
|
711
|
+
sendWAMBuffer
|
|
712
|
+
};
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
exports.makeSocket = makeSocket;
|
|
716
|
+
|
|
717
|
+
function mapWebSocketError(handler) {
|
|
718
|
+
return (error) => {
|
|
719
|
+
handler(new boom_1.Boom(
|
|
720
|
+
`WebSocket error: ${error?.message}`,
|
|
721
|
+
{
|
|
722
|
+
statusCode: Utils_1.getErrorCode(error),
|
|
723
|
+
data: error
|
|
724
|
+
}
|
|
725
|
+
));
|
|
726
|
+
};
|
|
727
|
+
}
|