@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.
Files changed (50) hide show
  1. package/README.md +203 -247
  2. package/lib/Defaults/baileys-version.json +2 -2
  3. package/lib/Defaults/connection.js +1 -1
  4. package/lib/Defaults/constants.js +13 -1
  5. package/lib/Defaults/history.js +3 -1
  6. package/lib/Signal/Group/sender-chain-key.js +1 -14
  7. package/lib/Signal/Group/sender-key-distribution-message.js +2 -2
  8. package/lib/Signal/Group/sender-key-record.js +2 -11
  9. package/lib/Signal/Group/sender-key-state.js +11 -57
  10. package/lib/Signal/libsignal.js +200 -116
  11. package/lib/Signal/lid-mapping.js +121 -68
  12. package/lib/Socket/Client/websocket.js +9 -2
  13. package/lib/Socket/business.js +5 -1
  14. package/lib/Socket/chats.js +180 -89
  15. package/lib/Socket/community.js +169 -41
  16. package/lib/Socket/groups.js +25 -21
  17. package/lib/Socket/messages-recv.js +458 -333
  18. package/lib/Socket/messages-send.js +517 -572
  19. package/lib/Socket/mex.js +61 -0
  20. package/lib/Socket/newsletter.js +159 -252
  21. package/lib/Socket/socket.js +283 -100
  22. package/lib/Types/Newsletter.js +32 -25
  23. package/lib/Utils/auth-utils.js +189 -354
  24. package/lib/Utils/browser-utils.js +43 -0
  25. package/lib/Utils/chat-utils.js +166 -41
  26. package/lib/Utils/decode-wa-message.js +77 -35
  27. package/lib/Utils/event-buffer.js +80 -24
  28. package/lib/Utils/generics.js +28 -128
  29. package/lib/Utils/history.js +10 -8
  30. package/lib/Utils/index.js +1 -1
  31. package/lib/Utils/link-preview.js +17 -32
  32. package/lib/Utils/lt-hash.js +28 -22
  33. package/lib/Utils/make-mutex.js +26 -28
  34. package/lib/Utils/message-retry-manager.js +51 -3
  35. package/lib/Utils/messages-media.js +343 -151
  36. package/lib/Utils/messages.js +806 -792
  37. package/lib/Utils/noise-handler.js +33 -2
  38. package/lib/Utils/pre-key-manager.js +126 -0
  39. package/lib/Utils/process-message.js +115 -55
  40. package/lib/Utils/signal.js +45 -18
  41. package/lib/Utils/validate-connection.js +52 -29
  42. package/lib/WABinary/constants.js +1268 -1268
  43. package/lib/WABinary/decode.js +58 -4
  44. package/lib/WABinary/encode.js +54 -7
  45. package/lib/WABinary/jid-utils.js +58 -11
  46. package/lib/WAM/constants.js +19064 -11563
  47. package/lib/WAM/encode.js +57 -8
  48. package/lib/WAUSync/USyncQuery.js +35 -19
  49. package/package.json +9 -8
  50. package/lib/Socket/usync.js +0 -83
@@ -9,9 +9,14 @@ const {
9
9
  ProtocolAddress
10
10
  } = require("@itsukichan/libsignal-node")
11
11
  const { generateSignalPubKey } = require("../Utils")
