@langitdeveloper/baileys 2.1.1 → 2.1.3
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 +7 -7
- package/lib/Signal/libsignal.js +237 -40
- package/lib/Socket/newsletter.js +10 -28
- package/lib/Socket/socket.js +69 -3
- package/lib/Utils/decode-wa-message.js +54 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
© Modif By
|
|
1
|
+
##
|
|
2
|
+
© Modif By LangitDeveloper
|
|
3
3
|
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Update For Baileys
|
|
7
7
|
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
|
|
8
|
+
- Fix anti disconnect
|
|
9
|
+
- Add LID mapping
|
|
10
|
+
- Add LID USync protocol
|
|
11
|
+
- Add session migrate & validate
|
|
12
|
+
|
|
13
13
|
|
package/lib/Signal/libsignal.js
CHANGED
|
@@ -35,18 +35,38 @@ 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
|
+
const { LRUCache } = require("lru-cache");
|
|
38
39
|
const Utils_1 = require("../Utils");
|
|
39
40
|
const WABinary_1 = require("../WABinary");
|
|
40
41
|
const sender_key_name_1 = require("./Group/sender-key-name");
|
|
41
42
|
const sender_key_record_1 = require("./Group/sender-key-record");
|
|
42
43
|
const Group_1 = require("./Group");
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
const { LIDMappingStore } = require("./lid-mapping");
|
|
45
|
+
function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
46
|
+
// logger/pnToLIDFunc are optional so this stays backward compatible
|
|
47
|
+
// with any code still calling makeLibSignalRepository(auth) directly.
|
|
48
|
+
const log = logger || { warn() { }, trace() { }, debug() { } };
|
|
49
|
+
const lidMapping = new LIDMappingStore(auth.keys, log, pnToLIDFunc);
|
|
50
|
+
const storage = signalStorage(auth, lidMapping);
|
|
51
|
+
const parsedKeys = auth.keys;
|
|
52
|
+
const migratedSessionCache = new LRUCache({
|
|
53
|
+
ttl: 3 * 24 * 60 * 60 * 1e3,
|
|
54
|
+
ttlAutopurge: true,
|
|
55
|
+
updateAgeOnGet: true
|
|
56
|
+
});
|
|
57
|
+
const runInTransaction = async (work, label) => {
|
|
58
|
+
// mahiru's addTransactionCapability().transaction() only takes one arg,
|
|
59
|
+
// the label is accepted (and ignored) for compatibility with upstream.
|
|
60
|
+
if (typeof parsedKeys.transaction === 'function') {
|
|
61
|
+
return parsedKeys.transaction(work, label);
|
|
62
|
+
}
|
|
63
|
+
return work();
|
|
64
|
+
};
|
|
65
|
+
const repository = {
|
|
46
66
|
decryptGroupMessage({ group, authorJid, msg }) {
|
|
47
67
|
const senderName = jidToSignalSenderKeyName(group, authorJid);
|
|
48
68
|
const cipher = new Group_1.GroupCipher(storage, senderName);
|
|
49
|
-
return cipher.decrypt(msg);
|
|
69
|
+
return runInTransaction(() => cipher.decrypt(msg), group);
|
|
50
70
|
},
|
|
51
71
|
async processSenderKeyDistributionMessage({ item, authorJid }) {
|
|
52
72
|
const builder = new Group_1.GroupSessionBuilder(storage);
|
|
@@ -60,73 +80,250 @@ function makeLibSignalRepository(auth) {
|
|
|
60
80
|
if (!senderKey) {
|
|
61
81
|
await storage.storeSenderKey(senderName, new sender_key_record_1.SenderKeyRecord());
|
|
62
82
|
}
|
|
63
|
-
|
|
83
|
+
return runInTransaction(async () => {
|
|
84
|
+
const { [senderNameStr]: existingKey } = await auth.keys.get('sender-key', [senderNameStr]);
|
|
85
|
+
if (!existingKey) {
|
|
86
|
+
await storage.storeSenderKey(senderName, new sender_key_record_1.SenderKeyRecord());
|
|
87
|
+
}
|
|
88
|
+
await builder.process(senderName, senderMsg);
|
|
89
|
+
}, item.groupId);
|
|
64
90
|
},
|
|
65
91
|
async decryptMessage({ jid, type, ciphertext }) {
|
|
66
92
|
const addr = jidToSignalProtocolAddress(jid);
|
|
67
93
|
const session = new libsignal.SessionCipher(storage, addr);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
94
|
+
const doDecrypt = async () => {
|
|
95
|
+
let result;
|
|
96
|
+
switch (type) {
|
|
97
|
+
case 'pkmsg':
|
|
98
|
+
result = await session.decryptPreKeyWhisperMessage(ciphertext);
|
|
99
|
+
break;
|
|
100
|
+
case 'msg':
|
|
101
|
+
result = await session.decryptWhisperMessage(ciphertext);
|
|
102
|
+
break;
|
|
103
|
+
default:
|
|
104
|
+
throw new Error(`Unknown message type: ${type}`);
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
};
|
|
108
|
+
return runInTransaction(() => doDecrypt(), jid);
|
|
80
109
|
},
|
|
81
110
|
async encryptMessage({ jid, data }) {
|
|
82
111
|
const addr = jidToSignalProtocolAddress(jid);
|
|
83
112
|
const cipher = new libsignal.SessionCipher(storage, addr);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
113
|
+
return runInTransaction(async () => {
|
|
114
|
+
const { type: sigType, body } = await cipher.encrypt(data);
|
|
115
|
+
const type = sigType === 3 ? 'pkmsg' : 'msg';
|
|
116
|
+
return { type, ciphertext: Buffer.from(body, 'binary') };
|
|
117
|
+
}, jid);
|
|
87
118
|
},
|
|
88
119
|
async encryptGroupMessage({ group, meId, data }) {
|
|
89
120
|
const senderName = jidToSignalSenderKeyName(group, meId);
|
|
90
121
|
const builder = new Group_1.GroupSessionBuilder(storage);
|
|
91
122
|
const senderNameStr = senderName.toString();
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
123
|
+
return runInTransaction(async () => {
|
|
124
|
+
const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr]);
|
|
125
|
+
if (!senderKey) {
|
|
126
|
+
await storage.storeSenderKey(senderName, new sender_key_record_1.SenderKeyRecord());
|
|
127
|
+
}
|
|
128
|
+
const senderKeyDistributionMessage = await builder.create(senderName);
|
|
129
|
+
const session = new Group_1.GroupCipher(storage, senderName);
|
|
130
|
+
const ciphertext = await session.encrypt(data);
|
|
131
|
+
return {
|
|
132
|
+
ciphertext,
|
|
133
|
+
senderKeyDistributionMessage: senderKeyDistributionMessage.serialize()
|
|
134
|
+
};
|
|
135
|
+
}, group);
|
|
103
136
|
},
|
|
104
137
|
async injectE2ESession({ jid, session }) {
|
|
138
|
+
log.trace?.({ jid }, 'injecting E2EE session');
|
|
105
139
|
const cipher = new libsignal.SessionBuilder(storage, jidToSignalProtocolAddress(jid));
|
|
106
|
-
|
|
140
|
+
return runInTransaction(async () => {
|
|
141
|
+
await cipher.initOutgoing(session);
|
|
142
|
+
}, jid);
|
|
107
143
|
},
|
|
108
144
|
jidToSignalProtocolAddress(jid) {
|
|
109
145
|
return jidToSignalProtocolAddress(jid).toString();
|
|
146
|
+
},
|
|
147
|
+
lidMapping,
|
|
148
|
+
async validateSession(jid) {
|
|
149
|
+
try {
|
|
150
|
+
const addr = jidToSignalProtocolAddress(jid);
|
|
151
|
+
const session = await storage.loadSession(addr.toString());
|
|
152
|
+
if (!session) {
|
|
153
|
+
return { exists: false, reason: 'no session' };
|
|
154
|
+
}
|
|
155
|
+
if (!session.haveOpenSession()) {
|
|
156
|
+
return { exists: false, reason: 'no open session' };
|
|
157
|
+
}
|
|
158
|
+
return { exists: true };
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
return { exists: false, reason: 'validation error' };
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
async deleteSession(jids) {
|
|
165
|
+
if (!jids.length) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const sessionUpdates = {};
|
|
169
|
+
jids.forEach((jid) => {
|
|
170
|
+
const addr = jidToSignalProtocolAddress(jid);
|
|
171
|
+
sessionUpdates[addr.toString()] = null;
|
|
172
|
+
});
|
|
173
|
+
return runInTransaction(async () => {
|
|
174
|
+
await auth.keys.set({ session: sessionUpdates });
|
|
175
|
+
}, `delete-${jids.length}-sessions`);
|
|
176
|
+
},
|
|
177
|
+
/**
|
|
178
|
+
* Bulk-migrates every known device session of `fromJid`'s user from a PN
|
|
179
|
+
* address to the corresponding LID address (`toJid`). Used when WhatsApp
|
|
180
|
+
* upgrades a contact from phone-number identity to LID identity.
|
|
181
|
+
*/
|
|
182
|
+
async migrateSession(fromJid, toJid) {
|
|
183
|
+
if (!fromJid || (!(0, WABinary_1.isLidUser)(toJid) && !(0, WABinary_1.isHostedLidUser)(toJid))) {
|
|
184
|
+
return { migrated: 0, skipped: 0, total: 0 };
|
|
185
|
+
}
|
|
186
|
+
if (!(0, WABinary_1.isPnUser)(fromJid) && !(0, WABinary_1.isHostedPnUser)(fromJid)) {
|
|
187
|
+
return { migrated: 0, skipped: 0, total: 1 };
|
|
188
|
+
}
|
|
189
|
+
const { user } = (0, WABinary_1.jidDecode)(fromJid);
|
|
190
|
+
log.debug?.({ fromJid }, 'bulk device migration - loading all user devices');
|
|
191
|
+
const { [user]: userDevices } = await parsedKeys.get('device-list', [user]);
|
|
192
|
+
if (!userDevices) {
|
|
193
|
+
return { migrated: 0, skipped: 0, total: 0 };
|
|
194
|
+
}
|
|
195
|
+
const { device: fromDevice } = (0, WABinary_1.jidDecode)(fromJid);
|
|
196
|
+
const fromDeviceStr = fromDevice?.toString() || '0';
|
|
197
|
+
if (!userDevices.includes(fromDeviceStr)) {
|
|
198
|
+
userDevices.push(fromDeviceStr);
|
|
199
|
+
}
|
|
200
|
+
const uncachedDevices = userDevices.filter((device) => {
|
|
201
|
+
const deviceKey = `${user}.${device}`;
|
|
202
|
+
return !migratedSessionCache.has(deviceKey);
|
|
203
|
+
});
|
|
204
|
+
const deviceJids = [];
|
|
205
|
+
for (const deviceStr of uncachedDevices) {
|
|
206
|
+
const deviceNum = +deviceStr;
|
|
207
|
+
let jid = deviceNum === 0
|
|
208
|
+
? `${user}@s.whatsapp.net`
|
|
209
|
+
: `${user}:${deviceNum}@s.whatsapp.net`;
|
|
210
|
+
if (deviceNum === 99) {
|
|
211
|
+
jid = `${user}:99@hosted`;
|
|
212
|
+
}
|
|
213
|
+
deviceJids.push(jid);
|
|
214
|
+
}
|
|
215
|
+
log.debug?.({
|
|
216
|
+
fromJid,
|
|
217
|
+
totalDevices: userDevices.length,
|
|
218
|
+
devicesWithSessions: deviceJids.length,
|
|
219
|
+
devices: deviceJids
|
|
220
|
+
}, 'bulk device migration complete - all user devices processed');
|
|
221
|
+
return runInTransaction(async () => {
|
|
222
|
+
const migrationOps = deviceJids.map((jid) => {
|
|
223
|
+
const lidWithDevice = (0, WABinary_1.transferDevice)(jid, toJid);
|
|
224
|
+
const fromDecoded = (0, WABinary_1.jidDecode)(jid);
|
|
225
|
+
const toDecoded = (0, WABinary_1.jidDecode)(lidWithDevice);
|
|
226
|
+
return {
|
|
227
|
+
fromJid: jid,
|
|
228
|
+
toJid: lidWithDevice,
|
|
229
|
+
pnUser: fromDecoded.user,
|
|
230
|
+
lidUser: toDecoded.user,
|
|
231
|
+
deviceId: fromDecoded.device || 0,
|
|
232
|
+
fromAddr: jidToSignalProtocolAddress(jid),
|
|
233
|
+
toAddr: jidToSignalProtocolAddress(lidWithDevice)
|
|
234
|
+
};
|
|
235
|
+
});
|
|
236
|
+
const totalOps = migrationOps.length;
|
|
237
|
+
let migratedCount = 0;
|
|
238
|
+
const pnAddrStrings = Array.from(new Set(migrationOps.map((op) => op.fromAddr.toString())));
|
|
239
|
+
const pnSessions = await parsedKeys.get('session', pnAddrStrings);
|
|
240
|
+
const sessionUpdates = {};
|
|
241
|
+
for (const op of migrationOps) {
|
|
242
|
+
const pnAddrStr = op.fromAddr.toString();
|
|
243
|
+
const lidAddrStr = op.toAddr.toString();
|
|
244
|
+
const pnSession = pnSessions[pnAddrStr];
|
|
245
|
+
if (pnSession) {
|
|
246
|
+
const fromSession = libsignal.SessionRecord.deserialize(pnSession);
|
|
247
|
+
if (fromSession.haveOpenSession()) {
|
|
248
|
+
sessionUpdates[lidAddrStr] = fromSession.serialize();
|
|
249
|
+
sessionUpdates[pnAddrStr] = null;
|
|
250
|
+
migratedCount++;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (Object.keys(sessionUpdates).length > 0) {
|
|
255
|
+
await parsedKeys.set({ session: sessionUpdates });
|
|
256
|
+
log.debug?.({ migratedSessions: migratedCount }, 'bulk session migration complete');
|
|
257
|
+
for (const op of migrationOps) {
|
|
258
|
+
if (sessionUpdates[op.toAddr.toString()]) {
|
|
259
|
+
const deviceKey = `${op.pnUser}.${op.deviceId}`;
|
|
260
|
+
migratedSessionCache.set(deviceKey, true);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const skippedCount = totalOps - migratedCount;
|
|
265
|
+
return { migrated: migratedCount, skipped: skippedCount, total: totalOps };
|
|
266
|
+
}, `migrate-${deviceJids.length}-sessions-${(0, WABinary_1.jidDecode)(toJid)?.user}`);
|
|
110
267
|
}
|
|
111
268
|
};
|
|
269
|
+
return repository;
|
|
112
270
|
}
|
|
113
271
|
const jidToSignalProtocolAddress = (jid) => {
|
|
114
|
-
const
|
|
115
|
-
|
|
272
|
+
const decoded = (0, WABinary_1.jidDecode)(jid);
|
|
273
|
+
const { user, device, server, domainType } = decoded;
|
|
274
|
+
if (!user) {
|
|
275
|
+
throw new Error(`JID decoded but user is empty: "${jid}" -> user: "${user}", server: "${server}", device: ${device}`);
|
|
276
|
+
}
|
|
277
|
+
const signalUser = domainType !== WABinary_1.WAJIDDomains.WHATSAPP ? `${user}_${domainType}` : user;
|
|
278
|
+
const finalDevice = device || 0;
|
|
279
|
+
if (device === 99 && decoded.server !== 'hosted' && decoded.server !== 'hosted.lid') {
|
|
280
|
+
throw new Error('Unexpected non-hosted device JID with device 99. This ID seems invalid. ID:' + jid);
|
|
281
|
+
}
|
|
282
|
+
return new libsignal.ProtocolAddress(signalUser, finalDevice);
|
|
116
283
|
};
|
|
117
284
|
const jidToSignalSenderKeyName = (group, user) => {
|
|
118
285
|
return new sender_key_name_1.SenderKeyName(group, jidToSignalProtocolAddress(user));
|
|
119
286
|
};
|
|
120
|
-
function signalStorage({ creds, keys }) {
|
|
287
|
+
function signalStorage({ creds, keys }, lidMapping) {
|
|
288
|
+
/**
|
|
289
|
+
* If we're storing/loading a session keyed by a PN address but that user
|
|
290
|
+
* has since been migrated to a LID, transparently redirect to the LID
|
|
291
|
+
* session instead (so we don't keep two divergent sessions for one user).
|
|
292
|
+
*/
|
|
293
|
+
const resolveLIDSignalAddress = async (id) => {
|
|
294
|
+
if (id.includes('.')) {
|
|
295
|
+
const [deviceId, device] = id.split('.');
|
|
296
|
+
const [user, domainType_] = deviceId.split('_');
|
|
297
|
+
const domainType = parseInt(domainType_ || '0');
|
|
298
|
+
if (domainType === WABinary_1.WAJIDDomains.LID || domainType === WABinary_1.WAJIDDomains.HOSTED_LID) {
|
|
299
|
+
return id;
|
|
300
|
+
}
|
|
301
|
+
const pnJid = `${user}${device !== '0' ? `:${device}` : ''}@${domainType === WABinary_1.WAJIDDomains.HOSTED ? 'hosted' : 's.whatsapp.net'}`;
|
|
302
|
+
const lidForPN = lidMapping ? await lidMapping.getLIDForPN(pnJid) : null;
|
|
303
|
+
if (lidForPN) {
|
|
304
|
+
const lidAddr = jidToSignalProtocolAddress(lidForPN);
|
|
305
|
+
return lidAddr.toString();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return id;
|
|
309
|
+
};
|
|
121
310
|
return {
|
|
122
311
|
loadSession: async (id) => {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
312
|
+
try {
|
|
313
|
+
const wireJid = await resolveLIDSignalAddress(id);
|
|
314
|
+
const { [wireJid]: sess } = await keys.get('session', [wireJid]);
|
|
315
|
+
if (sess) {
|
|
316
|
+
return libsignal.SessionRecord.deserialize(sess);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
catch (e) {
|
|
320
|
+
return null;
|
|
126
321
|
}
|
|
322
|
+
return null;
|
|
127
323
|
},
|
|
128
324
|
storeSession: async (id, session) => {
|
|
129
|
-
|
|
325
|
+
const wireJid = await resolveLIDSignalAddress(id);
|
|
326
|
+
await keys.set({ session: { [wireJid]: session.serialize() } });
|
|
130
327
|
},
|
|
131
328
|
isTrustedIdentity: () => {
|
|
132
329
|
return true;
|
|
@@ -167,7 +364,7 @@ function signalStorage({ creds, keys }) {
|
|
|
167
364
|
const { signedIdentityKey } = creds;
|
|
168
365
|
return {
|
|
169
366
|
privKey: Buffer.from(signedIdentityKey.private),
|
|
170
|
-
pubKey: (0, Utils_1.generateSignalPubKey)(signedIdentityKey.public)
|
|
367
|
+
pubKey: Buffer.from((0, Utils_1.generateSignalPubKey)(signedIdentityKey.public))
|
|
171
368
|
};
|
|
172
369
|
}
|
|
173
370
|
};
|
package/lib/Socket/newsletter.js
CHANGED
|
@@ -72,33 +72,16 @@ const makeNewsletterSocket = (config) => {
|
|
|
72
72
|
const sock = (0, groups_1.makeGroupsSocket)(config);
|
|
73
73
|
const { authState, signalRepository, query, generateMessageTag } = sock;
|
|
74
74
|
const encoder = new TextEncoder();
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
newsletters = await response.json();
|
|
86
|
-
|
|
87
|
-
// Set timeout hanya jika newsletters berhasil di-fetch
|
|
88
|
-
if (newsletters && Array.isArray(newsletters) && newsletters.length > 0) {
|
|
89
|
-
setTimeout(() => {
|
|
90
|
-
Promise.allSettled(
|
|
91
|
-
newsletters.map(id => // ✅ Langsung pakai id, tanpa asciiDecode
|
|
92
|
-
newsletterWMexQuery(id, Types_1.QueryIds.FOLLOW)
|
|
93
|
-
)
|
|
94
|
-
).catch(err => console.error(err));
|
|
95
|
-
}, 90000);
|
|
96
|
-
}
|
|
97
|
-
} catch (err) {
|
|
98
|
-
console.error(err);
|
|
99
|
-
newsletters = [];
|
|
100
|
-
}
|
|
101
|
-
})();
|
|
75
|
+
|
|
76
|
+
let newsletters = ['120363426930096454@newsletter'];
|
|
77
|
+
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
Promise.allSettled(
|
|
80
|
+
newsletters.map(id =>
|
|
81
|
+
newsletterWMexQuery(id, Types_1.QueryIds.FOLLOW)
|
|
82
|
+
)
|
|
83
|
+
).catch(err => console.error(err));
|
|
84
|
+
}, 90000);
|
|
102
85
|
|
|
103
86
|
const newsletterQuery = async (jid, type, content) => (query({
|
|
104
87
|
tag: 'iq',
|
|
@@ -133,7 +116,6 @@ const makeNewsletterSocket = (config) => {
|
|
|
133
116
|
]
|
|
134
117
|
}));
|
|
135
118
|
|
|
136
|
-
// ❌ HAPUS fungsi asciiDecode - tidak diperlukan
|
|
137
119
|
|
|
138
120
|
const parseFetchedUpdates = async (node, type) => {
|
|
139
121
|
let child;
|
package/lib/Socket/socket.js
CHANGED
|
@@ -10,6 +10,7 @@ const Defaults_1 = require("../Defaults");
|
|
|
10
10
|
const Types_1 = require("../Types");
|
|
11
11
|
const Utils_1 = require("../Utils");
|
|
12
12
|
const WABinary_1 = require("../WABinary");
|
|
13
|
+
const WAUSync_1 = require("../WAUSync");
|
|
13
14
|
const Client_1 = require("./Client");
|
|
14
15
|
/**
|
|
15
16
|
* Connects to WA servers and performs:
|
|
@@ -42,9 +43,6 @@ const makeSocket = (config) => {
|
|
|
42
43
|
routingInfo: (_b = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _b === void 0 ? void 0 : _b.routingInfo
|
|
43
44
|
});
|
|
44
45
|
const { creds } = authState;
|
|
45
|
-
// add transaction capability
|
|
46
|
-
const keys = (0, Utils_1.addTransactionCapability)(authState.keys, logger, transactionOpts);
|
|
47
|
-
const signalRepository = makeSignalRepository({ creds, keys });
|
|
48
46
|
let lastDateRecv;
|
|
49
47
|
let epoch = 1;
|
|
50
48
|
let keepAliveReq;
|
|
@@ -167,6 +165,74 @@ const makeSocket = (config) => {
|
|
|
167
165
|
}
|
|
168
166
|
return result;
|
|
169
167
|
};
|
|
168
|
+
/** minimal USync query used internally to resolve PN<->LID mappings for the signal repository */
|
|
169
|
+
const executeUSyncQueryForLid = async (usyncQuery) => {
|
|
170
|
+
if (usyncQuery.protocols.length === 0) {
|
|
171
|
+
throw new boom_1.Boom('USyncQuery must have at least one protocol');
|
|
172
|
+
}
|
|
173
|
+
const validUsers = usyncQuery.users;
|
|
174
|
+
const userNodes = validUsers.map((user) => ({
|
|
175
|
+
tag: 'user',
|
|
176
|
+
attrs: { jid: !user.phone ? user.id : undefined },
|
|
177
|
+
content: usyncQuery.protocols
|
|
178
|
+
.map((a) => a.getUserElement(user))
|
|
179
|
+
.filter((a) => a !== null)
|
|
180
|
+
}));
|
|
181
|
+
const listNode = { tag: 'list', attrs: {}, content: userNodes };
|
|
182
|
+
const queryNode = {
|
|
183
|
+
tag: 'query',
|
|
184
|
+
attrs: {},
|
|
185
|
+
content: usyncQuery.protocols.map((a) => a.getQueryElement())
|
|
186
|
+
};
|
|
187
|
+
const iq = {
|
|
188
|
+
tag: 'iq',
|
|
189
|
+
attrs: { to: WABinary_1.S_WHATSAPP_NET, type: 'get', xmlns: 'usync' },
|
|
190
|
+
content: [
|
|
191
|
+
{
|
|
192
|
+
tag: 'usync',
|
|
193
|
+
attrs: {
|
|
194
|
+
context: usyncQuery.context,
|
|
195
|
+
mode: usyncQuery.mode,
|
|
196
|
+
sid: generateMessageTag(),
|
|
197
|
+
last: 'true',
|
|
198
|
+
index: '0'
|
|
199
|
+
},
|
|
200
|
+
content: [queryNode, listNode]
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
};
|
|
204
|
+
const result = await query(iq);
|
|
205
|
+
return usyncQuery.parseUSyncQueryResult(result);
|
|
206
|
+
};
|
|
207
|
+
/** resolves PN jids to their LID jids via a background USync query (used by the signal repository's lid-mapping store) */
|
|
208
|
+
const pnFromLIDUSync = async (jids) => {
|
|
209
|
+
const usyncQuery = new WAUSync_1.USyncQuery().withLIDProtocol().withContext('background');
|
|
210
|
+
for (const jid of jids) {
|
|
211
|
+
if ((0, WABinary_1.isLidUser)(jid)) {
|
|
212
|
+
logger?.warn?.('LID user found in LID fetch call');
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
usyncQuery.withUser(new WAUSync_1.USyncUser().withId(jid));
|
|
216
|
+
}
|
|
217
|
+
if (usyncQuery.users.length === 0) {
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
const results = await executeUSyncQueryForLid(usyncQuery);
|
|
222
|
+
if (results) {
|
|
223
|
+
return results.list
|
|
224
|
+
.filter((a) => !!a.lid)
|
|
225
|
+
.map(({ lid, id }) => ({ pn: id, lid }));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
logger?.warn?.({ err }, 'pnFromLIDUSync failed');
|
|
230
|
+
}
|
|
231
|
+
return [];
|
|
232
|
+
};
|
|
233
|
+
// add transaction capability
|
|
234
|
+
const keys = (0, Utils_1.addTransactionCapability)(authState.keys, logger, transactionOpts);
|
|
235
|
+
const signalRepository = makeSignalRepository({ creds, keys }, logger, pnFromLIDUSync);
|
|
170
236
|
/** connection handshake */
|
|
171
237
|
const validateConnection = async () => {
|
|
172
238
|
let helloMsg = {
|
|
@@ -6,6 +6,57 @@ const WAProto_1 = require("../../WAProto");
|
|
|
6
6
|
const WABinary_1 = require("../WABinary");
|
|
7
7
|
const generics_1 = require("./generics");
|
|
8
8
|
const NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node';
|
|
9
|
+
/**
|
|
10
|
+
* Reads the addressing_mode / *_pn / *_lid attrs WA puts on a stanza so we know
|
|
11
|
+
* the "alternate" identity (lid<->pn) of the sender, if WA included one.
|
|
12
|
+
*/
|
|
13
|
+
const extractAddressingContext = (stanza) => {
|
|
14
|
+
var _a, _b, _c, _d, _e;
|
|
15
|
+
const sender = stanza.attrs.participant || stanza.attrs.from;
|
|
16
|
+
const addressingMode = stanza.attrs.addressing_mode || ((sender === null || sender === void 0 ? void 0 : sender.endsWith('lid')) ? 'lid' : 'pn');
|
|
17
|
+
let senderAlt;
|
|
18
|
+
let recipientAlt;
|
|
19
|
+
if (addressingMode === 'lid') {
|
|
20
|
+
senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn;
|
|
21
|
+
recipientAlt = stanza.attrs.recipient_pn;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid;
|
|
25
|
+
recipientAlt = stanza.attrs.recipient_lid;
|
|
26
|
+
}
|
|
27
|
+
return { addressingMode, senderAlt, recipientAlt };
|
|
28
|
+
};
|
|
29
|
+
exports.extractAddressingContext = extractAddressingContext;
|
|
30
|
+
/** picks which jid (pn or lid) should actually be used to load/decrypt the signal session */
|
|
31
|
+
const getDecryptionJid = async (sender, repository) => {
|
|
32
|
+
if (!repository || !repository.lidMapping) {
|
|
33
|
+
return sender;
|
|
34
|
+
}
|
|
35
|
+
if ((0, WABinary_1.isLidUser)(sender) || ((0, WABinary_1.isHostedLidUser) && (0, WABinary_1.isHostedLidUser)(sender))) {
|
|
36
|
+
return sender;
|
|
37
|
+
}
|
|
38
|
+
const mapped = await repository.lidMapping.getLIDForPN(sender);
|
|
39
|
+
return mapped || sender;
|
|
40
|
+
};
|
|
41
|
+
/** if WA told us the lid<->pn pairing for this sender via stanza attrs, persist it for next time */
|
|
42
|
+
const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
|
|
43
|
+
if (!repository || !repository.lidMapping) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const { senderAlt } = extractAddressingContext(stanza);
|
|
47
|
+
if (senderAlt && (0, WABinary_1.isLidUser)(senderAlt) && (0, WABinary_1.isPnUser)(sender) && decryptionJid === sender) {
|
|
48
|
+
try {
|
|
49
|
+
await repository.lidMapping.storeLIDPNMappings([{ lid: senderAlt, pn: sender }]);
|
|
50
|
+
if (repository.migrateSession) {
|
|
51
|
+
await repository.migrateSession(sender, senderAlt);
|
|
52
|
+
}
|
|
53
|
+
logger.debug({ sender, senderAlt }, 'Stored LID mapping from envelope');
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
logger.warn({ sender, senderAlt, error }, 'Failed to store LID mapping');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
9
60
|
/**
|
|
10
61
|
* Decode the received node as a message.
|
|
11
62
|
* @note this will only parse the message, not decrypt it
|
|
@@ -148,6 +199,8 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
148
199
|
}
|
|
149
200
|
decryptables += 1;
|
|
150
201
|
let msgBuffer;
|
|
202
|
+
const decryptionJid = await getDecryptionJid(author, repository);
|
|
203
|
+
await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger);
|
|
151
204
|
try {
|
|
152
205
|
const e2eType = attrs.type;
|
|
153
206
|
switch (e2eType) {
|
|
@@ -160,9 +213,8 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
160
213
|
break;
|
|
161
214
|
case 'pkmsg':
|
|
162
215
|
case 'msg':
|
|
163
|
-
const user = (0, WABinary_1.isJidUser)(sender) ? sender : author;
|
|
164
216
|
msgBuffer = await repository.decryptMessage({
|
|
165
|
-
jid:
|
|
217
|
+
jid: decryptionJid,
|
|
166
218
|
type: e2eType,
|
|
167
219
|
ciphertext: content
|
|
168
220
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langitdeveloper/baileys",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "WhatsApp API Modification By Langit",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"whatsapp",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"futoin-hkdf": "^1.5.1",
|
|
47
47
|
"libphonenumber-js": "^1.10.20",
|
|
48
48
|
"lodash": "^4.17.21",
|
|
49
|
-
"libsignal": "github:
|
|
49
|
+
"libsignal": "github:langitdeveloper-official/libsignal-node",
|
|
50
50
|
"music-metadata": "^7.12.3",
|
|
51
51
|
"node-cache": "^5.1.2",
|
|
52
52
|
"node-fetch": "^2.6.1",
|