@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/Signal/libsignal.js
CHANGED
|
@@ -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,
|
|
26
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
190
|
-
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
231
|
-
const opsToMigrate = migrationOps.filter(op => !existingSessions[op.toAddr.toString()])
|
|
232
|
-
const skippedCount = migrationOps.length - opsToMigrate.length
|
|
284
|
+
let migratedCount = 0
|
|
233
285
|
|
|
234
|
-
|
|
235
|
-
|
|
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
|
-
//
|
|
239
|
-
|
|
240
|
-
|
|
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 (
|
|
243
|
-
//
|
|
244
|
-
const
|
|
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
|
-
|
|
249
|
-
|
|
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
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
-
|
|
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
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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
|
-
|
|
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
|
}
|