12
- const {
12
+ const {
13
+ isHostedLidUser,
14
+ isHostedPnUser,
15
+ isLidUser,
16
+ isPnUser,
13
17
  jidDecode,
14
- transferDevice
18
+ transferDevice,
19
+ WAJIDDomains
15
20
  } = require("../WABinary")
16
21
  const { SenderKeyName } = require("./Group/sender-key-name")
17
22
  const { SenderKeyRecord } = require("./Group/sender-key-record")
@@ -20,56 +25,64 @@ const {
20
25
  GroupSessionBuilder,
21
26
  SenderKeyDistributionMessage
22
27
  } = require("./Group")
28
+ const { LRUCache } = require("lru-cache")
23
29
  const { LIDMappingStore } = require("./lid-mapping")
24
30
 
25
- function makeLibSignalRepository(auth, onWhatsAppFunc, logger) {
26
- const lidMapping = new LIDMappingStore(auth.keys, onWhatsAppFunc, logger)
31
+ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
32
+ const lidMapping = new LIDMappingStore(auth.keys, logger, pnToLIDFunc)
27
33
  const storage = signalStorage(auth, lidMapping)
28
34
  const parsedKeys = auth.keys
29
-
30
- function isLikelySyncMessage(addr) {
31
- const key = addr.toString()
32
- // Only bypass for WhatsApp system addresses, not regular user contacts
33
- // Be very specific about sync service patterns
34
- return (key.includes('@lid.whatsapp.net') || // WhatsApp system messages
35
- key.includes('@broadcast') || // Broadcast messages
36
- key.includes('@newsletter'))
37
- }
35
+ const migratedSessionCache = new LRUCache({
36
+ ttl: 3 * 24 * 60 * 60 * 1000, // 7 days
37
+ ttlAutopurge: true,
38
+ updateAgeOnGet: true
39
+ })
38
40
 
39
41
  const repository = {
40
42
  decryptGroupMessage({ group, authorJid, msg }) {
41
43
  const senderName = jidToSignalSenderKeyName(group, authorJid)
42
44
  const cipher = new GroupCipher(storage, senderName)
45
+
43
46
  // Use transaction to ensure atomicity
44
47
  return parsedKeys.transaction(async () => {
45
48
  return cipher.decrypt(msg)
46
49
  }, group)
47
50
  },
51
+
48
52
  async processSenderKeyDistributionMessage({ item, authorJid }) {
49
53
  const builder = new GroupSessionBuilder(storage)
54
+
50
55
  if (!item.groupId) {
51
56
  throw new Error('Group ID is required for sender key distribution message')
52
57
  }
58
+
53
59
  const senderName = jidToSignalSenderKeyName(item.groupId, authorJid)
54
60
  const senderMsg = new SenderKeyDistributionMessage(null, null, null, null, item.axolotlSenderKeyDistributionMessage)
55
61
  const senderNameStr = senderName.toString()
56
62
  const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr])
63
+
57
64
  if (!senderKey) {
58
65
  await storage.storeSenderKey(senderName, new SenderKeyRecord())
59
66
  }
67
+
60
68
  return parsedKeys.transaction(async () => {
61
69
  const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr])
70
+
62
71
  if (!senderKey) {
63
72
  await storage.storeSenderKey(senderName, new SenderKeyRecord())
64
73
  }
74
+
65
75
  await builder.process(senderName, senderMsg)
66
76
  }, item.groupId)
67
77
  },
78
+
68
79
  async decryptMessage({ jid, type, ciphertext }) {
69
80
  const addr = jidToSignalProtocolAddress(jid)
70
81
  const session = new SessionCipher(storage, addr)
82
+
71
83
  async function doDecrypt() {
72
84
  let result
85
+
73
86
  switch (type) {
74
87
  case 'pkmsg':
75
88
  result = await session.decryptPreKeyWhisperMessage(ciphertext)
@@ -78,98 +91,91 @@ function makeLibSignalRepository(auth, onWhatsAppFunc, logger) {
78
91
  result = await session.decryptWhisperMessage(ciphertext)
79
92
  break
80
93
  }
94
+
81
95
  return result
82
96
  }
83
- if (isLikelySyncMessage(addr)) {
84
- // If it's a sync message, we can skip the transaction
85
- // as it is likely to be a system message that doesn't require strict atomicity
86
- return await doDecrypt()
87
- }
97
+
88
98
  // If it's not a sync message, we need to ensure atomicity
89
99
  // For regular messages, we use a transaction to ensure atomicity
90
100
  return parsedKeys.transaction(async () => {
91
101
  return await doDecrypt()
92
102
  }, jid)
93
103
  },
104
+
94
105
  async encryptMessage({ jid, data }) {
95
- // LID SINGLE SOURCE OF TRUTH: Always prefer LID when available
96
- let encryptionJid = jid
97
- // Check for LID mapping and use it if session exists
98
- if (jid.includes('@s.whatsapp.net')) {
99
- const lidForPN = await lidMapping.getLIDForPN(jid)
100
- if (lidForPN?.includes('@lid')) {
101
- const lidAddr = jidToSignalProtocolAddress(lidForPN)
102
- const { [lidAddr.toString()]: lidSession } = await auth.keys.get('session', [lidAddr.toString()])
103
- if (lidSession) {
104
- // LID session exists, use it
105
- encryptionJid = lidForPN
106
- }
107
- else {
108
- // Try to migrate if PN session exists
109
- const pnAddr = jidToSignalProtocolAddress(jid)
110
- const { [pnAddr.toString()]: pnSession } = await auth.keys.get('session', [pnAddr.toString()])
111
- if (pnSession) {
112
- // Migrate PN to LID
113
- await repository.migrateSession([jid], lidForPN)
114
- encryptionJid = lidForPN
115
- }
116
- }
117
- }
118
- }
119
- const addr = jidToSignalProtocolAddress(encryptionJid)
106
+ const addr = jidToSignalProtocolAddress(jid)
120
107
  const cipher = new SessionCipher(storage, addr)
108
+
121
109
  // Use transaction to ensure atomicity
122
110
  return parsedKeys.transaction(async () => {
123
111
  const { type: sigType, body } = await cipher.encrypt(data)
124
112
  const type = sigType === 3 ? 'pkmsg' : 'msg'
113
+
125
114
  return { type, ciphertext: Buffer.from(body, 'binary') }
126
115
  }, jid)
127
116
  },
117
+
128
118
  async encryptGroupMessage({ group, meId, data }) {
129
119
  const senderName = jidToSignalSenderKeyName(group, meId)
130
120
  const builder = new GroupSessionBuilder(storage)
131
121
  const senderNameStr = senderName.toString()
122
+
132
123
  return parsedKeys.transaction(async () => {
133
124
  const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr])
125
+
134
126
  if (!senderKey) {
135
127
  await storage.storeSenderKey(senderName, new SenderKeyRecord())
136
128
  }
129
+
137
130
  const senderKeyDistributionMessage = await builder.create(senderName)
138
131
  const session = new GroupCipher(storage, senderName)
139
132
  const ciphertext = await session.encrypt(data)
133
+
140
134
  return {
141
135
  ciphertext,
142
136
  senderKeyDistributionMessage: senderKeyDistributionMessage.serialize()
143
137
  }
144
138
  }, group)
