@neelegirl/baileys 1.5.7 → 1.5.8
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/README.md +5 -2
- package/lib/Socket/socket.js +218 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
<h1 align="center">🌸 Willkommen bei <code>@neelegirl/baileys</code> 🌸</h1>
|
|
7
7
|
<p align="center"><i>Eine charmante WhatsApp Web API für TypeScript/JavaScript – von einer Prinzessin für alle, die Magie lieben.</i></p>
|
|
8
|
-
<p align="center"><strong>✨ Version 1.5.
|
|
8
|
+
<p align="center"><strong>✨ Version 1.5.8 – Aktualisiert mit neuesten Features von @whiskeysockets/baileys ✨</strong></p>
|
|
9
9
|
|
|
10
10
|
<div align="center">
|
|
11
11
|
|
|
@@ -45,7 +45,10 @@ Die Entwickler:innen übernehmen keine Verantwortung für den Gebrauch. Lies die
|
|
|
45
45
|
- 💖 Vollständige **Multi‑Device** Unterstützung
|
|
46
46
|
- 🧩 **LID‑kompatibel** (Linked ID Erkennung & Nutzung)
|
|
47
47
|
- 🧷 Saubere TypeScript‑Typen, DX zum Verlieben
|
|
48
|
-
- 🆕 **Version 1.5.
|
|
48
|
+
- 🆕 **Version 1.5.8** – Aktualisiert mit neuesten Features von @whiskeysockets/baileys
|
|
49
|
+
- ✨ **Neue Features**: `onWhatsApp()`, `executeUSyncQuery()`, `digestKeyBundle()`, `rotateSignedPreKey()`
|
|
50
|
+
- 🚀 **Verbesserte Pre-Key-Verwaltung** mit automatischer Validierung
|
|
51
|
+
- 💎 **WAM Buffer Support** für erweiterte Statistiken
|
|
49
52
|
|
|
50
53
|
---
|
|
51
54
|
|
package/lib/Socket/socket.js
CHANGED
|
@@ -11,6 +11,9 @@ const Defaults_1 = require("../Defaults")
|
|
|
11
11
|
const Types_1 = require("../Types")
|
|
12
12
|
const Utils_1 = require("../Utils")
|
|
13
13
|
const WABinary_1 = require("../WABinary")
|
|
14
|
+
const BinaryInfo_1 = require("../WAM/BinaryInfo")
|
|
15
|
+
const USyncQuery_1 = require("../WAUSync/USyncQuery")
|
|
16
|
+
const USyncUser_1 = require("../WAUSync/USyncUser")
|
|
14
17
|
const Client_1 = require("./Client")
|
|
15
18
|
const package_json_1 = require("../../package.json")
|
|
16
19
|
const CURRENT_VERSION = package_json_1.version
|
|
@@ -38,6 +41,7 @@ const makeSocket = (config) => {
|
|
|
38
41
|
|
|
39
42
|
ws.connect()
|
|
40
43
|
const ev = Utils_1.makeEventBuffer(logger)
|
|
44
|
+
const publicWAMBuffer = new BinaryInfo_1.BinaryInfo()
|
|
41
45
|
|
|
42
46
|
/** ephemeral key pair used to encrypt/decrypt communication. Unique for each connection */
|
|
43
47
|
const ephemeralKeyPair = Utils_1.Curve.generateKeyPair()
|
|
@@ -54,7 +58,11 @@ const makeSocket = (config) => {
|
|
|
54
58
|
|
|
55
59
|
// add transaction capability
|
|
56
60
|
const keys = Utils_1.addTransactionCapability(authState.keys, logger, transactionOpts)
|
|
57
|
-
|
|
61
|
+
// pnFromLIDUSync wird später definiert, daher temporär undefined
|
|
62
|
+
let signalRepository
|
|
63
|
+
const initSignalRepository = () => {
|
|
64
|
+
signalRepository = makeSignalRepository({ creds, keys }, logger, pnFromLIDUSync)
|
|
65
|
+
}
|
|
58
66
|
|
|
59
67
|
let lastDateRecv
|
|
60
68
|
let epoch = 1
|
|
@@ -139,21 +147,38 @@ const makeSocket = (config) => {
|
|
|
139
147
|
let onRecv
|
|
140
148
|
let onErr
|
|
141
149
|
try {
|
|
142
|
-
|
|
143
|
-
onRecv =
|
|
150
|
+
const result = await Utils_1.promiseTimeout(timeoutMs, (resolve, reject) => {
|
|
151
|
+
onRecv = data => {
|
|
152
|
+
resolve(data)
|
|
153
|
+
}
|
|
144
154
|
onErr = err => {
|
|
145
|
-
reject(err ||
|
|
155
|
+
reject(err ||
|
|
156
|
+
new boom_1.Boom('Connection Closed', {
|
|
157
|
+
statusCode: Types_1.DisconnectReason.connectionClosed
|
|
158
|
+
}))
|
|
146
159
|
}
|
|
147
160
|
ws.on(`TAG:${msgId}`, onRecv)
|
|
148
|
-
ws.on('close', onErr)
|
|
149
|
-
ws.
|
|
161
|
+
ws.on('close', onErr)
|
|
162
|
+
ws.on('error', onErr)
|
|
163
|
+
return () => reject(new boom_1.Boom('Query Cancelled'))
|
|
150
164
|
})
|
|
165
|
+
return result
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
// Catch timeout and return undefined instead of throwing
|
|
169
|
+
if (error instanceof boom_1.Boom && error.output?.statusCode === Types_1.DisconnectReason.timedOut) {
|
|
170
|
+
logger?.warn?.({ msgId }, 'timed out waiting for message')
|
|
171
|
+
return undefined
|
|
172
|
+
}
|
|
173
|
+
throw error
|
|
151
174
|
}
|
|
152
|
-
|
|
153
175
|
finally {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
176
|
+
if (onRecv)
|
|
177
|
+
ws.off(`TAG:${msgId}`, onRecv)
|
|
178
|
+
if (onErr) {
|
|
179
|
+
ws.off('close', onErr)
|
|
180
|
+
ws.off('error', onErr)
|
|
181
|
+
}
|
|
157
182
|
}
|
|
158
183
|
}
|
|
159
184
|
|
|
@@ -162,20 +187,146 @@ const makeSocket = (config) => {
|
|
|
162
187
|
if (!node.attrs.id) {
|
|
163
188
|
node.attrs.id = generateMessageTag()
|
|
164
189
|
}
|
|
165
|
-
|
|
166
190
|
const msgId = node.attrs.id
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if ('tag' in result) {
|
|
191
|
+
const result = await Utils_1.promiseTimeout(timeoutMs, async (resolve, reject) => {
|
|
192
|
+
const result = waitForMessage(msgId, timeoutMs).catch(reject)
|
|
193
|
+
sendNode(node)
|
|
194
|
+
.then(async () => resolve(await result))
|
|
195
|
+
.catch(reject)
|
|
196
|
+
})
|
|
197
|
+
if (result && 'tag' in result) {
|
|
174
198
|
WABinary_1.assertNodeErrorFree(result)
|
|
175
199
|
}
|
|
176
|
-
|
|
177
200
|
return result
|
|
178
201
|
}
|
|
202
|
+
// Validate current key-bundle on server; on failure, trigger pre-key upload and rethrow
|
|
203
|
+
const digestKeyBundle = async () => {
|
|
204
|
+
const res = await query({
|
|
205
|
+
tag: 'iq',
|
|
206
|
+
attrs: { to: WABinary_1.S_WHATSAPP_NET, type: 'get', xmlns: 'encrypt' },
|
|
207
|
+
content: [{ tag: 'digest', attrs: {} }]
|
|
208
|
+
})
|
|
209
|
+
const digestNode = WABinary_1.getBinaryNodeChild(res, 'digest')
|
|
210
|
+
if (!digestNode) {
|
|
211
|
+
await uploadPreKeys()
|
|
212
|
+
throw new Error('encrypt/get digest returned no digest node')
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Rotate our signed pre-key on server; on failure, run digest as fallback and rethrow
|
|
216
|
+
const rotateSignedPreKey = async () => {
|
|
217
|
+
const newId = (creds.signedPreKey.keyId || 0) + 1
|
|
218
|
+
const skey = await Utils_1.signedKeyPair(creds.signedIdentityKey, newId)
|
|
219
|
+
await query({
|
|
220
|
+
tag: 'iq',
|
|
221
|
+
attrs: { to: WABinary_1.S_WHATSAPP_NET, type: 'set', xmlns: 'encrypt' },
|
|
222
|
+
content: [
|
|
223
|
+
{
|
|
224
|
+
tag: 'rotate',
|
|
225
|
+
attrs: {},
|
|
226
|
+
content: [Utils_1.xmppSignedPreKey(skey)]
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
})
|
|
230
|
+
// Persist new signed pre-key in creds
|
|
231
|
+
ev.emit('creds.update', { signedPreKey: skey })
|
|
232
|
+
}
|
|
233
|
+
const executeUSyncQuery = async (usyncQuery) => {
|
|
234
|
+
if (usyncQuery.protocols.length === 0) {
|
|
235
|
+
throw new boom_1.Boom('USyncQuery must have at least one protocol')
|
|
236
|
+
}
|
|
237
|
+
// todo: validate users, throw WARNING on no valid users
|
|
238
|
+
// variable below has only validated users
|
|
239
|
+
const validUsers = usyncQuery.users
|
|
240
|
+
const userNodes = validUsers.map(user => {
|
|
241
|
+
return {
|
|
242
|
+
tag: 'user',
|
|
243
|
+
attrs: {
|
|
244
|
+
jid: !user.phone ? user.id : undefined
|
|
245
|
+
},
|
|
246
|
+
content: usyncQuery.protocols.map(a => a.getUserElement(user)).filter(a => a !== null)
|
|
247
|
+
}
|
|
248
|
+
})
|
|
249
|
+
const listNode = {
|
|
250
|
+
tag: 'list',
|
|
251
|
+
attrs: {},
|
|
252
|
+
content: userNodes
|
|
253
|
+
}
|
|
254
|
+
const queryNode = {
|
|
255
|
+
tag: 'query',
|
|
256
|
+
attrs: {},
|
|
257
|
+
content: usyncQuery.protocols.map(a => a.getQueryElement())
|
|
258
|
+
}
|
|
259
|
+
const iq = {
|
|
260
|
+
tag: 'iq',
|
|
261
|
+
attrs: {
|
|
262
|
+
to: WABinary_1.S_WHATSAPP_NET,
|
|
263
|
+
type: 'get',
|
|
264
|
+
xmlns: 'usync'
|
|
265
|
+
},
|
|
266
|
+
content: [
|
|
267
|
+
{
|
|
268
|
+
tag: 'usync',
|
|
269
|
+
attrs: {
|
|
270
|
+
context: usyncQuery.context,
|
|
271
|
+
mode: usyncQuery.mode,
|
|
272
|
+
sid: generateMessageTag(),
|
|
273
|
+
last: 'true',
|
|
274
|
+
index: '0'
|
|
275
|
+
},
|
|
276
|
+
content: [queryNode, listNode]
|
|
277
|
+
}
|
|
278
|
+
]
|
|
279
|
+
}
|
|
280
|
+
const result = await query(iq)
|
|
281
|
+
return usyncQuery.parseUSyncQueryResult(result)
|
|
282
|
+
}
|
|
283
|
+
const onWhatsApp = async (...phoneNumber) => {
|
|
284
|
+
let usyncQuery = new USyncQuery_1.USyncQuery()
|
|
285
|
+
let contactEnabled = false
|
|
286
|
+
for (const jid of phoneNumber) {
|
|
287
|
+
if (WABinary_1.isLidUser(jid)) {
|
|
288
|
+
logger?.warn('LIDs are not supported with onWhatsApp')
|
|
289
|
+
continue
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
if (!contactEnabled) {
|
|
293
|
+
contactEnabled = true
|
|
294
|
+
usyncQuery = usyncQuery.withContactProtocol()
|
|
295
|
+
}
|
|
296
|
+
const phone = `+${jid.replace('+', '').split('@')[0]?.split(':')[0]}`
|
|
297
|
+
usyncQuery.withUser(new USyncUser_1.USyncUser().withPhone(phone))
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (usyncQuery.users.length === 0) {
|
|
301
|
+
return [] // return early without forcing an empty query
|
|
302
|
+
}
|
|
303
|
+
const results = await executeUSyncQuery(usyncQuery)
|
|
304
|
+
if (results) {
|
|
305
|
+
return results.list.filter(a => !!a.contact).map(({ contact, id }) => ({ jid: id, exists: contact }))
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const pnFromLIDUSync = async (jids) => {
|
|
309
|
+
const usyncQuery = new USyncQuery_1.USyncQuery().withLIDProtocol().withContext('background')
|
|
310
|
+
for (const jid of jids) {
|
|
311
|
+
if (WABinary_1.isLidUser(jid)) {
|
|
312
|
+
logger?.warn('LID user found in LID fetch call')
|
|
313
|
+
continue
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
usyncQuery.withUser(new USyncUser_1.USyncUser().withId(jid))
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (usyncQuery.users.length === 0) {
|
|
320
|
+
return [] // return early without forcing an empty query
|
|
321
|
+
}
|
|
322
|
+
const results = await executeUSyncQuery(usyncQuery)
|
|
323
|
+
if (results) {
|
|
324
|
+
return results.list.filter(a => !!a.lid).map(({ lid, id }) => ({ pn: id, lid: lid }))
|
|
325
|
+
}
|
|
326
|
+
return []
|
|
327
|
+
}
|
|
328
|
+
// Initialize signalRepository after pnFromLIDUSync is defined
|
|
329
|
+
initSignalRepository()
|
|
179
330
|
/** connection handshake */
|
|
180
331
|
const validateConnection = async () => {
|
|
181
332
|
let helloMsg = {
|
|
@@ -254,8 +405,8 @@ const makeSocket = (config) => {
|
|
|
254
405
|
}
|
|
255
406
|
}
|
|
256
407
|
|
|
257
|
-
const onMessageReceived = (data) => {
|
|
258
|
-
noise.decodeFrame(data, frame => {
|
|
408
|
+
const onMessageReceived = async (data) => {
|
|
409
|
+
await noise.decodeFrame(data, frame => {
|
|
259
410
|
// reset ping timeout
|
|
260
411
|
lastDateRecv = new Date()
|
|
261
412
|
let anyTriggered = false
|
|
@@ -509,7 +660,7 @@ const makeSocket = (config) => {
|
|
|
509
660
|
content: [
|
|
510
661
|
{
|
|
511
662
|
tag: 'add',
|
|
512
|
-
attrs: {},
|
|
663
|
+
attrs: { t: Math.round(Date.now() / 1000) + '' },
|
|
513
664
|
content: wamBuffer
|
|
514
665
|
}
|
|
515
666
|
]
|
|
@@ -619,27 +770,52 @@ const makeSocket = (config) => {
|
|
|
619
770
|
ws.on('CB:success', async (node) => {
|
|
620
771
|
try {
|
|
621
772
|
await uploadPreKeysToServerIfRequired()
|
|
622
|
-
|
|
623
773
|
await sendPassiveIq('active')
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
774
|
+
// After successful login, validate our key-bundle against server
|
|
775
|
+
try {
|
|
776
|
+
await digestKeyBundle()
|
|
777
|
+
}
|
|
778
|
+
catch (e) {
|
|
779
|
+
logger.warn({ e }, 'failed to run digest after login')
|
|
780
|
+
}
|
|
630
781
|
}
|
|
631
|
-
|
|
632
782
|
catch (err) {
|
|
633
|
-
logger.
|
|
634
|
-
|
|
783
|
+
logger.warn({ err }, 'failed to send initial passive iq')
|
|
784
|
+
}
|
|
785
|
+
logger.info('opened connection to WA')
|
|
786
|
+
clearTimeout(qrTimer) // will never happen in all likelyhood -- but just in case WA sends success on first try
|
|
787
|
+
ev.emit('creds.update', { me: { ...authState.creds.me, lid: node.attrs.lid } })
|
|
788
|
+
ev.emit('connection.update', { connection: 'open' })
|
|
789
|
+
if (node.attrs.lid && authState.creds.me?.id) {
|
|
790
|
+
const myLID = node.attrs.lid
|
|
791
|
+
process.nextTick(async () => {
|
|
792
|
+
try {
|
|
793
|
+
const myPN = authState.creds.me.id
|
|
794
|
+
// Store our own LID-PN mapping
|
|
795
|
+
await signalRepository.lidMapping.storeLIDPNMappings([{ lid: myLID, pn: myPN }])
|
|
796
|
+
// Create device list for our own user (needed for bulk migration)
|
|
797
|
+
const { user, device } = WABinary_1.jidDecode(myPN)
|
|
798
|
+
await authState.keys.set({
|
|
799
|
+
'device-list': {
|
|
800
|
+
[user]: [device?.toString() || '0']
|
|
801
|
+
}
|
|
802
|
+
})
|
|
803
|
+
// migrate our own session
|
|
804
|
+
await signalRepository.migrateSession(myPN, myLID)
|
|
805
|
+
logger.info({ myPN, myLID }, 'Own LID session created successfully')
|
|
806
|
+
}
|
|
807
|
+
catch (error) {
|
|
808
|
+
logger.error({ error, lid: myLID }, 'Failed to create own LID session')
|
|
809
|
+
}
|
|
810
|
+
})
|
|
635
811
|
}
|
|
636
812
|
})
|
|
637
813
|
|
|
638
814
|
ws.on('CB:stream:error', (node) => {
|
|
639
|
-
|
|
815
|
+
const [reasonNode] = WABinary_1.getAllBinaryNodeChildren(node)
|
|
816
|
+
logger.error({ reasonNode, fullErrorNode: node }, 'stream errored out')
|
|
640
817
|
const { reason, statusCode } = Utils_1.getErrorCodeFromStreamError(node)
|
|
641
|
-
|
|
642
|
-
end(new boom_1.Boom(`Stream Errored (${reason})`, { statusCode, data: node }))
|
|
818
|
+
end(new boom_1.Boom(`Stream Errored (${reason})`, { statusCode, data: reasonNode || node }))
|
|
643
819
|
})
|
|
644
820
|
|
|
645
821
|
// stream fail, possible logout
|
|
@@ -653,10 +829,9 @@ const makeSocket = (config) => {
|
|
|
653
829
|
end(new boom_1.Boom('Multi-device beta not joined', { statusCode: Types_1.DisconnectReason.multideviceMismatch }))
|
|
654
830
|
})
|
|
655
831
|
|
|
656
|
-
ws.on('CB:ib,,offline_preview', (node) => {
|
|
832
|
+
ws.on('CB:ib,,offline_preview', async (node) => {
|
|
657
833
|
logger.info('offline preview received', JSON.stringify(node))
|
|
658
|
-
|
|
659
|
-
sendNode({
|
|
834
|
+
await sendNode({
|
|
660
835
|
tag: 'ib',
|
|
661
836
|
attrs: {},
|
|
662
837
|
content: [{ tag: 'offline_batch', attrs: { count: '100' } }]
|
|
@@ -744,10 +919,15 @@ const makeSocket = (config) => {
|
|
|
744
919
|
onUnexpectedError,
|
|
745
920
|
uploadPreKeys,
|
|
746
921
|
uploadPreKeysToServerIfRequired,
|
|
922
|
+
digestKeyBundle,
|
|
923
|
+
rotateSignedPreKey,
|
|
747
924
|
requestPairingCode,
|
|
925
|
+
wamBuffer: publicWAMBuffer,
|
|
748
926
|
/** Waits for the connection to WA to reach a state */
|
|
749
927
|
waitForConnectionUpdate: Utils_1.bindWaitForConnectionUpdate(ev),
|
|
750
928
|
sendWAMBuffer,
|
|
929
|
+
executeUSyncQuery,
|
|
930
|
+
onWhatsApp
|
|
751
931
|
}
|
|
752
932
|
}
|
|
753
933
|
|