@nexustechpro/baileys 1.0.8 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -36
- package/lib/Defaults/index.js +1 -1
- package/lib/Signal/libsignal.js +58 -22
- package/lib/Socket/groups.js +3 -0
- package/lib/Socket/messages-recv.js +156 -138
- package/lib/Socket/messages-send.js +212 -369
- package/lib/Socket/mex.js +13 -4
- package/lib/Socket/newsletter.js +109 -10
- package/lib/Socket/nexus-handler.js +174 -224
- package/lib/Socket/socket.js +295 -109
- package/lib/Store/index.js +5 -5
- package/lib/Store/make-in-memory-store.js +2 -2
- package/lib/Utils/chat-utils.js +3 -1
- package/lib/Utils/decode-wa-message.js +7 -2
- package/lib/Utils/messages.js +17 -6
- package/lib/WABinary/encode.js +20 -3
- package/lib/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -733,42 +733,6 @@ await sock.sendMessage(jid, {
|
|
|
733
733
|
})
|
|
734
734
|
```
|
|
735
735
|
|
|
736
|
-
#### Pin Message
|
|
737
|
-
```javascript
|
|
738
|
-
await sock.sendMessage(jid, {
|
|
739
|
-
pin: {
|
|
740
|
-
type: 1, // 0 to remove
|
|
741
|
-
time: 86400, // 24 hours in seconds
|
|
742
|
-
key: message.key
|
|
743
|
-
}
|
|
744
|
-
})
|
|
745
|
-
```
|
|
746
|
-
|
|
747
|
-
**Pin Time Options:**
|
|
748
|
-
|
|
749
|
-
| Time | Seconds |
|
|
750
|
-
|------|-----------|
|
|
751
|
-
| 24h | 86,400 |
|
|
752
|
-
| 7d | 604,800 |
|
|
753
|
-
| 30d | 2,592,000 |
|
|
754
|
-
|
|
755
|
-
#### Keep Message
|
|
756
|
-
```javascript
|
|
757
|
-
await sock.sendMessage(jid, {
|
|
758
|
-
keep: message.key,
|
|
759
|
-
type: 1, // 2 to unpin
|
|
760
|
-
time: 86400
|
|
761
|
-
})
|
|
762
|
-
```
|
|
763
|
-
|
|
764
|
-
**Keep Time Options:**
|
|
765
|
-
|
|
766
|
-
| Time | Seconds |
|
|
767
|
-
|------|-----------|
|
|
768
|
-
| 24h | 86,400 |
|
|
769
|
-
| 7d | 604,800 |
|
|
770
|
-
| 30d | 2,592,000 |
|
|
771
|
-
|
|
772
736
|
#### Poll Message
|
|
773
737
|
```javascript
|
|
774
738
|
await sock.sendMessage(jid, {
|
|
@@ -1373,6 +1337,51 @@ await sock.chatModify({ pin: true }, jid)
|
|
|
1373
1337
|
await sock.chatModify({ pin: false }, jid)
|
|
1374
1338
|
```
|
|
1375
1339
|
|
|
1340
|
+
|
|
1341
|
+
#### Pin Message
|
|
1342
|
+
```javascript
|
|
1343
|
+
// Method 1: Using boolean (requires quoted message)
|
|
1344
|
+
await sock.sendMessage(jid, { pin: true }, { quoted: message })
|
|
1345
|
+
|
|
1346
|
+
// Method 2: Using pin object with message key
|
|
1347
|
+
await sock.sendMessage(jid, {
|
|
1348
|
+
pin: {
|
|
1349
|
+
key: message.key // or stanzaId, id, etc.
|
|
1350
|
+
}
|
|
1351
|
+
})
|
|
1352
|
+
|
|
1353
|
+
// Unpin message
|
|
1354
|
+
await sock.sendMessage(jid, {
|
|
1355
|
+
pin: {
|
|
1356
|
+
key: message.key,
|
|
1357
|
+
unpin: true
|
|
1358
|
+
}
|
|
1359
|
+
})
|
|
1360
|
+
|
|
1361
|
+
// Alternative unpin syntax
|
|
1362
|
+
await sock.sendMessage(jid, { pin: false }, { quoted: message })
|
|
1363
|
+
```
|
|
1364
|
+
|
|
1365
|
+
#### Keep Message
|
|
1366
|
+
```javascript
|
|
1367
|
+
await sock.sendMessage(jid, {
|
|
1368
|
+
keep: message.key,
|
|
1369
|
+
type: 1 // 1 to keep, 2 to unkeep
|
|
1370
|
+
})
|
|
1371
|
+
```
|
|
1372
|
+
|
|
1373
|
+
**Pin/Keep Details:**
|
|
1374
|
+
|
|
1375
|
+
| Operation | Method | Syntax |
|
|
1376
|
+
|-----------|--------|--------|
|
|
1377
|
+
| Pin (quoted) | Boolean | `{ pin: true }` with `{ quoted: message }` |
|
|
1378
|
+
| Pin (object) | Object | `{ pin: { key: message.key } }` |
|
|
1379
|
+
| Unpin (quoted) | Boolean | `{ pin: false }` with `{ quoted: message }` |
|
|
1380
|
+
| Unpin (object) | Object | `{ pin: { key: message.key, unpin: true } }` |
|
|
1381
|
+
| Keep | Key | `{ keep: message.key, type: 1 }` |
|
|
1382
|
+
| Unkeep | Key | `{ keep: message.key, type: 2 }` |
|
|
1383
|
+
|
|
1384
|
+
|
|
1376
1385
|
### Delete Chat
|
|
1377
1386
|
```javascript
|
|
1378
1387
|
const lastMsg = await getLastMessageInChat(jid)
|
package/lib/Defaults/index.js
CHANGED
|
@@ -107,7 +107,7 @@ export const MEDIA_HKDF_KEY_MAPPING = {
|
|
|
107
107
|
};
|
|
108
108
|
export const MEDIA_KEYS = Object.keys(MEDIA_PATH_MAP);
|
|
109
109
|
export const MIN_PREKEY_COUNT = 5;
|
|
110
|
-
export const INITIAL_PREKEY_COUNT = 812
|
|
110
|
+
export const INITIAL_PREKEY_COUNT = 95; // Changed from 812 to 95
|
|
111
111
|
export const UPLOAD_TIMEOUT = 30000; // 30 seconds
|
|
112
112
|
export const MIN_UPLOAD_INTERVAL = 5000; // 5 seconds minimum between uploads
|
|
113
113
|
export const DEFAULT_CACHE_TTLS = {
|
package/lib/Signal/libsignal.js
CHANGED
|
@@ -104,14 +104,30 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
104
104
|
}
|
|
105
105
|
},
|
|
106
106
|
|
|
107
|
-
deleteSession: jids => jids.length && txn(() =>
|
|
107
|
+
deleteSession: jids => jids.length && txn(async () => {
|
|
108
|
+
const sessionAddrs = jids.map(j => jidToAddr(j).toString())
|
|
109
|
+
// Load batched sessions
|
|
110
|
+
const batchData = await parsedKeys.get("session", ["_index"])
|
|
111
|
+
const sessionBatch = batchData?.['_index'] || {}
|
|
112
|
+
|
|
113
|
+
// Remove the specified sessions
|
|
114
|
+
sessionAddrs.forEach(addr => {
|
|
115
|
+
delete sessionBatch[addr]
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
// Store updated batch
|
|
119
|
+
await parsedKeys.set({ session: { "_index": sessionBatch } })
|
|
120
|
+
}, `del-${jids.length}`),
|
|
108
121
|
|
|
109
122
|
migrateSession: async (fromJid, toJid) => {
|
|
110
123
|
if (!fromJid || (!isLidUser(toJid) && !isHostedLidUser(toJid))) return { migrated: 0, skipped: 0, total: 0 }
|
|
111
124
|
if (!isPnUser(fromJid) && !isHostedPnUser(fromJid)) return { migrated: 0, skipped: 0, total: 1 }
|
|
112
125
|
|
|
113
126
|
const { user } = jidDecode(fromJid)
|
|
114
|
-
|
|
127
|
+
// Load device-list from batched storage
|
|
128
|
+
const batchData = await parsedKeys.get("device-list", ["_index"])
|
|
129
|
+
const deviceListBatch = batchData?.['_index'] || {}
|
|
130
|
+
const userDevices = deviceListBatch[user]
|
|
115
131
|
if (!userDevices?.length) return { migrated: 0, skipped: 0, total: 0 }
|
|
116
132
|
|
|
117
133
|
const { device: fromDevice } = jidDecode(fromJid)
|
|
@@ -119,41 +135,43 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
119
135
|
if (!userDevices.includes(fromDeviceStr)) userDevices.push(fromDeviceStr)
|
|
120
136
|
|
|
121
137
|
const uncachedDevices = userDevices.filter(d => !migratedCache.has(`${user}.${d}`))
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const num = Number.parseInt(
|
|
130
|
-
|
|
138
|
+
|
|
139
|
+
// Load batched sessions
|
|
140
|
+
const sessionBatchData = await parsedKeys.get("session", ["_index"])
|
|
141
|
+
const sessionBatch = sessionBatchData?.['_index'] || {}
|
|
142
|
+
|
|
143
|
+
const deviceJids = uncachedDevices
|
|
144
|
+
.map(d => {
|
|
145
|
+
const num = Number.parseInt(d)
|
|
146
|
+
const addrStr = num === 0 ? `${user}.0` : `${user}.${d}`
|
|
147
|
+
return { addr: addrStr, jid: num === 0 ? `${user}@s.whatsapp.net` : num === 99 ? `${user}:99@hosted` : `${user}:${num}@s.whatsapp.net` }
|
|
131
148
|
})
|
|
149
|
+
.filter(({ addr }) => sessionBatch[addr])
|
|
132
150
|
|
|
133
151
|
return txn(async () => {
|
|
134
|
-
const pnAddrStrs = Array.from(new Set(deviceJids.map(
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
const updates = {}
|
|
152
|
+
const pnAddrStrs = Array.from(new Set(deviceJids.map(d => jidToAddr(d.jid).toString())))
|
|
153
|
+
const updatedBatch = { ...sessionBatch }
|
|
138
154
|
let migrated = 0
|
|
139
155
|
|
|
140
|
-
for (const jid of deviceJids) {
|
|
156
|
+
for (const { jid } of deviceJids) {
|
|
141
157
|
const pnAddr = jidToAddr(jid).toString()
|
|
142
158
|
const lidAddr = jidToAddr(transferDevice(jid, toJid)).toString()
|
|
143
|
-
const pnSession =
|
|
159
|
+
const pnSession = updatedBatch[pnAddr]
|
|
144
160
|
|
|
145
161
|
if (pnSession) {
|
|
146
162
|
const sess = libsignal.SessionRecord.deserialize(pnSession)
|
|
147
163
|
if (sess.haveOpenSession()) {
|
|
148
|
-
|
|
149
|
-
|
|
164
|
+
updatedBatch[lidAddr] = sess.serialize()
|
|
165
|
+
delete updatedBatch[pnAddr]
|
|
150
166
|
migrated++
|
|
151
167
|
migratedCache.set(`${user}.${jidDecode(jid).device || 0}`, true)
|
|
152
168
|
}
|
|
153
169
|
}
|
|
154
170
|
}
|
|
155
171
|
|
|
156
|
-
if (
|
|
172
|
+
if (migrated > 0) {
|
|
173
|
+
await parsedKeys.set({ session: { "_index": updatedBatch } })
|
|
174
|
+
}
|
|
157
175
|
return { migrated, skipped: deviceJids.length - migrated, total: deviceJids.length }
|
|
158
176
|
}, `migrate-${deviceJids.length}`)
|
|
159
177
|
},
|
|
@@ -176,7 +194,10 @@ function signalStorage({ creds, keys }, lidMapping, logger) {
|
|
|
176
194
|
loadSession: async id => {
|
|
177
195
|
try {
|
|
178
196
|
const addr = await resolveLID(id)
|
|
179
|
-
|
|
197
|
+
// Load from batched session storage
|
|
198
|
+
const batchData = await keys.get("session", ["_index"])
|
|
199
|
+
const sessionBatch = batchData?.['_index'] || {}
|
|
200
|
+
const sess = sessionBatch[addr]
|
|
180
201
|
return sess ? libsignal.SessionRecord.deserialize(sess) : null
|
|
181
202
|
} catch (e) {
|
|
182
203
|
logger?.error?.(`[Signal] Load session: ${e.message}`)
|
|
@@ -186,7 +207,22 @@ function signalStorage({ creds, keys }, lidMapping, logger) {
|
|
|
186
207
|
|
|
187
208
|
storeSession: async (id, session) => {
|
|
188
209
|
const addr = await resolveLID(id)
|
|
189
|
-
|
|
210
|
+
// Store in batched session storage
|
|
211
|
+
const existingData = await keys.get("session", ["_index"])
|
|
212
|
+
const sessionBatch = existingData?.['_index'] || {}
|
|
213
|
+
|
|
214
|
+
// Add/update the session
|
|
215
|
+
sessionBatch[addr] = session.serialize()
|
|
216
|
+
|
|
217
|
+
// Keep only the most recent 1000 sessions to prevent unlimited growth
|
|
218
|
+
const sessionKeys = Object.keys(sessionBatch).sort()
|
|
219
|
+
const recentSessions = sessionKeys.slice(-1000)
|
|
220
|
+
const trimmedBatch = {}
|
|
221
|
+
recentSessions.forEach(key => {
|
|
222
|
+
trimmedBatch[key] = sessionBatch[key]
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
await keys.set({ session: { "_index": trimmedBatch } })
|
|
190
226
|
},
|
|
191
227
|
|
|
192
228
|
isTrustedIdentity: () => true,
|
package/lib/Socket/groups.js
CHANGED
|
@@ -282,6 +282,9 @@ export const makeGroupsSocket = (config) => {
|
|
|
282
282
|
};
|
|
283
283
|
export const extractGroupMetadata = (result) => {
|
|
284
284
|
const group = getBinaryNodeChild(result, 'group');
|
|
285
|
+
if (!group) {
|
|
286
|
+
throw new Error('Group node not found in result');
|
|
287
|
+
}
|
|
285
288
|
const descChild = getBinaryNodeChild(group, 'description');
|
|
286
289
|
let desc;
|
|
287
290
|
let descId;
|
|
@@ -68,6 +68,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
68
68
|
uploadPreKeys,
|
|
69
69
|
sendPeerDataOperationMessage,
|
|
70
70
|
messageRetryManager,
|
|
71
|
+
triggerPreKeyCheck,
|
|
71
72
|
} = sock
|
|
72
73
|
/** this mutex ensures that each retryRequest will wait for the previous one to finish */
|
|
73
74
|
const retryMutex = makeMutex()
|
|
@@ -141,7 +142,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
141
142
|
const handleMexNewsletterNotification = async (node) => {
|
|
142
143
|
const mexNode = getBinaryNodeChild(node, "mex")
|
|
143
144
|
if (!mexNode?.content) {
|
|
144
|
-
logger.warn({ node }, "Invalid mex newsletter notification")
|
|
145
|
+
//logger.warn({ node }, "Invalid mex newsletter notification")
|
|
145
146
|
return
|
|
146
147
|
}
|
|
147
148
|
let data
|
|
@@ -334,157 +335,174 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
334
335
|
await query(stanza)
|
|
335
336
|
}
|
|
336
337
|
const sendRetryRequest = async (node, forceIncludeKeys = false) => {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
// Increment retry count using new system
|
|
348
|
-
const retryCount = messageRetryManager.incrementRetryCount(msgId)
|
|
349
|
-
// Use the new retry count for the rest of the logic
|
|
350
|
-
const key = `${msgId}:${msgKey?.participant}`
|
|
351
|
-
msgRetryCache.set(key, retryCount)
|
|
352
|
-
} else {
|
|
353
|
-
// Fallback to old system
|
|
354
|
-
const key = `${msgId}:${msgKey?.participant}`
|
|
355
|
-
let retryCount = (await msgRetryCache.get(key)) || 0
|
|
356
|
-
if (retryCount >= maxMsgRetryCount) {
|
|
357
|
-
logger.debug({ retryCount, msgId }, "reached retry limit, clearing")
|
|
358
|
-
msgRetryCache.del(key)
|
|
359
|
-
return
|
|
360
|
-
}
|
|
361
|
-
retryCount += 1
|
|
362
|
-
await msgRetryCache.set(key, retryCount)
|
|
338
|
+
const { fullMessage } = decodeMessageNode(node, authState.creds.me.id, authState.creds.me.lid || "")
|
|
339
|
+
const { key: msgKey } = fullMessage
|
|
340
|
+
const msgId = msgKey.id
|
|
341
|
+
|
|
342
|
+
if (messageRetryManager) {
|
|
343
|
+
if (messageRetryManager.hasExceededMaxRetries(msgId)) {
|
|
344
|
+
logger.debug({ msgId }, "reached retry limit with new retry manager, clearing")
|
|
345
|
+
messageRetryManager.markRetryFailed(msgId)
|
|
346
|
+
return
|
|
363
347
|
}
|
|
348
|
+
const retryCount = messageRetryManager.incrementRetryCount(msgId)
|
|
364
349
|
const key = `${msgId}:${msgKey?.participant}`
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
350
|
+
msgRetryCache.set(key, retryCount)
|
|
351
|
+
} else {
|
|
352
|
+
const key = `${msgId}:${msgKey?.participant}`
|
|
353
|
+
let retryCount = (await msgRetryCache.get(key)) || 0
|
|
354
|
+
if (retryCount >= maxMsgRetryCount) {
|
|
355
|
+
logger.debug({ retryCount, msgId }, "reached retry limit, clearing")
|
|
356
|
+
msgRetryCache.del(key)
|
|
357
|
+
return
|
|
358
|
+
}
|
|
359
|
+
retryCount += 1
|
|
360
|
+
await msgRetryCache.set(key, retryCount)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const key = `${msgId}:${msgKey?.participant}`
|
|
364
|
+
const retryCount = (await msgRetryCache.get(key)) || 1
|
|
365
|
+
const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds
|
|
366
|
+
const fromJid = node.attrs.from
|
|
367
|
+
|
|
368
|
+
// ENHANCED: Check both PN and potential LID for session
|
|
369
|
+
let shouldRecreateSession = false
|
|
370
|
+
let recreateReason = ""
|
|
371
|
+
|
|
372
|
+
if (enableAutoSessionRecreation && messageRetryManager) {
|
|
373
|
+
try {
|
|
374
|
+
const sessionId = signalRepository.jidToSignalProtocolAddress(fromJid)
|
|
375
|
+
const hasSession = await signalRepository.validateSession(fromJid)
|
|
376
|
+
|
|
377
|
+
// Also check if LID mapping exists and session should be under LID
|
|
378
|
+
let lidJid = null
|
|
379
|
+
if (isPnUser(fromJid)) {
|
|
380
|
+
lidJid = await signalRepository.lidMapping.getLIDForPN(fromJid)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const result = messageRetryManager.shouldRecreateSession(fromJid, retryCount, hasSession.exists)
|
|
384
|
+
shouldRecreateSession = result.recreate
|
|
385
|
+
recreateReason = result.reason
|
|
386
|
+
|
|
387
|
+
if (shouldRecreateSession) {
|
|
388
|
+
logger.debug({ fromJid, lidJid, retryCount, reason: recreateReason }, "recreating session for retry")
|
|
389
|
+
|
|
390
|
+
// Delete both PN and LID sessions to force clean rebuild
|
|
391
|
+
await authState.keys.set({ session: { [sessionId]: null } })
|
|
392
|
+
if (lidJid) {
|
|
393
|
+
const lidSessionId = signalRepository.jidToSignalProtocolAddress(lidJid)
|
|
394
|
+
await authState.keys.set({ session: { [lidSessionId]: null } })
|
|
384
395
|
}
|
|
385
|
-
|
|
386
|
-
|
|
396
|
+
|
|
397
|
+
forceIncludeKeys = true
|
|
387
398
|
}
|
|
399
|
+
} catch (error) {
|
|
400
|
+
logger.warn({ error, fromJid }, "failed to check session recreation")
|
|
388
401
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
)
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Rest of the function remains the same...
|
|
405
|
+
if (retryCount <= 2) {
|
|
406
|
+
if (messageRetryManager) {
|
|
407
|
+
messageRetryManager.schedulePhoneRequest(msgId, async () => {
|
|
408
|
+
try {
|
|
409
|
+
const requestId = await requestPlaceholderResend(msgKey)
|
|
410
|
+
logger.debug(
|
|
411
|
+
`sendRetryRequest: requested placeholder resend (${requestId}) for message ${msgId} (scheduled)`,
|
|
412
|
+
)
|
|
413
|
+
} catch (error) {
|
|
414
|
+
logger.warn({ error, msgId }, "failed to send scheduled phone request")
|
|
415
|
+
}
|
|
416
|
+
})
|
|
417
|
+
} else {
|
|
418
|
+
const msgId = await requestPlaceholderResend(msgKey)
|
|
419
|
+
logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId}`)
|
|
408
420
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const deviceIdentity = encodeSignedDeviceIdentity(account, true)
|
|
424
|
+
await authState.keys.transaction(async () => {
|
|
425
|
+
const receipt = {
|
|
426
|
+
tag: "receipt",
|
|
427
|
+
attrs: {
|
|
428
|
+
id: msgId,
|
|
429
|
+
type: "retry",
|
|
430
|
+
to: node.attrs.from,
|
|
431
|
+
},
|
|
432
|
+
content: [
|
|
433
|
+
{
|
|
434
|
+
tag: "retry",
|
|
435
|
+
attrs: {
|
|
436
|
+
count: retryCount.toString(),
|
|
437
|
+
id: node.attrs.id,
|
|
438
|
+
t: node.attrs.t,
|
|
439
|
+
v: "1",
|
|
440
|
+
error: "0",
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
tag: "registration",
|
|
445
|
+
attrs: {},
|
|
446
|
+
content: encodeBigEndian(authState.creds.registrationId),
|
|
417
447
|
},
|
|
448
|
+
],
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (node.attrs.recipient) {
|
|
452
|
+
receipt.attrs.recipient = node.attrs.recipient
|
|
453
|
+
}
|
|
454
|
+
if (node.attrs.participant) {
|
|
455
|
+
receipt.attrs.participant = node.attrs.participant
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (retryCount > 1 || forceIncludeKeys || shouldRecreateSession) {
|
|
459
|
+
const { update, preKeys } = await getNextPreKeys(authState, 1)
|
|
460
|
+
const [keyId] = Object.keys(preKeys)
|
|
461
|
+
const key = preKeys[+keyId]
|
|
462
|
+
const content = receipt.content
|
|
463
|
+
content.push({
|
|
464
|
+
tag: "keys",
|
|
465
|
+
attrs: {},
|
|
418
466
|
content: [
|
|
419
|
-
{
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
t: node.attrs.t,
|
|
425
|
-
v: "1",
|
|
426
|
-
// ADD ERROR FIELD
|
|
427
|
-
error: "0",
|
|
428
|
-
},
|
|
429
|
-
},
|
|
430
|
-
{
|
|
431
|
-
tag: "registration",
|
|
432
|
-
attrs: {},
|
|
433
|
-
content: encodeBigEndian(authState.creds.registrationId),
|
|
434
|
-
},
|
|
467
|
+
{ tag: "type", attrs: {}, content: Buffer.from(KEY_BUNDLE_TYPE) },
|
|
468
|
+
{ tag: "identity", attrs: {}, content: identityKey.public },
|
|
469
|
+
xmppPreKey(key, +keyId),
|
|
470
|
+
xmppSignedPreKey(signedPreKey),
|
|
471
|
+
{ tag: "device-identity", attrs: {}, content: deviceIdentity },
|
|
435
472
|
],
|
|
436
|
-
}
|
|
437
|
-
if (node.attrs.recipient) {
|
|
438
|
-
receipt.attrs.recipient = node.attrs.recipient
|
|
439
|
-
}
|
|
440
|
-
if (node.attrs.participant) {
|
|
441
|
-
receipt.attrs.participant = node.attrs.participant
|
|
442
|
-
}
|
|
443
|
-
if (retryCount > 1 || forceIncludeKeys || shouldRecreateSession) {
|
|
444
|
-
const { update, preKeys } = await getNextPreKeys(authState, 1)
|
|
445
|
-
const [keyId] = Object.keys(preKeys)
|
|
446
|
-
const key = preKeys[+keyId]
|
|
447
|
-
const content = receipt.content
|
|
448
|
-
content.push({
|
|
449
|
-
tag: "keys",
|
|
450
|
-
attrs: {},
|
|
451
|
-
content: [
|
|
452
|
-
{ tag: "type", attrs: {}, content: Buffer.from(KEY_BUNDLE_TYPE) },
|
|
453
|
-
{ tag: "identity", attrs: {}, content: identityKey.public },
|
|
454
|
-
xmppPreKey(key, +keyId),
|
|
455
|
-
xmppSignedPreKey(signedPreKey),
|
|
456
|
-
{ tag: "device-identity", attrs: {}, content: deviceIdentity },
|
|
457
|
-
],
|
|
458
|
-
})
|
|
459
|
-
ev.emit("creds.update", update)
|
|
460
|
-
}
|
|
461
|
-
await sendNode(receipt)
|
|
462
|
-
logger.info({ msgAttrs: node.attrs, retryCount }, "sent retry receipt")
|
|
463
|
-
}, authState?.creds?.me?.id || "sendRetryRequest")
|
|
464
|
-
}
|
|
465
|
-
const handleEncryptNotification = async (node) => {
|
|
466
|
-
const from = node.attrs.from
|
|
467
|
-
if (from === S_WHATSAPP_NET) {
|
|
468
|
-
const countChild = getBinaryNodeChild(node, "count")
|
|
469
|
-
const count = +countChild.attrs.value
|
|
470
|
-
const shouldUploadMorePreKeys = count < MIN_PREKEY_COUNT
|
|
471
|
-
logger.debug({ count, shouldUploadMorePreKeys }, "recv pre-key count")
|
|
472
|
-
if (shouldUploadMorePreKeys) {
|
|
473
|
-
smartPreKeyMonitor("server-notification").catch(err => {
|
|
474
|
-
logger.error({ err }, "Failed to upload pre-keys after server notification")
|
|
475
473
|
})
|
|
476
|
-
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
474
|
+
ev.emit("creds.update", update)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
await sendNode(receipt)
|
|
478
|
+
logger.info({ msgAttrs: node.attrs, retryCount }, "sent retry receipt")
|
|
479
|
+
}, authState?.creds?.me?.id || "sendRetryRequest")
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const handleEncryptNotification = async (node) => {
|
|
483
|
+
const from = node.attrs.from
|
|
484
|
+
if (from === S_WHATSAPP_NET) {
|
|
485
|
+
const countChild = getBinaryNodeChild(node, "count")
|
|
486
|
+
const count = +countChild.attrs.value
|
|
487
|
+
const shouldUploadMorePreKeys = count < MIN_PREKEY_COUNT
|
|
488
|
+
logger.debug({ count, shouldUploadMorePreKeys }, "recv pre-key count")
|
|
489
|
+
if (shouldUploadMorePreKeys) {
|
|
490
|
+
// Use debounced trigger if available, otherwise fallback to direct upload
|
|
491
|
+
if (typeof triggerPreKeyCheck === 'function') {
|
|
492
|
+
triggerPreKeyCheck("server-notification", "normal")
|
|
483
493
|
} else {
|
|
484
|
-
|
|
494
|
+
await uploadPreKeys(MIN_PREKEY_COUNT)
|
|
485
495
|
}
|
|
486
496
|
}
|
|
497
|
+
} else {
|
|
498
|
+
const identityNode = getBinaryNodeChild(node, "identity")
|
|
499
|
+
if (identityNode) {
|
|
500
|
+
logger.info({ jid: from }, "identity changed")
|
|
501
|
+
} else {
|
|
502
|
+
logger.info({ node }, "unknown encrypt notification")
|
|
503
|
+
}
|
|
487
504
|
}
|
|
505
|
+
}
|
|
488
506
|
const handleGroupNotification = (fullNode, child, msg) => {
|
|
489
507
|
// TODO: Support PN/LID (Here is only LID now)
|
|
490
508
|
const actingParticipantLid = fullNode.attrs.participant
|