145
- },
139
+ },
140
+
146
141
  async injectE2ESession({ jid, session }) {
142
+ logger.trace({ jid }, 'injecting E2EE session')
143
+
147
144
  const cipher = new SessionBuilder(storage, jidToSignalProtocolAddress(jid))
145
+
148
146
  return parsedKeys.transaction(async () => {
149
147
  await cipher.initOutgoing(session)
150
148
  }, jid)
151
149
  },
150
+
152
151
  jidToSignalProtocolAddress(jid) {
153
152
  return jidToSignalProtocolAddress(jid).toString()
154
153
  },
154
+
155
155
  // Optimized direct access to LID mapping store
156
156
  lidMapping,
157
+
157
158
  async validateSession(jid) {
158
159
  try {
159
160
  const addr = jidToSignalProtocolAddress(jid)
160
161
  const session = await storage.loadSession(addr.toString())
162
+
161
163
  if (!session) {
162
164
  return { exists: false, reason: 'no session' }
163
165
  }
166
+
164
167
  if (!session.haveOpenSession()) {
165
168
  return { exists: false, reason: 'no open session' }
166
169
  }
170
+
167
171
  return { exists: true }
168
172
  }
173
+
169
174
  catch (error) {
170
175
  return { exists: false, reason: 'validation error' }
171
176
  }
172
177
  },
178
+
173
179
  async deleteSession(jids) {
174
180
  if (!jids.length) return
175
181
 
@@ -186,28 +192,78 @@ function makeLibSignalRepository(auth, onWhatsAppFunc, logger) {
186
192
  await auth.keys.set({ session: sessionUpdates })
187
193
  }, `delete-${jids.length}-sessions`)
188
194
  },
