@hansaka02/baileys 7.3.4 → 7.3.6
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 +203 -247
- package/lib/Defaults/baileys-version.json +2 -2
- package/lib/Defaults/connection.js +1 -1
- package/lib/Defaults/constants.js +13 -1
- package/lib/Defaults/history.js +3 -1
- package/lib/Signal/Group/sender-chain-key.js +1 -14
- package/lib/Signal/Group/sender-key-distribution-message.js +2 -2
- package/lib/Signal/Group/sender-key-record.js +2 -11
- package/lib/Signal/Group/sender-key-state.js +11 -57
- package/lib/Signal/libsignal.js +200 -116
- package/lib/Signal/lid-mapping.js +121 -68
- package/lib/Socket/Client/websocket.js +9 -2
- package/lib/Socket/business.js +5 -1
- package/lib/Socket/chats.js +180 -89
- package/lib/Socket/community.js +169 -41
- package/lib/Socket/groups.js +25 -21
- package/lib/Socket/messages-recv.js +458 -333
- package/lib/Socket/messages-send.js +517 -572
- package/lib/Socket/mex.js +61 -0
- package/lib/Socket/newsletter.js +159 -252
- package/lib/Socket/socket.js +283 -100
- package/lib/Types/Newsletter.js +32 -25
- package/lib/Utils/auth-utils.js +189 -354
- package/lib/Utils/browser-utils.js +43 -0
- package/lib/Utils/chat-utils.js +166 -41
- package/lib/Utils/decode-wa-message.js +77 -35
- package/lib/Utils/event-buffer.js +80 -24
- package/lib/Utils/generics.js +28 -128
- package/lib/Utils/history.js +10 -8
- package/lib/Utils/index.js +1 -1
- package/lib/Utils/link-preview.js +17 -32
- package/lib/Utils/lt-hash.js +28 -22
- package/lib/Utils/make-mutex.js +26 -28
- package/lib/Utils/message-retry-manager.js +51 -3
- package/lib/Utils/messages-media.js +343 -151
- package/lib/Utils/messages.js +806 -792
- package/lib/Utils/noise-handler.js +33 -2
- package/lib/Utils/pre-key-manager.js +126 -0
- package/lib/Utils/process-message.js +115 -55
- package/lib/Utils/signal.js +45 -18
- package/lib/Utils/validate-connection.js +52 -29
- package/lib/WABinary/constants.js +1268 -1268
- package/lib/WABinary/decode.js +58 -4
- package/lib/WABinary/encode.js +54 -7
- package/lib/WABinary/jid-utils.js +58 -11
- package/lib/WAM/constants.js +19064 -11563
- package/lib/WAM/encode.js +57 -8
- package/lib/WAUSync/USyncQuery.js +35 -19
- package/package.json +9 -8
- package/lib/Socket/usync.js +0 -83
package/lib/Utils/auth-utils.js
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true })
|
|
4
4
|
|
|
5
5
|
const { randomBytes } = require("crypto")
|
|
6
|
+
const { default: PQueue } = require("p-queue")
|
|
6
7
|
const { default: NodeCache } = require("@cacheable/node-cache")
|
|
7
8
|
const { DEFAULT_CACHE_TTLS } = require("../Defaults/constants")
|
|
9
|
+
const { AsyncLocalStorage } = require("async_hooks")
|
|
8
10
|
const { LRUCache } = require("lru-cache")
|
|
9
11
|
const { Mutex }= require("async-mutex")
|
|
10
12
|
const {
|
|
@@ -15,6 +17,7 @@ const {
|
|
|
15
17
|
delay,
|
|
16
18
|
generateRegistrationId
|
|
17
19
|
} = require("./generics")
|
|
20
|
+
const { PreKeyManager } = require("./pre-key-manager")
|
|
18
21
|
|
|
19
22
|
/**
|
|
20
23
|
* Adds caching capability to a SignalKeyStore
|
|
@@ -83,413 +86,244 @@ function makeCacheableSignalKeyStore(store, logger, _cache) {
|
|
|
83
86
|
}
|
|
84
87
|
}
|
|
85
88
|
|
|
86
|
-
// Module-level specialized mutexes for pre-key operations
|
|
87
|
-
const preKeyMutex = new Mutex()
|
|
88
|
-
const signedPreKeyMutex = new Mutex()
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Get the appropriate mutex for the key type
|
|
92
|
-
*/
|
|
93
|
-
const getPreKeyMutex = (keyType) => {
|
|
94
|
-
return keyType === 'signed-pre-key' ? signedPreKeyMutex : preKeyMutex
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Handles pre-key operations with mutex protection
|
|
99
|
-
*/
|
|
100
|
-
async function handlePreKeyOperations(data, keyType, transactionCache, mutations, logger, isInTransaction, state) {
|
|
101
|
-
const mutex = getPreKeyMutex(keyType)
|
|
102
|
-
await mutex.runExclusive(async () => {
|
|
103
|
-
const keyData = data[keyType]
|
|
104
|
-
if (!keyData)
|
|
105
|
-
return
|
|
106
|
-
|
|
107
|
-
// Ensure structures exist
|
|
108
|
-
transactionCache[keyType] = transactionCache[keyType] || {}
|
|
109
|
-
mutations[keyType] = mutations[keyType] || {}
|
|
110
|
-
|
|
111
|
-
// Separate deletions from updates for batch processing
|
|
112
|
-
const deletionKeys = []
|
|
113
|
-
const updateKeys = []
|
|
114
|
-
|
|
115
|
-
for (const keyId in keyData) {
|
|
116
|
-
if (keyData[keyId] === null) {
|
|
117
|
-
deletionKeys.push(keyId)
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
updateKeys.push(keyId)
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Process updates first (no validation needed)
|
|
125
|
-
for (const keyId of updateKeys) {
|
|
126
|
-
if (transactionCache[keyType]) {
|
|
127
|
-
transactionCache[keyType][keyId] = keyData[keyId]
|
|
128
|
-
}
|
|
129
|
-
if (mutations[keyType]) {
|
|
130
|
-
mutations[keyType][keyId] = keyData[keyId]
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Process deletions with validation
|
|
135
|
-
if (deletionKeys.length === 0)
|
|
136
|
-
return
|
|
137
|
-
|
|
138
|
-
if (isInTransaction) {
|
|
139
|
-
// In transaction, only allow deletion if key exists in cache
|
|
140
|
-
for (const keyId of deletionKeys) {
|
|
141
|
-
if (transactionCache[keyType]) {
|
|
142
|
-
transactionCache[keyType][keyId] = null
|
|
143
|
-
if (mutations[keyType]) {
|
|
144
|
-
// Mark for deletion in mutations
|
|
145
|
-
mutations[keyType][keyId] = null
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
logger.warn(`Skipping deletion of non-existent ${keyType} in transaction: ${keyId}`)
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Outside transaction, batch validate all deletions
|
|
156
|
-
if (!state)
|
|
157
|
-
return
|
|
158
|
-
|
|
159
|
-
const existingKeys = await state.get(keyType, deletionKeys)
|
|
160
|
-
for (const keyId of deletionKeys) {
|
|
161
|
-
if (existingKeys[keyId]) {
|
|
162
|
-
if (transactionCache[keyType])
|
|
163
|
-
transactionCache[keyType][keyId] = null
|
|
164
|
-
if (mutations[keyType])
|
|
165
|
-
mutations[keyType][keyId] = null
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
logger.warn(`Skipping deletion of non-existent ${keyType}: ${keyId}`)
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
})
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Handles normal key operations for transactions
|
|
176
|
-
*/
|
|
177
|
-
function handleNormalKeyOperations(data, key, transactionCache, mutations) {
|
|
178
|
-
Object.assign(transactionCache[key], data[key])
|
|
179
|
-
mutations[key] = mutations[key] || {}
|
|
180
|
-
Object.assign(mutations[key], data[key])
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Process pre-key deletions with validation
|
|
185
|
-
*/
|
|
186
|
-
async function processPreKeyDeletions(data, keyType, state, logger) {
|
|
187
|
-
const mutex = getPreKeyMutex(keyType)
|
|
188
|
-
await mutex.runExclusive(async () => {
|
|
189
|
-
const keyData = data[keyType]
|
|
190
|
-
if (!keyData)
|
|
191
|
-
return
|
|
192
|
-
|
|
193
|
-
// Validate deletions
|
|
194
|
-
for (const keyId in keyData) {
|
|
195
|
-
if (keyData[keyId] === null) {
|
|
196
|
-
const existingKeys = await state.get(keyType, [keyId])
|
|
197
|
-
if (!existingKeys[keyId]) {
|
|
198
|
-
logger.warn(`Skipping deletion of non-existent ${keyType}: ${keyId}`)
|
|
199
|
-
if (data[keyType])
|
|
200
|
-
delete data[keyType][keyId]
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
})
|
|
205
|
-
}
|
|
206
|
-
|
|
207
89
|
/**
|
|
208
|
-
*
|
|
209
|
-
* Uses
|
|
210
|
-
*/
|
|
211
|
-
async function withMutexes(keyTypes, getKeyTypeMutex, fn) {
|
|
212
|
-
if (keyTypes.length === 0) {
|
|
213
|
-
return fn()
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (keyTypes.length === 1) {
|
|
217
|
-
return getKeyTypeMutex(keyTypes[0]).runExclusive(fn)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// For multiple mutexes, sort by key type to prevent deadlocks
|
|
221
|
-
// Then acquire all mutexes in order using Promise.all for better efficiency
|
|
222
|
-
const sortedKeyTypes = [...keyTypes].sort()
|
|
223
|
-
const mutexes = sortedKeyTypes.map(getKeyTypeMutex)
|
|
224
|
-
|
|
225
|
-
// Acquire all mutexes in order to prevent deadlocks
|
|
226
|
-
const releases = []
|
|
227
|
-
try {
|
|
228
|
-
for (const mutex of mutexes) {
|
|
229
|
-
releases.push(await mutex.acquire())
|
|
230
|
-
}
|
|
231
|
-
return await fn()
|
|
232
|
-
}
|
|
233
|
-
finally {
|
|
234
|
-
// Release in reverse order
|
|
235
|
-
while (releases.length > 0) {
|
|
236
|
-
const release = releases.pop()
|
|
237
|
-
if (release)
|
|
238
|
-
release()
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Adds DB like transaction capability (https://en.wikipedia.org/wiki/Database_transaction) to the SignalKeyStore,
|
|
245
|
-
* this allows batch read & write operations & improves the performance of the lib
|
|
90
|
+
* Adds DB-like transaction capability to the SignalKeyStore
|
|
91
|
+
* Uses AsyncLocalStorage for automatic context management
|
|
246
92
|
* @param state the key store to apply this capability to
|
|
247
93
|
* @param logger logger to log events
|
|
248
94
|
* @returns SignalKeyStore with transaction capability
|
|
249
95
|
*/
|
|
250
96
|
const addTransactionCapability = (state, logger, { maxCommitRetries, delayBetweenTriesMs }) => {
|
|
251
|
-
|
|
252
|
-
// only there for logging purposes
|
|
253
|
-
let dbQueriesInTransaction = 0
|
|
254
|
-
let transactionCache = {}
|
|
255
|
-
let mutations = {}
|
|
97
|
+
const txStorage = new AsyncLocalStorage()
|
|
256
98
|
|
|
257
|
-
//
|
|
258
|
-
const
|
|
259
|
-
ttl: 60 * 60 * 1000, // 1 hour
|
|
260
|
-
ttlAutopurge: true,
|
|
261
|
-
updateAgeOnGet: true
|
|
262
|
-
})
|
|
99
|
+
// Queues for concurrency control (keyed by signal data type - bounded set)
|
|
100
|
+
const keyQueues = new Map()
|
|
263
101
|
|
|
264
|
-
|
|
102
|
+
// Transaction mutexes with reference counting for cleanup
|
|
103
|
+
const txMutexes = new Map()
|
|
265
104
|
|
|
266
|
-
|
|
267
|
-
return getMutex(`keytype:${type}`)
|
|
268
|
-
}
|
|
105
|
+
const txMutexRefCounts = new Map()
|
|
269
106
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
107
|
+
// Pre-key manager for specialized operations
|
|
108
|
+
const preKeyManager = new PreKeyManager(state, logger)
|
|
273
109
|
|
|
274
|
-
|
|
275
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Get or create a queue for a specific key type
|
|
112
|
+
*/
|
|
113
|
+
function getQueue(key) {
|
|
114
|
+
if (!keyQueues.has(key)) {
|
|
115
|
+
keyQueues.set(key, new PQueue({ concurrency: 1 }))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return keyQueues.get(key)
|
|
276
119
|
}
|
|
277
120
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
121
|
+
/**
|
|
122
|
+
* Get or create a transaction mutex
|
|
123
|
+
*/
|
|
124
|
+
function getTxMutex(key) {
|
|
125
|
+
if (!txMutexes.has(key)) {
|
|
126
|
+
txMutexes.set(key, new Mutex())
|
|
127
|
+
txMutexRefCounts.set(key, 0)
|
|
285
128
|
}
|
|
286
|
-
|
|
129
|
+
|
|
130
|
+
return txMutexes.get(key)
|
|
287
131
|
}
|
|
288
132
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Acquire a reference to a transaction mutex
|
|
135
|
+
*/
|
|
136
|
+
function acquireTxMutexRef(key) {
|
|
137
|
+
const count = txMutexRefCounts.get(key) ?? 0
|
|
138
|
+
txMutexRefCounts.set(key, count + 1)
|
|
292
139
|
}
|
|
293
140
|
|
|
294
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Release a reference to a transaction mutex and cleanup if no longer needed
|
|
143
|
+
*/
|
|
144
|
+
function releaseTxMutexRef(key) {
|
|
145
|
+
const count = (txMutexRefCounts.get(key) ?? 1) - 1
|
|
146
|
+
|
|
147
|
+
txMutexRefCounts.set(key, count)
|
|
148
|
+
|
|
149
|
+
// Cleanup if no more references and mutex is not locked
|
|
150
|
+
if (count <= 0) {
|
|
151
|
+
const mutex = txMutexes.get(key)
|
|
152
|
+
|
|
153
|
+
if (mutex && !mutex.isLocked()) {
|
|
154
|
+
txMutexes.delete(key)
|
|
155
|
+
txMutexRefCounts.delete(key)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Check if currently in a transaction
|
|
162
|
+
*/
|
|
295
163
|
function isInTransaction() {
|
|
296
|
-
return
|
|
164
|
+
return !!txStorage.getStore()
|
|
297
165
|
}
|
|
298
166
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
167
|
+
/**
|
|
168
|
+
* Commit transaction with retries
|
|
169
|
+
*/
|
|
170
|
+
async function commitWithRetry(mutations) {
|
|
171
|
+
if (Object.keys(mutations).length === 0) {
|
|
302
172
|
logger.trace('no mutations in transaction')
|
|
303
173
|
return
|
|
304
174
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
175
|
+
|
|
176
|
+
logger.trace('committing transaction')
|
|
177
|
+
|
|
178
|
+
for (let attempt = 0; attempt < maxCommitRetries; attempt++) {
|
|
309
179
|
try {
|
|
310
180
|
await state.set(mutations)
|
|
311
|
-
logger.trace({
|
|
181
|
+
logger.trace({ mutationCount: Object.keys(mutations).length }, 'committed transaction')
|
|
312
182
|
return
|
|
313
183
|
}
|
|
184
|
+
|
|
314
185
|
catch (error) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
186
|
+
const retriesLeft = maxCommitRetries - attempt - 1
|
|
187
|
+
|
|
188
|
+
logger.warn(`failed to commit mutations, retries left=${retriesLeft}`)
|
|
189
|
+
|
|
190
|
+
if (retriesLeft === 0) {
|
|
191
|
+
throw error
|
|
318
192
|
}
|
|
193
|
+
|
|
194
|
+
await delay(delayBetweenTriesMs)
|
|
319
195
|
}
|
|
320
196
|
}
|
|
321
197
|
}
|
|
322
198
|
|
|
323
|
-
// Helper function to clean up transaction state
|
|
324
|
-
function cleanupTransactionState() {
|
|
325
|
-
transactionsInProgress -= 1
|
|
326
|
-
if (transactionsInProgress === 0) {
|
|
327
|
-
transactionCache = {}
|
|
328
|
-
mutations = {}
|
|
329
|
-
dbQueriesInTransaction = 0
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Helper function to execute work within transaction
|
|
334
|
-
async function executeTransactionWork(work) {
|
|
335
|
-
const result = await work()
|
|
336
|
-
// commit if this is the outermost transaction
|
|
337
|
-
if (transactionsInProgress === 1) {
|
|
338
|
-
await commitTransaction()
|
|
339
|
-
}
|
|
340
|
-
return result
|
|
341
|
-
}
|
|
342
|
-
|
|
343
199
|
return {
|
|
344
200
|
get: async (type, ids) => {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
201
|
+
const ctx = txStorage.getStore()
|
|
202
|
+
|
|
203
|
+
if (!ctx) {
|
|
204
|
+
// No transaction - direct read without exclusive lock for concurrency
|
|
205
|
+
return state.get(type, ids)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// In transaction - check cache first
|
|
209
|
+
const cached = ctx.cache[type] || {}
|
|
210
|
+
const missing = ids.filter(id => !(id in cached))
|
|
211
|
+
|
|
212
|
+
if (missing.length > 0) {
|
|
213
|
+
ctx.dbQueries++
|
|
348
214
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
// For sender keys, process each one with queued operations to maintain serialization
|
|
357
|
-
for (const senderKeyName of idsRequiringFetch) {
|
|
358
|
-
await queueSenderKeyOperation(senderKeyName, async () => {
|
|
359
|
-
logger.info({ senderKeyName }, 'fetching sender key in transaction')
|
|
360
|
-
const result = await state.get(type, [senderKeyName])
|
|
361
|
-
// Update transaction cache
|
|
362
|
-
transactionCache[type] || (transactionCache[type] = {})
|
|
363
|
-
Object.assign(transactionCache[type], result)
|
|
364
|
-
logger.info({ senderKeyName, hasResult: !!result[senderKeyName] }, 'sender key fetch complete')
|
|
365
|
-
})
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
else {
|
|
369
|
-
// Use runExclusive for cleaner mutex handling
|
|
370
|
-
await getKeyTypeMutex(type).runExclusive(async () => {
|
|
371
|
-
const result = await state.get(type, idsRequiringFetch)
|
|
372
|
-
// Update transaction cache
|
|
373
|
-
transactionCache[type] || (transactionCache[type] = {})
|
|
374
|
-
Object.assign(transactionCache[type], result)
|
|
375
|
-
})
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
return ids.reduce((dict, id) => {
|
|
379
|
-
const value = transactionCache[type]?.[id]
|
|
380
|
-
if (value) {
|
|
381
|
-
dict[id] = value
|
|
382
|
-
}
|
|
383
|
-
return dict
|
|
384
|
-
}, {})
|
|
215
|
+
logger.trace({ type, count: missing.length }, 'fetching missing keys in transaction')
|
|
216
|
+
|
|
217
|
+
const fetched = await getTxMutex(type).runExclusive(() => state.get(type, missing))
|
|
218
|
+
|
|
219
|
+
// Update cache
|
|
220
|
+
ctx.cache[type] = ctx.cache[type] || {};
|
|
221
|
+
Object.assign(ctx.cache[type], fetched);
|
|
385
222
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
return results
|
|
396
|
-
}
|
|
397
|
-
else {
|
|
398
|
-
return await getKeyTypeMutex(type).runExclusive(() => state.get(type, ids))
|
|
223
|
+
|
|
224
|
+
// Return requested ids from cache
|
|
225
|
+
const result = {}
|
|
226
|
+
|
|
227
|
+
for (const id of ids) {
|
|
228
|
+
const value = ctx.cache[type]?.[id]
|
|
229
|
+
|
|
230
|
+
if (value !== undefined && value !== null) {
|
|
231
|
+
result[id] = value;
|
|
399
232
|
}
|
|
400
233
|
}
|
|
234
|
+
|
|
235
|
+
return result
|
|
401
236
|
},
|
|
402
237
|
set: async (data) => {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
handleNormalKeyOperations(data, key, transactionCache, mutations)
|
|
238
|
+
const ctx = txStorage.getStore()
|
|
239
|
+
|
|
240
|
+
if (!ctx) {
|
|
241
|
+
// No transaction - direct write with queue protection
|
|
242
|
+
const types = Object.keys(data)
|
|
243
|
+
|
|
244
|
+
// Process pre-keys with validation
|
|
245
|
+
for (const type_ of types) {
|
|
246
|
+
const type = type_
|
|
247
|
+
if (type === 'pre-key') {
|
|
248
|
+
await preKeyManager.validateDeletions(data, type)
|
|
415
249
|
}
|
|
416
250
|
}
|
|
251
|
+
|
|
252
|
+
// Write all data in parallel
|
|
253
|
+
await Promise.all(types.map(type => getQueue(type).add(async () => {
|
|
254
|
+
const typeData = { [type]: data[type] }
|
|
255
|
+
await state.set(typeData)
|
|
256
|
+
})))
|
|
257
|
+
|
|
258
|
+
return
|
|
417
259
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
};
|
|
433
|
-
logger.trace({ senderKeyName }, 'storing sender key')
|
|
434
|
-
// Apply changes to the store
|
|
435
|
-
await state.set(senderKeyData)
|
|
436
|
-
logger.trace({ senderKeyName }, 'sender key stored')
|
|
437
|
-
})
|
|
438
|
-
}
|
|
439
|
-
// Handle any non-sender-key data with regular mutexes
|
|
440
|
-
const nonSenderKeyData = { ...data }
|
|
441
|
-
delete nonSenderKeyData['sender-key']
|
|
442
|
-
if (Object.keys(nonSenderKeyData).length > 0) {
|
|
443
|
-
await withMutexes(Object.keys(nonSenderKeyData), getKeyTypeMutex, async () => {
|
|
444
|
-
// Process pre-keys and signed-pre-keys separately with specialized mutexes
|
|
445
|
-
for (const key_ in nonSenderKeyData) {
|
|
446
|
-
const keyType = key_
|
|
447
|
-
if (keyType === 'pre-key') {
|
|
448
|
-
await processPreKeyDeletions(nonSenderKeyData, keyType, state, logger)
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
// Apply changes to the store
|
|
452
|
-
await state.set(nonSenderKeyData)
|
|
453
|
-
})
|
|
454
|
-
}
|
|
260
|
+
|
|
261
|
+
// In transaction - update cache and mutations
|
|
262
|
+
logger.trace({ types: Object.keys(data) }, 'caching in transaction')
|
|
263
|
+
|
|
264
|
+
for (const key_ in data) {
|
|
265
|
+
const key = key_
|
|
266
|
+
|
|
267
|
+
// Ensure structures exist
|
|
268
|
+
ctx.cache[key] = ctx.cache[key] || {}
|
|
269
|
+
ctx.mutations[key] = ctx.mutations[key] || {}
|
|
270
|
+
|
|
271
|
+
// Special handling for pre-keys
|
|
272
|
+
if (key === 'pre-key') {
|
|
273
|
+
await preKeyManager.processOperations(data, key, ctx.cache, ctx.mutations, true)
|
|
455
274
|
}
|
|
275
|
+
|
|
456
276
|
else {
|
|
457
|
-
//
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
for (const key_ in data) {
|
|
461
|
-
const keyType = key_
|
|
462
|
-
if (keyType === 'pre-key') {
|
|
463
|
-
await processPreKeyDeletions(data, keyType, state, logger)
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
// Apply changes to the store
|
|
467
|
-
await state.set(data)
|
|
468
|
-
})
|
|
277
|
+
// Normal key types
|
|
278
|
+
Object.assign(ctx.cache[key], data[key])
|
|
279
|
+
Object.assign(ctx.mutations[key], data[key])
|
|
469
280
|
}
|
|
470
281
|
}
|
|
471
282
|
},
|
|
472
283
|
isInTransaction,
|
|
473
|
-
async
|
|
474
|
-
const
|
|
284
|
+
transaction: async (work, key) => {
|
|
285
|
+
const existing = txStorage.getStore()
|
|
286
|
+
|
|
287
|
+
// Nested transaction - reuse existing context
|
|
288
|
+
if (existing) {
|
|
289
|
+
logger.trace('reusing existing transaction context')
|
|
290
|
+
return work()
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// New transaction - acquire mutex and create context
|
|
294
|
+
const mutex = getTxMutex(key)
|
|
295
|
+
|
|
296
|
+
acquireTxMutexRef(key)
|
|
297
|
+
|
|
475
298
|
try {
|
|
476
|
-
|
|
477
|
-
|
|
299
|
+
return await mutex.runExclusive(async () => {
|
|
300
|
+
const ctx = {
|
|
301
|
+
cache: {},
|
|
302
|
+
mutations: {},
|
|
303
|
+
dbQueries: 0
|
|
304
|
+
}
|
|
305
|
+
|
|
478
306
|
logger.trace('entering transaction')
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
const result = await txStorage.run(ctx, work)
|
|
310
|
+
|
|
311
|
+
// Commit mutations
|
|
312
|
+
await commitWithRetry(ctx.mutations)
|
|
313
|
+
|
|
314
|
+
logger.trace({ dbQueries: ctx.dbQueries }, 'transaction completed')
|
|
315
|
+
|
|
316
|
+
return result
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
catch (error) {
|
|
320
|
+
logger.error({ error }, 'transaction failed, rolling back')
|
|
321
|
+
throw error
|
|
322
|
+
}
|
|
323
|
+
})
|
|
489
324
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
throw error
|
|
325
|
+
finally {
|
|
326
|
+
releaseTxMutexRef(key)
|
|
493
327
|
}
|
|
494
328
|
}
|
|
495
329
|
}
|
|
@@ -514,7 +348,8 @@ const initAuthCreds = () => {
|
|
|
514
348
|
registered: false,
|
|
515
349
|
pairingCode: undefined,
|
|
516
350
|
lastPropHash: undefined,
|
|
517
|
-
routingInfo: undefined
|
|
351
|
+
routingInfo: undefined,
|
|
352
|
+
additionalData: undefined
|
|
518
353
|
}
|
|
519
354
|
}
|
|
520
355
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true })
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
platform,
|
|
7
|
+
release
|
|
8
|
+
} = require("os")
|
|
9
|
+
const { proto } = require("../../WAProto")
|
|
10
|
+
|
|
11
|
+
const PLATFORM_MAP = {
|
|
12
|
+
aix: 'AIX',
|
|
13
|
+
darwin: 'Mac OS',
|
|
14
|
+
win32: 'Windows',
|
|
15
|
+
android: 'Android',
|
|
16
|
+
freebsd: 'FreeBSD',
|
|
17
|
+
openbsd: 'OpenBSD',
|
|
18
|
+
sunos: 'Solaris',
|
|
19
|
+
linux: undefined,
|
|
20
|
+
haiku: undefined,
|
|
21
|
+
cygwin: undefined,
|
|
22
|
+
netbsd: undefined
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const Browsers = {
|
|
26
|
+
ubuntu: browser => ['Ubuntu', browser, '22.04.4'],
|
|
27
|
+
macOS: browser => ['Mac OS', browser, '14.4.1'],
|
|
28
|
+
baileys: browser => ['Baileys', browser, '6.5.0'],
|
|
29
|
+
windows: browser => ['Windows', browser, '10.0.22631'],
|
|
30
|
+
//android: browser => [browser, 'Android', ''],
|
|
31
|
+
/** The appropriate browser based on your OS & release */
|
|
32
|
+
appropriate: browser => [PLATFORM_MAP[platform()] || 'Ubuntu', browser, release()]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const getPlatformId = (browser) => {
|
|
36
|
+
const platformType = proto.DeviceProps.PlatformType[browser.toUpperCase()]
|
|
37
|
+
return platformType ? platformType.toString() : '1' //chrome
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
Browsers,
|
|
42
|
+
getPlatformId
|
|
43
|
+
}
|