@periskope/baileys 6.7.18-17-2 → 6.7.18-17-4
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/lib/Signal/Group/group_cipher.js +3 -6
- package/lib/Signal/libsignal.d.ts +2 -2
- package/lib/Signal/libsignal.js +163 -19
- package/lib/Signal/lid-mapping.d.ts +17 -0
- package/lib/Signal/lid-mapping.js +89 -0
- package/lib/Socket/business.d.ts +4 -2
- package/lib/Socket/index.d.ts +4 -2
- package/lib/Socket/messages-recv.d.ts +4 -2
- package/lib/Socket/messages-recv.js +31 -1
- package/lib/Socket/messages-send.d.ts +4 -2
- package/lib/Socket/messages-send.js +438 -59
- package/lib/Socket/socket.js +17 -0
- package/lib/Types/Auth.d.ts +1 -0
- package/lib/Types/Signal.d.ts +20 -0
- package/lib/Utils/auth-utils.d.ts +1 -1
- package/lib/Utils/auth-utils.js +111 -83
- package/lib/Utils/decode-wa-message.d.ts +5 -0
- package/lib/Utils/decode-wa-message.js +51 -2
- package/package.json +2 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GroupCipher = void 0;
|
|
4
|
+
/* @ts-ignore */
|
|
4
5
|
const crypto_1 = require("libsignal/src/crypto");
|
|
5
6
|
const sender_key_message_1 = require("./sender-key-message");
|
|
6
7
|
class GroupCipher {
|
|
@@ -30,13 +31,9 @@ class GroupCipher {
|
|
|
30
31
|
throw new Error('No SenderKeyRecord found for decryption');
|
|
31
32
|
}
|
|
32
33
|
const senderKeyMessage = new sender_key_message_1.SenderKeyMessage(null, null, null, null, senderKeyMessageBytes);
|
|
33
|
-
|
|
34
|
-
// Fallback: try to get the latest sender key state if specific keyId not found
|
|
34
|
+
const senderKeyState = record.getSenderKeyState(senderKeyMessage.getKeyId());
|
|
35
35
|
if (!senderKeyState) {
|
|
36
|
-
|
|
37
|
-
if (!senderKeyState) {
|
|
38
|
-
throw new Error('No session found to decrypt message');
|
|
39
|
-
}
|
|
36
|
+
throw new Error('No session found to decrypt message');
|
|
40
37
|
}
|
|
41
38
|
senderKeyMessage.verifySignature(senderKeyState.getSigningKeyPublic());
|
|
42
39
|
const senderKey = this.getSenderKey(senderKeyState, senderKeyMessage.getIteration());
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { SignalAuthState } from '../Types';
|
|
2
|
-
import { SignalRepository } from '../Types/Signal';
|
|
1
|
+
import type { SignalAuthState } from '../Types';
|
|
2
|
+
import type { SignalRepository } from '../Types/Signal';
|
|
3
3
|
export declare function makeLibSignalRepository(auth: SignalAuthState): SignalRepository;
|
package/lib/Signal/libsignal.js
CHANGED
|
@@ -35,19 +35,29 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.makeLibSignalRepository = makeLibSignalRepository;
|
|
37
37
|
const libsignal = __importStar(require("libsignal"));
|
|
38
|
+
/* @ts-ignore */
|
|
39
|
+
const lru_cache_1 = require("lru-cache");
|
|
38
40
|
const Utils_1 = require("../Utils");
|
|
39
41
|
const WABinary_1 = require("../WABinary");
|
|
40
42
|
const sender_key_name_1 = require("./Group/sender-key-name");
|
|
41
43
|
const sender_key_record_1 = require("./Group/sender-key-record");
|
|
42
44
|
const Group_1 = require("./Group");
|
|
45
|
+
const lid_mapping_1 = require("./lid-mapping");
|
|
43
46
|
function makeLibSignalRepository(auth) {
|
|
44
|
-
const
|
|
45
|
-
|
|
47
|
+
const lidMapping = new lid_mapping_1.LIDMappingStore(auth.keys);
|
|
48
|
+
const storage = signalStorage(auth, lidMapping);
|
|
49
|
+
// Simple operation-level deduplication (5 minutes)
|
|
50
|
+
const recentMigrations = new lru_cache_1.LRUCache({
|
|
51
|
+
max: 500,
|
|
52
|
+
ttl: 5 * 60 * 1000
|
|
53
|
+
});
|
|
54
|
+
const parsedKeys = auth.keys;
|
|
55
|
+
const repository = {
|
|
46
56
|
decryptGroupMessage({ group, authorJid, msg }) {
|
|
47
57
|
const senderName = jidToSignalSenderKeyName(group, authorJid);
|
|
48
58
|
const cipher = new Group_1.GroupCipher(storage, senderName);
|
|
49
59
|
// Use transaction to ensure atomicity
|
|
50
|
-
return
|
|
60
|
+
return parsedKeys.transaction(async () => {
|
|
51
61
|
return cipher.decrypt(msg);
|
|
52
62
|
});
|
|
53
63
|
},
|
|
@@ -59,7 +69,11 @@ function makeLibSignalRepository(auth) {
|
|
|
59
69
|
const senderName = jidToSignalSenderKeyName(item.groupId, authorJid);
|
|
60
70
|
const senderMsg = new Group_1.SenderKeyDistributionMessage(null, null, null, null, item.axolotlSenderKeyDistributionMessage);
|
|
61
71
|
const senderNameStr = senderName.toString();
|
|
62
|
-
|
|
72
|
+
const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr]);
|
|
73
|
+
if (!senderKey) {
|
|
74
|
+
await storage.storeSenderKey(senderName, new sender_key_record_1.SenderKeyRecord());
|
|
75
|
+
}
|
|
76
|
+
return parsedKeys.transaction(async () => {
|
|
63
77
|
const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr]);
|
|
64
78
|
if (!senderKey) {
|
|
65
79
|
await storage.storeSenderKey(senderName, new sender_key_record_1.SenderKeyRecord());
|
|
@@ -70,8 +84,8 @@ function makeLibSignalRepository(auth) {
|
|
|
70
84
|
async decryptMessage({ jid, type, ciphertext }) {
|
|
71
85
|
const addr = jidToSignalProtocolAddress(jid);
|
|
72
86
|
const session = new libsignal.SessionCipher(storage, addr);
|
|
73
|
-
// Use transaction to ensure
|
|
74
|
-
return
|
|
87
|
+
// Use transaction to ensure atomicity
|
|
88
|
+
return parsedKeys.transaction(async () => {
|
|
75
89
|
let result;
|
|
76
90
|
switch (type) {
|
|
77
91
|
case 'pkmsg':
|
|
@@ -80,15 +94,41 @@ function makeLibSignalRepository(auth) {
|
|
|
80
94
|
case 'msg':
|
|
81
95
|
result = await session.decryptWhisperMessage(ciphertext);
|
|
82
96
|
break;
|
|
97
|
+
default:
|
|
98
|
+
throw new Error(`Unknown message type: ${type}`);
|
|
83
99
|
}
|
|
84
100
|
return result;
|
|
85
101
|
});
|
|
86
102
|
},
|
|
87
103
|
async encryptMessage({ jid, data }) {
|
|
88
|
-
|
|
104
|
+
// LID SINGLE SOURCE OF TRUTH: Always prefer LID when available
|
|
105
|
+
let encryptionJid = jid;
|
|
106
|
+
// Check for LID mapping and use it if session exists
|
|
107
|
+
if (jid.includes('@s.whatsapp.net')) {
|
|
108
|
+
const lidForPN = await lidMapping.getLIDForPN(jid);
|
|
109
|
+
if (lidForPN === null || lidForPN === void 0 ? void 0 : lidForPN.includes('@lid')) {
|
|
110
|
+
const lidAddr = jidToSignalProtocolAddress(lidForPN);
|
|
111
|
+
const { [lidAddr.toString()]: lidSession } = await auth.keys.get('session', [lidAddr.toString()]);
|
|
112
|
+
if (lidSession) {
|
|
113
|
+
// LID session exists, use it
|
|
114
|
+
encryptionJid = lidForPN;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// Try to migrate if PN session exists
|
|
118
|
+
const pnAddr = jidToSignalProtocolAddress(jid);
|
|
119
|
+
const { [pnAddr.toString()]: pnSession } = await auth.keys.get('session', [pnAddr.toString()]);
|
|
120
|
+
if (pnSession) {
|
|
121
|
+
// Migrate PN to LID
|
|
122
|
+
await repository.migrateSession(jid, lidForPN);
|
|
123
|
+
encryptionJid = lidForPN;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const addr = jidToSignalProtocolAddress(encryptionJid);
|
|
89
129
|
const cipher = new libsignal.SessionCipher(storage, addr);
|
|
90
|
-
// Use transaction to ensure
|
|
91
|
-
return
|
|
130
|
+
// Use transaction to ensure atomicity
|
|
131
|
+
return parsedKeys.transaction(async () => {
|
|
92
132
|
const { type: sigType, body } = await cipher.encrypt(data);
|
|
93
133
|
const type = sigType === 3 ? 'pkmsg' : 'msg';
|
|
94
134
|
return { type, ciphertext: Buffer.from(body, 'binary') };
|
|
@@ -98,8 +138,7 @@ function makeLibSignalRepository(auth) {
|
|
|
98
138
|
const senderName = jidToSignalSenderKeyName(group, meId);
|
|
99
139
|
const builder = new Group_1.GroupSessionBuilder(storage);
|
|
100
140
|
const senderNameStr = senderName.toString();
|
|
101
|
-
|
|
102
|
-
return auth.keys.transaction(async () => {
|
|
141
|
+
return parsedKeys.transaction(async () => {
|
|
103
142
|
const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr]);
|
|
104
143
|
if (!senderKey) {
|
|
105
144
|
await storage.storeSenderKey(senderName, new sender_key_record_1.SenderKeyRecord());
|
|
@@ -115,31 +154,136 @@ function makeLibSignalRepository(auth) {
|
|
|
115
154
|
},
|
|
116
155
|
async injectE2ESession({ jid, session }) {
|
|
117
156
|
const cipher = new libsignal.SessionBuilder(storage, jidToSignalProtocolAddress(jid));
|
|
118
|
-
|
|
119
|
-
return auth.keys.transaction(async () => {
|
|
157
|
+
return parsedKeys.transaction(async () => {
|
|
120
158
|
await cipher.initOutgoing(session);
|
|
121
159
|
});
|
|
122
160
|
},
|
|
123
161
|
jidToSignalProtocolAddress(jid) {
|
|
124
162
|
return jidToSignalProtocolAddress(jid).toString();
|
|
163
|
+
},
|
|
164
|
+
async storeLIDPNMapping(lid, pn) {
|
|
165
|
+
await lidMapping.storeLIDPNMapping(lid, pn);
|
|
166
|
+
},
|
|
167
|
+
getLIDMappingStore() {
|
|
168
|
+
return lidMapping;
|
|
169
|
+
},
|
|
170
|
+
async validateSession(jid) {
|
|
171
|
+
try {
|
|
172
|
+
const addr = jidToSignalProtocolAddress(jid);
|
|
173
|
+
const session = await storage.loadSession(addr.toString());
|
|
174
|
+
if (!session) {
|
|
175
|
+
return { exists: false, reason: 'no session' };
|
|
176
|
+
}
|
|
177
|
+
if (!session.haveOpenSession()) {
|
|
178
|
+
return { exists: false, reason: 'no open session' };
|
|
179
|
+
}
|
|
180
|
+
return { exists: true };
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
return { exists: false, reason: 'validation error' };
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
async deleteSession(jid) {
|
|
187
|
+
const addr = jidToSignalProtocolAddress(jid);
|
|
188
|
+
return auth.keys.transaction(async () => {
|
|
189
|
+
await auth.keys.set({ session: { [addr.toString()]: null } });
|
|
190
|
+
});
|
|
191
|
+
},
|
|
192
|
+
async migrateSession(fromJid, toJid) {
|
|
193
|
+
// Only migrate PN → LID
|
|
194
|
+
if (!fromJid.includes('@s.whatsapp.net') || !toJid.includes('@lid')) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const fromDecoded = (0, WABinary_1.jidDecode)(fromJid);
|
|
198
|
+
const toDecoded = (0, WABinary_1.jidDecode)(toJid);
|
|
199
|
+
if (!fromDecoded || !toDecoded)
|
|
200
|
+
return;
|
|
201
|
+
const deviceId = fromDecoded.device || 0;
|
|
202
|
+
const migrationKey = `${fromDecoded.user}.${deviceId}→${toDecoded.user}.${deviceId}`;
|
|
203
|
+
// Check if recently migrated (5 min window)
|
|
204
|
+
if (recentMigrations.has(migrationKey)) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
// Check if LID session already exists
|
|
208
|
+
const lidAddr = jidToSignalProtocolAddress(toJid);
|
|
209
|
+
const { [lidAddr.toString()]: lidExists } = await auth.keys.get('session', [lidAddr.toString()]);
|
|
210
|
+
if (lidExists) {
|
|
211
|
+
recentMigrations.set(migrationKey, true);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
return auth.keys.transaction(async () => {
|
|
215
|
+
// Store mapping
|
|
216
|
+
await lidMapping.storeLIDPNMapping(toJid, fromJid);
|
|
217
|
+
// Load and copy session
|
|
218
|
+
const fromAddr = jidToSignalProtocolAddress(fromJid);
|
|
219
|
+
const fromSession = await storage.loadSession(fromAddr.toString());
|
|
220
|
+
if (fromSession === null || fromSession === void 0 ? void 0 : fromSession.haveOpenSession()) {
|
|
221
|
+
// Deep copy session to prevent reference issues
|
|
222
|
+
const sessionBytes = fromSession.serialize();
|
|
223
|
+
const copiedSession = libsignal.SessionRecord.deserialize(sessionBytes);
|
|
224
|
+
// Store at LID address
|
|
225
|
+
await storage.storeSession(lidAddr.toString(), copiedSession);
|
|
226
|
+
// Delete PN session - maintain single encryption layer
|
|
227
|
+
await auth.keys.set({ session: { [fromAddr.toString()]: null } });
|
|
228
|
+
}
|
|
229
|
+
recentMigrations.set(migrationKey, true);
|
|
230
|
+
});
|
|
231
|
+
},
|
|
232
|
+
async encryptMessageWithWire({ encryptionJid, wireJid, data }) {
|
|
233
|
+
const result = await repository.encryptMessage({ jid: encryptionJid, data });
|
|
234
|
+
return { ...result, wireJid };
|
|
235
|
+
},
|
|
236
|
+
destroy() {
|
|
237
|
+
recentMigrations.clear();
|
|
125
238
|
}
|
|
126
239
|
};
|
|
240
|
+
return repository;
|
|
127
241
|
}
|
|
128
242
|
const jidToSignalProtocolAddress = (jid) => {
|
|
129
|
-
const
|
|
130
|
-
|
|
243
|
+
const decoded = (0, WABinary_1.jidDecode)(jid);
|
|
244
|
+
const { user, device, server } = decoded;
|
|
245
|
+
// LID addresses get _1 suffix for Signal protocol
|
|
246
|
+
const signalUser = server === 'lid' ? `${user}_1` : user;
|
|
247
|
+
const finalDevice = device || 0;
|
|
248
|
+
return new libsignal.ProtocolAddress(signalUser, finalDevice);
|
|
131
249
|
};
|
|
132
250
|
const jidToSignalSenderKeyName = (group, user) => {
|
|
133
251
|
return new sender_key_name_1.SenderKeyName(group, jidToSignalProtocolAddress(user));
|
|
134
252
|
};
|
|
135
|
-
function signalStorage({ creds, keys }) {
|
|
253
|
+
function signalStorage({ creds, keys }, lidMapping) {
|
|
136
254
|
return {
|
|
137
255
|
loadSession: async (id) => {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
256
|
+
try {
|
|
257
|
+
// LID SINGLE SOURCE OF TRUTH: Auto-redirect PN to LID if mapping exists
|
|
258
|
+
let actualId = id;
|
|
259
|
+
if (id.includes('.') && !id.includes('_1')) {
|
|
260
|
+
// This is a PN signal address format (e.g., "1234567890.0")
|
|
261
|
+
// Convert back to JID to check for LID mapping
|
|
262
|
+
const parts = id.split('.');
|
|
263
|
+
const device = parts[1] || '0';
|
|
264
|
+
const pnJid = device === '0' ? `${parts[0]}@s.whatsapp.net` : `${parts[0]}:${device}@s.whatsapp.net`;
|
|
265
|
+
const lidForPN = await lidMapping.getLIDForPN(pnJid);
|
|
266
|
+
if (lidForPN === null || lidForPN === void 0 ? void 0 : lidForPN.includes('@lid')) {
|
|
267
|
+
const lidAddr = jidToSignalProtocolAddress(lidForPN);
|
|
268
|
+
const lidId = lidAddr.toString();
|
|
269
|
+
// Check if LID session exists
|
|
270
|
+
const { [lidId]: lidSession } = await keys.get('session', [lidId]);
|
|
271
|
+
if (lidSession) {
|
|
272
|
+
actualId = lidId;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const { [actualId]: sess } = await keys.get('session', [actualId]);
|
|
277
|
+
if (sess) {
|
|
278
|
+
return libsignal.SessionRecord.deserialize(sess);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
catch (e) {
|
|
282
|
+
return null;
|
|
141
283
|
}
|
|
284
|
+
return null;
|
|
142
285
|
},
|
|
286
|
+
// TODO: Replace with libsignal.SessionRecord when type exports are added to libsignal
|
|
143
287
|
storeSession: async (id, session) => {
|
|
144
288
|
await keys.set({ session: { [id]: session.serialize() } });
|
|
145
289
|
},
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SignalKeyStoreWithTransaction } from '../Types';
|
|
2
|
+
export declare class LIDMappingStore {
|
|
3
|
+
private readonly keys;
|
|
4
|
+
constructor(keys: SignalKeyStoreWithTransaction);
|
|
5
|
+
/**
|
|
6
|
+
* Store LID-PN mapping - USER LEVEL
|
|
7
|
+
*/
|
|
8
|
+
storeLIDPNMapping(lid: string, pn: string): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Get LID for PN - Returns device-specific LID based on user mapping
|
|
11
|
+
*/
|
|
12
|
+
getLIDForPN(pn: string): Promise<string | null>;
|
|
13
|
+
/**
|
|
14
|
+
* Get PN for LID - USER LEVEL with device construction
|
|
15
|
+
*/
|
|
16
|
+
getPNForLID(lid: string): Promise<string | null>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LIDMappingStore = void 0;
|
|
7
|
+
const logger_1 = __importDefault(require("../Utils/logger"));
|
|
8
|
+
const WABinary_1 = require("../WABinary");
|
|
9
|
+
class LIDMappingStore {
|
|
10
|
+
constructor(keys) {
|
|
11
|
+
this.keys = keys;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Store LID-PN mapping - USER LEVEL
|
|
15
|
+
*/
|
|
16
|
+
async storeLIDPNMapping(lid, pn) {
|
|
17
|
+
// Validate inputs
|
|
18
|
+
if (!(((0, WABinary_1.isLidUser)(lid) && (0, WABinary_1.isJidUser)(pn)) || ((0, WABinary_1.isJidUser)(lid) && (0, WABinary_1.isLidUser)(pn)))) {
|
|
19
|
+
logger_1.default.warn(`Invalid LID-PN mapping: ${lid}, ${pn}`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const [lidJid, pnJid] = (0, WABinary_1.isLidUser)(lid) ? [lid, pn] : [pn, lid];
|
|
23
|
+
const lidDecoded = (0, WABinary_1.jidDecode)(lidJid);
|
|
24
|
+
const pnDecoded = (0, WABinary_1.jidDecode)(pnJid);
|
|
25
|
+
if (!lidDecoded || !pnDecoded)
|
|
26
|
+
return;
|
|
27
|
+
const pnUser = pnDecoded.user;
|
|
28
|
+
const lidUser = lidDecoded.user;
|
|
29
|
+
logger_1.default.trace(`Storing USER LID mapping: PN ${pnUser} → LID ${lidUser}`);
|
|
30
|
+
await this.keys.transaction(async () => {
|
|
31
|
+
await this.keys.set({
|
|
32
|
+
'lid-mapping': {
|
|
33
|
+
[pnUser]: lidUser, // "554396160286" -> "102765716062358"
|
|
34
|
+
[`${lidUser}_reverse`]: pnUser // "102765716062358_reverse" -> "554396160286"
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
logger_1.default.trace(`USER LID mapping stored: PN ${pnUser} → LID ${lidUser}`);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get LID for PN - Returns device-specific LID based on user mapping
|
|
42
|
+
*/
|
|
43
|
+
async getLIDForPN(pn) {
|
|
44
|
+
if (!(0, WABinary_1.isJidUser)(pn))
|
|
45
|
+
return null;
|
|
46
|
+
const decoded = (0, WABinary_1.jidDecode)(pn);
|
|
47
|
+
if (!decoded)
|
|
48
|
+
return null;
|
|
49
|
+
// Look up user-level mapping (whatsmeow approach)
|
|
50
|
+
const pnUser = decoded.user;
|
|
51
|
+
const stored = await this.keys.get('lid-mapping', [pnUser]);
|
|
52
|
+
const lidUser = stored[pnUser];
|
|
53
|
+
if (!lidUser) {
|
|
54
|
+
logger_1.default.trace(`No LID mapping found for PN user ${pnUser}`);
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
if (typeof lidUser !== 'string')
|
|
58
|
+
return null;
|
|
59
|
+
// Push the PN device ID to the LID to maintain device separation
|
|
60
|
+
const pnDevice = decoded.device !== undefined ? decoded.device : 0;
|
|
61
|
+
const deviceSpecificLid = `${lidUser}:${pnDevice}@lid`;
|
|
62
|
+
logger_1.default.trace(`getLIDForPN: ${pn} → ${deviceSpecificLid} (user mapping with device ${pnDevice})`);
|
|
63
|
+
return deviceSpecificLid;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get PN for LID - USER LEVEL with device construction
|
|
67
|
+
*/
|
|
68
|
+
async getPNForLID(lid) {
|
|
69
|
+
if (!(0, WABinary_1.isLidUser)(lid))
|
|
70
|
+
return null;
|
|
71
|
+
const decoded = (0, WABinary_1.jidDecode)(lid);
|
|
72
|
+
if (!decoded)
|
|
73
|
+
return null;
|
|
74
|
+
// Look up reverse user mapping
|
|
75
|
+
const lidUser = decoded.user;
|
|
76
|
+
const stored = await this.keys.get('lid-mapping', [`${lidUser}_reverse`]);
|
|
77
|
+
const pnUser = stored[`${lidUser}_reverse`];
|
|
78
|
+
if (!pnUser || typeof pnUser !== 'string') {
|
|
79
|
+
logger_1.default.trace(`No reverse mapping found for LID user: ${lidUser}`);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
// Construct device-specific PN JID
|
|
83
|
+
const lidDevice = decoded.device !== undefined ? decoded.device : 0;
|
|
84
|
+
const pnJid = `${pnUser}:${lidDevice}@s.whatsapp.net`;
|
|
85
|
+
logger_1.default.trace(`Found reverse mapping: ${lid} → ${pnJid}`);
|
|
86
|
+
return pnJid;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.LIDMappingStore = LIDMappingStore;
|
package/lib/Socket/business.d.ts
CHANGED
|
@@ -32,11 +32,13 @@ export declare const makeBusinessSocket: (config: SocketConfig) => {
|
|
|
32
32
|
[_: string]: string;
|
|
33
33
|
}>;
|
|
34
34
|
sendPeerDataOperationMessage: (pdoMessage: import("../Types").WAProto.Message.IPeerDataOperationRequestMessage) => Promise<string>;
|
|
35
|
-
createParticipantNodes: (jids: string[], message: import("../Types").WAProto.IMessage, extraAttrs?: BinaryNode["attrs"]) => Promise<{
|
|
35
|
+
createParticipantNodes: (jids: string[], message: import("../Types").WAProto.IMessage, extraAttrs?: BinaryNode["attrs"], dsmMessage?: import("../Types").WAProto.IMessage) => Promise<{
|
|
36
36
|
nodes: BinaryNode[];
|
|
37
37
|
shouldIncludeDeviceIdentity: boolean;
|
|
38
38
|
}>;
|
|
39
|
-
getUSyncDevices: (jids: string[], useCache: boolean, ignoreZeroDevices: boolean) => Promise<import("../WABinary").JidWithDevice
|
|
39
|
+
getUSyncDevices: (jids: string[], useCache: boolean, ignoreZeroDevices: boolean) => Promise<(import("../WABinary").JidWithDevice & {
|
|
40
|
+
wireJid: string;
|
|
41
|
+
})[]>;
|
|
40
42
|
updateMediaMessage: (message: import("../Types").WAProto.IWebMessageInfo) => Promise<import("../Types").WAProto.IWebMessageInfo>;
|
|
41
43
|
sendMessage: (jid: string, content: import("../Types").AnyMessageContent, options?: import("../Types").MiscMessageGenerationOptions) => Promise<import("../Types").WAProto.WebMessageInfo | undefined>;
|
|
42
44
|
newsletterCreate: (name: string, description?: string) => Promise<import("../Types").NewsletterMetadata>;
|
package/lib/Socket/index.d.ts
CHANGED
|
@@ -31,11 +31,13 @@ declare const makeWASocket: (config: UserFacingSocketConfig) => {
|
|
|
31
31
|
[_: string]: string;
|
|
32
32
|
}>;
|
|
33
33
|
sendPeerDataOperationMessage: (pdoMessage: import("../Types").WAProto.Message.IPeerDataOperationRequestMessage) => Promise<string>;
|
|
34
|
-
createParticipantNodes: (jids: string[], message: import("../Types").WAProto.IMessage, extraAttrs?: import("..").BinaryNode["attrs"]) => Promise<{
|
|
34
|
+
createParticipantNodes: (jids: string[], message: import("../Types").WAProto.IMessage, extraAttrs?: import("..").BinaryNode["attrs"], dsmMessage?: import("../Types").WAProto.IMessage) => Promise<{
|
|
35
35
|
nodes: import("..").BinaryNode[];
|
|
36
36
|
shouldIncludeDeviceIdentity: boolean;
|
|
37
37
|
}>;
|
|
38
|
-
getUSyncDevices: (jids: string[], useCache: boolean, ignoreZeroDevices: boolean) => Promise<import("..").JidWithDevice
|
|
38
|
+
getUSyncDevices: (jids: string[], useCache: boolean, ignoreZeroDevices: boolean) => Promise<(import("..").JidWithDevice & {
|
|
39
|
+
wireJid: string;
|
|
40
|
+
})[]>;
|
|
39
41
|
updateMediaMessage: (message: import("../Types").WAProto.IWebMessageInfo) => Promise<import("../Types").WAProto.IWebMessageInfo>;
|
|
40
42
|
sendMessage: (jid: string, content: import("../Types").AnyMessageContent, options?: import("../Types").MiscMessageGenerationOptions) => Promise<import("../Types").WAProto.WebMessageInfo | undefined>;
|
|
41
43
|
newsletterCreate: (name: string, description?: string) => Promise<import("../Types").NewsletterMetadata>;
|
|
@@ -21,11 +21,13 @@ export declare const makeMessagesRecvSocket: (config: SocketConfig) => {
|
|
|
21
21
|
[_: string]: string;
|
|
22
22
|
}>;
|
|
23
23
|
sendPeerDataOperationMessage: (pdoMessage: proto.Message.IPeerDataOperationRequestMessage) => Promise<string>;
|
|
24
|
-
createParticipantNodes: (jids: string[], message: proto.IMessage, extraAttrs?: BinaryNode["attrs"]) => Promise<{
|
|
24
|
+
createParticipantNodes: (jids: string[], message: proto.IMessage, extraAttrs?: BinaryNode["attrs"], dsmMessage?: proto.IMessage) => Promise<{
|
|
25
25
|
nodes: BinaryNode[];
|
|
26
26
|
shouldIncludeDeviceIdentity: boolean;
|
|
27
27
|
}>;
|
|
28
|
-
getUSyncDevices: (jids: string[], useCache: boolean, ignoreZeroDevices: boolean) => Promise<import("../WABinary").JidWithDevice
|
|
28
|
+
getUSyncDevices: (jids: string[], useCache: boolean, ignoreZeroDevices: boolean) => Promise<(import("../WABinary").JidWithDevice & {
|
|
29
|
+
wireJid: string;
|
|
30
|
+
})[]>;
|
|
29
31
|
updateMediaMessage: (message: proto.IWebMessageInfo) => Promise<proto.IWebMessageInfo>;
|
|
30
32
|
sendMessage: (jid: string, content: import("../Types").AnyMessageContent, options?: import("../Types").MiscMessageGenerationOptions) => Promise<proto.WebMessageInfo | undefined>;
|
|
31
33
|
newsletterCreate: (name: string, description?: string) => Promise<import("../Types").NewsletterMetadata>;
|
|
@@ -661,7 +661,7 @@ const makeMessagesRecvSocket = (config) => {
|
|
|
661
661
|
}
|
|
662
662
|
};
|
|
663
663
|
const handleMessage = async (node) => {
|
|
664
|
-
var _a, _b, _c;
|
|
664
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
665
665
|
if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !== '@s.whatsapp.net') {
|
|
666
666
|
logger.debug({ key: node.attrs.key }, 'ignored message');
|
|
667
667
|
await sendMessageAck(node);
|
|
@@ -697,6 +697,36 @@ const makeMessagesRecvSocket = (config) => {
|
|
|
697
697
|
node.attrs.sender_pn) {
|
|
698
698
|
ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
|
|
699
699
|
}
|
|
700
|
+
if ((_f = (_e = (_d = msg.message) === null || _d === void 0 ? void 0 : _d.protocolMessage) === null || _e === void 0 ? void 0 : _e.lidMigrationMappingSyncMessage) === null || _f === void 0 ? void 0 : _f.encodedMappingPayload) {
|
|
701
|
+
try {
|
|
702
|
+
const payload = msg.message.protocolMessage.lidMigrationMappingSyncMessage.encodedMappingPayload;
|
|
703
|
+
const decoded = WAProto_1.proto.LIDMigrationMappingSyncPayload.decode(payload);
|
|
704
|
+
logger.debug({
|
|
705
|
+
mappingCount: ((_g = decoded.pnToLidMappings) === null || _g === void 0 ? void 0 : _g.length) || 0,
|
|
706
|
+
timestamp: decoded.chatDbMigrationTimestamp
|
|
707
|
+
}, 'Received LID migration sync message from server');
|
|
708
|
+
const lidMapping = signalRepository.getLIDMappingStore();
|
|
709
|
+
if (decoded.pnToLidMappings && decoded.pnToLidMappings.length > 0) {
|
|
710
|
+
for (const mapping of decoded.pnToLidMappings) {
|
|
711
|
+
const pn = `${mapping.pn}@s.whatsapp.net`;
|
|
712
|
+
// Use latestLid if available, otherwise assignedLid (proper LID refresh)
|
|
713
|
+
const lidValue = mapping.latestLid || mapping.assignedLid;
|
|
714
|
+
const lid = `${lidValue}@lid`;
|
|
715
|
+
await lidMapping.storeLIDPNMapping(lid, pn);
|
|
716
|
+
logger.debug({
|
|
717
|
+
pn,
|
|
718
|
+
lid,
|
|
719
|
+
assignedLid: mapping.assignedLid,
|
|
720
|
+
latestLid: mapping.latestLid,
|
|
721
|
+
usedLatest: !!mapping.latestLid
|
|
722
|
+
}, 'Stored server-provided PN-LID mapping');
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
catch (error) {
|
|
727
|
+
logger.error({ error }, 'Failed to process LID migration sync message');
|
|
728
|
+
}
|
|
729
|
+
}
|
|
700
730
|
try {
|
|
701
731
|
await Promise.all([
|
|
702
732
|
processingMutex.mutex(async () => {
|
|
@@ -16,11 +16,13 @@ export declare const makeMessagesSocket: (config: SocketConfig) => {
|
|
|
16
16
|
[_: string]: string;
|
|
17
17
|
}>;
|
|
18
18
|
sendPeerDataOperationMessage: (pdoMessage: proto.Message.IPeerDataOperationRequestMessage) => Promise<string>;
|
|
19
|
-
createParticipantNodes: (jids: string[], message: proto.IMessage, extraAttrs?: BinaryNode["attrs"]) => Promise<{
|
|
19
|
+
createParticipantNodes: (jids: string[], message: proto.IMessage, extraAttrs?: BinaryNode["attrs"], dsmMessage?: proto.IMessage) => Promise<{
|
|
20
20
|
nodes: BinaryNode[];
|
|
21
21
|
shouldIncludeDeviceIdentity: boolean;
|
|
22
22
|
}>;
|
|
23
|
-
getUSyncDevices: (jids: string[], useCache: boolean, ignoreZeroDevices: boolean) => Promise<JidWithDevice
|
|
23
|
+
getUSyncDevices: (jids: string[], useCache: boolean, ignoreZeroDevices: boolean) => Promise<(JidWithDevice & {
|
|
24
|
+
wireJid: string;
|
|
25
|
+
})[]>;
|
|
24
26
|
updateMediaMessage: (message: proto.IWebMessageInfo) => Promise<proto.IWebMessageInfo>;
|
|
25
27
|
sendMessage: (jid: string, content: AnyMessageContent, options?: MiscMessageGenerationOptions) => Promise<proto.WebMessageInfo | undefined>;
|
|
26
28
|
newsletterCreate: (name: string, description?: string) => Promise<import("../Types").NewsletterMetadata>;
|