189
- async migrateSession(fromJids, toJid) {
190
- if (!fromJids.length || !toJid.includes('@lid'))
195
+
196
+ async migrateSession(fromJid, toJid) {
197
+ // TODO: use usync to handle this entire mess
198
+ if (!fromJid || (!isLidUser(toJid) && !isHostedLidUser(toJid))) {
191
199
  return { migrated: 0, skipped: 0, total: 0 }
192
-
193
- // Filter valid PN JIDs
194
- const validJids = fromJids.filter(jid => jid.includes('@s.whatsapp.net'))
200
+ }
195
201
 
196
- if (!validJids.length)
197
- return { migrated: 0, skipped: 0, total: fromJids.length }
198
-
199
- // Single optimized transaction for all migrations
202
+ // Only support PN to LID migration
203
+ if (!isPnUser(fromJid) && !isHostedPnUser(fromJid)) {
204
+ return { migrated: 0, skipped: 0, total: 1 }
205
+ }
206
+
207
+ const { user } = jidDecode(fromJid)
208
+
209
+ logger.debug({ fromJid }, 'bulk device migration - loading all user devices')
210
+
211
+ // Get user's device list from storage
212
+ const { [user]: userDevices } = await parsedKeys.get('device-list', [user])
213
+
214
+ if (!userDevices) {
215
+ return { migrated: 0, skipped: 0, total: 0 }
216
+ }
217
+
218
+ const { device: fromDevice } = jidDecode(fromJid)
219
+ const fromDeviceStr = fromDevice?.toString() || '0'
220
+
221
+ if (!userDevices.includes(fromDeviceStr)) {
222
+ userDevices.push(fromDeviceStr)
223
+ }
224
+
225
+ // Filter out cached devices before database fetch
226
+ const uncachedDevices = userDevices.filter(device => {
227
+ const deviceKey = `${user}.${device}`
228
+ return !migratedSessionCache.has(deviceKey)
229
+ })
230
+
231
+ // Bulk check session existence only for uncached devices
232
+ const deviceSessionKeys = uncachedDevices.map(device => `${user}.${device}`)
233
+ const existingSessions = await parsedKeys.get('session', deviceSessionKeys)
234
+
235
+ // Step 3: Convert existing sessions to JIDs (only migrate sessions that exist)
236
+ const deviceJids = []
237
+
238
+ for (const [sessionKey, sessionData] of Object.entries(existingSessions)) {
239
+ if (sessionData) {
240
+ // Session exists in storage
241
+ const deviceStr = sessionKey.split('.')[1]
242
+
243
+ if (!deviceStr) continue
244
+
245
+ const deviceNum = parseInt(deviceStr)
246
+
247
+ let jid = deviceNum === 0 ? `${user}@s.whatsapp.net` : `${user}:${deviceNum}@s.whatsapp.net`
248
+
249
+ if (deviceNum === 99) {
250
+ jid = `${user}:99@hosted`
251
+ }
252
+
253
+ deviceJids.push(jid)
254
+ }
255
+ }
256
+
257
+ logger.debug({
258
+ fromJid,
259
+ totalDevices: userDevices.length,
260
+ devicesWithSessions: deviceJids.length,
261
+ devices: deviceJids
262
+ }, 'bulk device migration complete - all user devices processed')
263
+
264
+ // Single transaction for all migrations
200
265
  return parsedKeys.transaction(async () => {
201
- // 1. Batch store all LID mappings
202
- const mappings = validJids.map(jid => ({
203
- lid: transferDevice(jid, toJid),
204
- pn: jid
205
- }))
206
-
207
- await lidMapping.storeLIDPNMappings(mappings)
208
-
209
- // 2. Prepare migration operations
210
- const migrationOps = validJids.map(jid => {
266
+ const migrationOps = deviceJids.map(jid => {
211
267
  const lidWithDevice = transferDevice(jid, toJid)
212
268
  const fromDecoded = jidDecode(jid)
213
269
  const toDecoded = jidDecode(lidWithDevice)
@@ -223,56 +279,75 @@ function makeLibSignalRepository(auth, onWhatsAppFunc, logger) {
223
279
  }
224
280
  })
225
281
 
226
- // 3. Batch check which LID sessions already exist
227
- const lidAddrs = migrationOps.map(op => op.toAddr.toString())
228
- const existingSessions = await auth.keys.get('session', lidAddrs)
282
+ const totalOps = migrationOps.length
229
283
 
230
- // 4. Filter out sessions that already have LID sessions
231
- const opsToMigrate = migrationOps.filter(op => !existingSessions[op.toAddr.toString()])
232
- const skippedCount = migrationOps.length - opsToMigrate.length
284
+ let migratedCount = 0
233
285
 
234
- if (!opsToMigrate.length) {
235
- return { migrated: 0, skipped: skippedCount, total: validJids.length };
236
- }
286
+ // Bulk fetch PN sessions - already exist (verified during device discovery)
287
+ const pnAddrStrings = Array.from(new Set(migrationOps.map(op => op.fromAddr.toString())))
288
+ const pnSessions = await parsedKeys.get('session', pnAddrStrings)
237
289
 
238
- // 5. Execute all migrations in parallel
239
- await Promise.all(opsToMigrate.map(async (op) => {
240
- const fromSession = await storage.loadSession(op.fromAddr.toString())
290
+ // Prepare bulk session updates (PN → LID migration + deletion)
291
+ const sessionUpdates = {}
292
+
293
+ for (const op of migrationOps) {
294
+ const pnAddrStr = op.fromAddr.toString()
295
+ const lidAddrStr = op.toAddr.toString()
296
+ const pnSession = pnSessions[pnAddrStr]
241
297
 
242
- if (fromSession?.haveOpenSession()) {
243
- // Copy session to LID address
244
- const sessionBytes = fromSession.serialize()
245
- const copiedSession = SessionRecord.deserialize(sessionBytes)
246
- await storage.storeSession(op.toAddr.toString(), copiedSession)
298
+ if (pnSession) {
299
+ // Session exists (guaranteed from device discovery)
300
+ const fromSession = SessionRecord.deserialize(pnSession)
247
301
 
248
- // Delete PN session
249
- await auth.keys.set({ session: { [op.fromAddr.toString()]: null } })
302
+ if (fromSession.haveOpenSession()) {
303
+ // Queue for bulk update: copy to LID, delete from PN
304
+ sessionUpdates[lidAddrStr] = fromSession.serialize()
305
+ sessionUpdates[pnAddrStr] = null
306
+ migratedCount++
307
+ }
250
308
  }
251
- }))
309
+ }
252
310
 
253
- return { migrated: opsToMigrate.length, skipped: skippedCount, total: validJids.length }
254
- }, `migrate-${validJids.length}-sessions-${jidDecode(toJid)?.user}`)
255
- },
256
- async encryptMessageWithWire({ encryptionJid, wireJid, data }) {
257
- const result = await repository.encryptMessage({ jid: encryptionJid, data })
258
- return { ...result, wireJid }
311
+ // Single bulk session update for all migrations
312
+ if (Object.keys(sessionUpdates).length > 0) {
313
+ await parsedKeys.set({ session: sessionUpdates })
314
+
315
+ logger.debug({ migratedSessions: migratedCount }, 'bulk session migration complete')
316
+
317
+ // Cache device-level migrations
318
+ for (const op of migrationOps) {
319
+ if (sessionUpdates[op.toAddr.toString()]) {
320
+ const deviceKey = `${op.pnUser}.${op.deviceId}`
321
+ migratedSessionCache.set(deviceKey, true)
322
+ }
323
+ }
324
+ }
325
+
326
+ const skippedCount = totalOps - migratedCount
327
+
328
+ return { migrated: migratedCount, skipped: skippedCount, total: totalOps }
329
+ }, `migrate-${deviceJids.length}-sessions-${jidDecode(toJid)?.user}`)
259
330
  }
260
331
  }
332
+
261
333
  return repository
262
334
  }
263
335
 
264
336
  const jidToSignalProtocolAddress = (jid) => {
265
337
  const decoded = jidDecode(jid)
266
- const { user, device, server } = decoded
338
+ const { user, device, server, domainType } = decoded
267
339
 
268
340
  if (!user) {
269
341
  throw new Error(`JID decoded but user is empty: "${jid}" -> user: "${user}", server: "${server}", device: ${device}`)
270
342
  }
271
343
 
272
- // LID addresses get _1 suffix for Signal protocol
273
- const signalUser = server === 'lid' ? `${user}_1` : user
344
+ const signalUser = domainType !== WAJIDDomains.WHATSAPP ? `${user}_${domainType}` : user
274
345
  const finalDevice = device || 0
275
346
 
347
+ if (device === 99 && decoded.server !== 'hosted' && decoded.server !== 'hosted.lid') {
348
+ throw new Error('Unexpected non-hosted device JID with device 99. This ID seems invalid. ID:' + jid)
349
+ }
350
+
276
351
  return new ProtocolAddress(signalUser, finalDevice)
277
352
  }
278
353
 
@@ -281,48 +356,55 @@ const jidToSignalSenderKeyName = (group, user) => {
281
356
  }
282
357
 
283
358
  function signalStorage({ creds, keys }, lidMapping) {
359
+ // Shared function to resolve PN signal address to LID if mapping exists
360
+ const resolveLIDSignalAddress = async (id) => {
361
+ if (id.includes('.')) {
362
+ const [deviceId, device] = id.split('.')
363
+ const [user, domainType_] = deviceId.split('_')
364
+ const domainType = parseInt(domainType_ || '0')
365
+
366
+ if (domainType === WAJIDDomains.LID || domainType === WAJIDDomains.HOSTED_LID) return id
367
+
368
+ const pnJid = `${user}${device !== '0' ? `:${device}` : ''}@${domainType === WAJIDDomains.HOSTED ? 'hosted' : 's.whatsapp.net'}`
369
+ const lidForPN = await lidMapping.getLIDForPN(pnJid)
370
+
371
+ if (lidForPN) {
372
+ const lidAddr = jidToSignalProtocolAddress(lidForPN)
373
+ return lidAddr.toString()
374
+ }
375
+ }
376
+
377
+ return id
378
+ }
379
+
284
380
  return {
285
381
  loadSession: async (id) => {
286
382
  try {
287
- // LID SINGLE SOURCE OF TRUTH: Auto-redirect PN to LID if mapping exists
288
- let actualId = id
289
- if (id.includes('.') && !id.includes('_1')) {
290
- // This is a PN signal address format (e.g., "1234567890.0")
291
- // Convert back to JID to check for LID mapping
292
- const parts = id.split('.')
293
- const device = parts[1] || '0'
294
- const pnJid = device === '0' ? `${parts[0]}@s.whatsapp.net` : `${parts[0]}:${device}@s.whatsapp.net`
295
- const lidForPN = await lidMapping.getLIDForPN(pnJid)
296
- if (lidForPN?.includes('@lid')) {
297
- const lidAddr = jidToSignalProtocolAddress(lidForPN)
298
- const lidId = lidAddr.toString()
299
- // Check if LID session exists
300
- const { [lidId]: lidSession } = await keys.get('session', [lidId])
301
- if (lidSession) {
302
- actualId = lidId
303
- }
304
- }
305
- }
306
- const { [actualId]: sess } = await keys.get('session', [actualId])
383
+ const wireJid = await resolveLIDSignalAddress(id)
384
+ const { [wireJid]: sess } = await keys.get('session', [wireJid])
385
+
307
386
  if (sess) {
308
387
  return SessionRecord.deserialize(sess)
309
388
  }
310
389
  }
390
+
311
391
  catch (e) {
312
392
  return null
313
393
  }
394
+
314
395
  return null
315
396
  },
316
- // TODO: Replace with SessionRecord when type exports are added to libsignal
317
397
  storeSession: async (id, session) => {
318
- await keys.set({ session: { [id]: session.serialize() } })
398
+ const wireJid = await resolveLIDSignalAddress(id)
399
+ await keys.set({ session: { [wireJid]: session.serialize() } })
319
400
  },
320
401
  isTrustedIdentity: () => {
321
- return true
402
+ return true // todo: implement
322
403
  },
323
404
  loadPreKey: async (id) => {
324
405
  const keyId = id.toString()
325
406
  const { [keyId]: key } = await keys.get('pre-key', [keyId])
407
+
326
408
  if (key) {
327
409
  return {
328
410
  privKey: Buffer.from(key.private),
@@ -341,9 +423,11 @@ function signalStorage({ creds, keys }, lidMapping) {
341
423
  loadSenderKey: async (senderKeyName) => {
342
424
  const keyId = senderKeyName.toString()
343
425
  const { [keyId]: key } = await keys.get('sender-key', [keyId])
426
+
344
427
  if (key) {
345
428
  return SenderKeyRecord.deserialize(key)
346
429
  }
430
+
347
431
  return new SenderKeyRecord()
348
432
  },
349
433
  storeSenderKey: async (senderKeyName, key) => {
@@ -356,7 +440,7 @@ function signalStorage({ creds, keys }, lidMapping) {
356
440
  const { signedIdentityKey } = creds
357
441
  return {
358
442
  privKey: Buffer.from(signedIdentityKey.private),
359
- pubKey: Buffer.from(generateSignalPubKey(signedIdentityKey.public))
443
+ pubKey: Buffer.from(generateSignalPubKey(signedIdentityKey.public))
360
444
  }
361
445
  }
362
446
  }