@pontalabs/baileys 1.0.11 → 1.1.0
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 +96 -85
- package/lib/Defaults/connection.js +39 -0
- package/lib/Defaults/constants.js +50 -0
- package/lib/Defaults/history.js +13 -0
- package/lib/Defaults/index.js +36 -151
- package/lib/Defaults/media.js +43 -0
- package/lib/Defaults/phonenumber-mcc.json +221 -221
- package/lib/Defaults/prefix.js +12 -0
- package/lib/Defaults/vialeys-version.json +7 -0
- package/lib/Signal/Group/ciphertext-message.js +10 -15
- package/lib/Signal/Group/group-session-builder.js +34 -60
- package/lib/Signal/Group/group_cipher.js +69 -76
- package/lib/Signal/Group/index.js +41 -60
- package/lib/Signal/Group/keyhelper.js +12 -57
- package/lib/Signal/Group/sender-chain-key.js +20 -33
- package/lib/Signal/Group/sender-key-distribution-message.js +43 -48
- package/lib/Signal/Group/sender-key-message.js +58 -53
- package/lib/Signal/Group/sender-key-name.js +21 -31
- package/lib/Signal/Group/sender-key-record.js +21 -34
- package/lib/Signal/Group/sender-key-state.js +59 -106
- package/lib/Signal/Group/sender-message-key.js +16 -21
- package/lib/Signal/libsignal.js +282 -203
- package/lib/Signal/lid-mapping.js +164 -184
- package/lib/Socket/Client/index.js +31 -22
- package/lib/Socket/Client/types.js +9 -15
- package/lib/Socket/Client/websocket.js +42 -37
- package/lib/Socket/business.js +212 -336
- package/lib/Socket/chats.js +696 -940
- package/lib/Socket/community.js +454 -369
- package/lib/Socket/groups.js +278 -280
- package/lib/Socket/index.js +9 -21
- package/lib/Socket/messages-recv.js +1027 -1570
- package/lib/Socket/messages-send.js +1180 -1136
- package/lib/Socket/mex.js +59 -0
- package/lib/Socket/newsletter.js +193 -251
- package/lib/Socket/socket.js +758 -898
- package/lib/Store/index.js +35 -24
- package/lib/Store/make-cache-manager-store.js +53 -66
- package/lib/Store/make-in-memory-store.js +319 -325
- package/lib/Store/make-ordered-dictionary.js +49 -57
- package/lib/Store/object-repository.js +10 -15
- package/lib/Types/Auth.js +2 -3
- package/lib/Types/Bussines.js +2 -3
- package/lib/Types/Call.js +2 -3
- package/lib/Types/Chat.js +10 -9
- package/lib/Types/Contact.js +2 -3
- package/lib/Types/Events.js +2 -3
- package/lib/Types/GroupMetadata.js +2 -3
- package/lib/Types/Label.js +6 -12
- package/lib/Types/LabelAssociation.js +4 -13
- package/lib/Types/Message.js +10 -18
- package/lib/Types/MexUpdates.js +15 -18
- package/lib/Types/Newsletter.js +26 -34
- package/lib/Types/Product.js +2 -3
- package/lib/Types/Signal.js +2 -3
- package/lib/Types/Socket.js +2 -3
- package/lib/Types/State.js +8 -13
- package/lib/Types/USync.js +2 -3
- package/lib/Types/index.js +49 -40
- package/lib/Utils/auth-utils.js +190 -495
- package/lib/Utils/browser-utils.js +29 -0
- package/lib/Utils/business.js +177 -199
- package/lib/Utils/chat-utils.js +711 -624
- package/lib/Utils/crypto.js +116 -161
- package/lib/Utils/decode-wa-message.js +225 -321
- package/lib/Utils/event-buffer.js +363 -405
- package/lib/Utils/generics.js +318 -472
- package/lib/Utils/history.js +72 -76
- package/lib/Utils/index.js +49 -41
- package/lib/Utils/link-preview.js +59 -103
- package/lib/Utils/logger.js +4 -7
- package/lib/Utils/lt-hash.js +29 -42
- package/lib/Utils/make-mutex.js +26 -42
- package/lib/Utils/message-retry-manager.js +134 -160
- package/lib/Utils/messages-media.js +665 -731
- package/lib/Utils/messages.js +518 -1
- package/lib/Utils/noise-handler.js +127 -125
- package/lib/Utils/pre-key-manager.js +86 -0
- package/lib/Utils/process-message.js +739 -351
- package/lib/Utils/signal.js +146 -129
- package/lib/Utils/use-multi-file-auth-state.js +68 -135
- package/lib/Utils/validate-connection.js +183 -142
- package/lib/Utils/vialeys-event-stream.js +41 -0
- package/lib/WABinary/constants.js +1281 -1289
- package/lib/WABinary/decode.js +145 -200
- package/lib/WABinary/encode.js +149 -202
- package/lib/WABinary/generic-utils.js +79 -97
- package/lib/WABinary/index.js +36 -25
- package/lib/WABinary/jid-utils.js +91 -123
- package/lib/WABinary/types.js +2 -3
- package/lib/WAM/BinaryInfo.js +8 -13
- package/lib/WAM/constants.js +16584 -11464
- package/lib/WAM/encode.js +117 -133
- package/lib/WAM/index.js +34 -23
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +62 -69
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +11 -25
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +32 -44
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +13 -23
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +24 -38
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +17 -31
- package/lib/WAUSync/Protocols/index.js +37 -26
- package/lib/WAUSync/USyncQuery.js +66 -66
- package/lib/WAUSync/USyncUser.js +13 -18
- package/lib/WAUSync/index.js +34 -23
- package/lib/index.js +95 -28
- package/package.json +2 -1
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Signal/Group/queue-job.d.ts +0 -1
- package/lib/Signal/Group/queue-job.js +0 -57
- package/lib/Socket/usync.d.ts +0 -37
- package/lib/Socket/usync.js +0 -83
- package/lib/Utils/baileys-event-stream.d.ts +0 -18
- package/lib/Utils/baileys-event-stream.js +0 -70
- package/lib/Utils/signal-housekeeping.d.ts +0 -19
- package/lib/Utils/signal-housekeeping.js +0 -73
- package/lib/Utils/use-mongo-file-auth-state.d.ts +0 -6
- package/lib/Utils/use-mongo-file-auth-state.js +0 -84
- package/lib/Utils/use-single-file-auth-state.d.ts +0 -13
- package/lib/Utils/use-single-file-auth-state.js +0 -80
package/lib/Signal/libsignal.js
CHANGED
|
@@ -1,285 +1,364 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
function makeLibSignalRepository(auth, onWhatsAppFunc, logger) {
|
|
73
|
-
const lidMapping = new LIDMappingStore_1.LIDMappingStore(auth.keys, onWhatsAppFunc, logger)
|
|
74
|
-
const storage = signalStorage(auth);
|
|
75
|
-
return {
|
|
76
|
-
lidMapping,
|
|
77
|
-
decryptGroupMessage({ group, authorJid, msg }) {
|
|
3
|
+
const {
|
|
4
|
+
SessionCipher: SessionCipher,
|
|
5
|
+
SessionBuilder: SessionBuilder,
|
|
6
|
+
SessionRecord: SessionRecord,
|
|
7
|
+
ProtocolAddress: ProtocolAddress,
|
|
8
|
+
} = require("libsignal");
|
|
9
|
+
const { generateSignalPubKey: generateSignalPubKey } = require("../Utils");
|
|
10
|
+
const {
|
|
11
|
+
isHostedLidUser: isHostedLidUser,
|
|
12
|
+
isHostedPnUser: isHostedPnUser,
|
|
13
|
+
isLidUser: isLidUser,
|
|
14
|
+
isPnUser: isPnUser,
|
|
15
|
+
jidDecode: jidDecode,
|
|
16
|
+
transferDevice: transferDevice,
|
|
17
|
+
WAJIDDomains: WAJIDDomains,
|
|
18
|
+
} = require("../WABinary");
|
|
19
|
+
const { SenderKeyName: SenderKeyName } = require("./Group/sender-key-name");
|
|
20
|
+
const { SenderKeyRecord: SenderKeyRecord } = require("./Group/sender-key-record");
|
|
21
|
+
const {
|
|
22
|
+
GroupCipher: GroupCipher,
|
|
23
|
+
GroupSessionBuilder: GroupSessionBuilder,
|
|
24
|
+
SenderKeyDistributionMessage: SenderKeyDistributionMessage,
|
|
25
|
+
} = require("./Group");
|
|
26
|
+
const { LRUCache: LRUCache } = require("lru-cache");
|
|
27
|
+
const { LIDMappingStore: LIDMappingStore } = require("./lid-mapping");
|
|
28
|
+
function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
29
|
+
const lidMapping = new LIDMappingStore(auth.keys, logger, pnToLIDFunc);
|
|
30
|
+
const storage = signalStorage(auth, lidMapping);
|
|
31
|
+
const parsedKeys = auth.keys;
|
|
32
|
+
const migratedSessionCache = new LRUCache({
|
|
33
|
+
ttl: 3 * 24 * 60 * 60 * 1e3,
|
|
34
|
+
ttlAutopurge: true,
|
|
35
|
+
updateAgeOnGet: true,
|
|
36
|
+
});
|
|
37
|
+
const repository = {
|
|
38
|
+
decryptGroupMessage({ group: group, authorJid: authorJid, msg: msg }) {
|
|
78
39
|
const senderName = jidToSignalSenderKeyName(group, authorJid);
|
|
79
|
-
const cipher = new
|
|
80
|
-
|
|
81
|
-
// lainnya, cegah race condition kalau ada beberapa pesan grup dari
|
|
82
|
-
// sender yang sama numpuk barengan.
|
|
83
|
-
return auth.keys.transaction(async () => {
|
|
84
|
-
return cipher.decrypt(msg);
|
|
85
|
-
}, group);
|
|
40
|
+
const cipher = new GroupCipher(storage, senderName);
|
|
41
|
+
return parsedKeys.transaction(async () => cipher.decrypt(msg), group);
|
|
86
42
|
},
|
|
87
|
-
async processSenderKeyDistributionMessage({ item, authorJid }) {
|
|
88
|
-
const builder = new
|
|
43
|
+
async processSenderKeyDistributionMessage({ item: item, authorJid: authorJid }) {
|
|
44
|
+
const builder = new GroupSessionBuilder(storage);
|
|
89
45
|
if (!item.groupId) {
|
|
90
|
-
throw new Error(
|
|
46
|
+
throw new Error("Group ID is required for sender key distribution message");
|
|
91
47
|
}
|
|
92
48
|
const senderName = jidToSignalSenderKeyName(item.groupId, authorJid);
|
|
93
|
-
const senderMsg = new
|
|
49
|
+
const senderMsg = new SenderKeyDistributionMessage(
|
|
50
|
+
null,
|
|
51
|
+
null,
|
|
52
|
+
null,
|
|
53
|
+
null,
|
|
54
|
+
item.axolotlSenderKeyDistributionMessage
|
|
55
|
+
);
|
|
94
56
|
const senderNameStr = senderName.toString();
|
|
95
|
-
|
|
96
|
-
|
|
57
|
+
const { [senderNameStr]: senderKey } = await auth.keys.get("sender-key", [
|
|
58
|
+
senderNameStr,
|
|
59
|
+
]);
|
|
60
|
+
if (!senderKey) {
|
|
61
|
+
await storage.storeSenderKey(senderName, new SenderKeyRecord());
|
|
62
|
+
}
|
|
63
|
+
return parsedKeys.transaction(async () => {
|
|
64
|
+
const { [senderNameStr]: senderKey } = await auth.keys.get("sender-key", [
|
|
65
|
+
senderNameStr,
|
|
66
|
+
]);
|
|
97
67
|
if (!senderKey) {
|
|
98
|
-
await storage.storeSenderKey(senderName, new
|
|
68
|
+
await storage.storeSenderKey(senderName, new SenderKeyRecord());
|
|
99
69
|
}
|
|
100
70
|
await builder.process(senderName, senderMsg);
|
|
101
71
|
}, item.groupId);
|
|
102
72
|
},
|
|
103
|
-
async decryptMessage({ jid, type, ciphertext }) {
|
|
73
|
+
async decryptMessage({ jid: jid, type: type, ciphertext: ciphertext }) {
|
|
104
74
|
const addr = jidToSignalProtocolAddress(jid);
|
|
105
|
-
const session = new
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
logger?.info?.({ jid, addr: addrStr }, 'identity key changed or new contact, session will be re-established');
|
|
116
|
-
}
|
|
75
|
+
const session = new SessionCipher(storage, addr);
|
|
76
|
+
async function doDecrypt() {
|
|
77
|
+
let result;
|
|
78
|
+
switch (type) {
|
|
79
|
+
case "pkmsg":
|
|
80
|
+
result = await session.decryptPreKeyWhisperMessage(ciphertext);
|
|
81
|
+
break;
|
|
82
|
+
case "msg":
|
|
83
|
+
result = await session.decryptWhisperMessage(ciphertext);
|
|
84
|
+
break;
|
|
117
85
|
}
|
|
86
|
+
return result;
|
|
118
87
|
}
|
|
119
|
-
|
|
120
|
-
return await auth.keys.transaction(async () => {
|
|
121
|
-
let result;
|
|
122
|
-
switch (type) {
|
|
123
|
-
case 'pkmsg':
|
|
124
|
-
result = await session.decryptPreKeyWhisperMessage(ciphertext);
|
|
125
|
-
break;
|
|
126
|
-
case 'msg':
|
|
127
|
-
result = await session.decryptWhisperMessage(ciphertext);
|
|
128
|
-
break;
|
|
129
|
-
default:
|
|
130
|
-
throw new Error(`Unknown message type: ${type}`);
|
|
131
|
-
}
|
|
132
|
-
return result;
|
|
133
|
-
}, jid);
|
|
134
|
-
} catch (error) {
|
|
135
|
-
const errText = String(error?.message || error || '')
|
|
136
|
-
if (/bad mac|no session|invalid message|duplicate message|cannot decrypt/i.test(errText)) {
|
|
137
|
-
await storage.removeSession(addr.toString()).catch(() => null)
|
|
138
|
-
logger?.warn?.({ jid, type, errText }, 'reset stale session after decrypt failure')
|
|
139
|
-
}
|
|
140
|
-
throw error
|
|
141
|
-
}
|
|
88
|
+
return parsedKeys.transaction(async () => await doDecrypt(), jid);
|
|
142
89
|
},
|
|
143
|
-
async encryptMessage({ jid, data }) {
|
|
90
|
+
async encryptMessage({ jid: jid, data: data }) {
|
|
144
91
|
const addr = jidToSignalProtocolAddress(jid);
|
|
145
|
-
const cipher = new
|
|
146
|
-
return
|
|
147
|
-
const { type: sigType, body } = await cipher.encrypt(data);
|
|
148
|
-
const type = sigType === 3 ?
|
|
149
|
-
return { type, ciphertext: Buffer.from(body,
|
|
92
|
+
const cipher = new SessionCipher(storage, addr);
|
|
93
|
+
return parsedKeys.transaction(async () => {
|
|
94
|
+
const { type: sigType, body: body } = await cipher.encrypt(data);
|
|
95
|
+
const type = sigType === 3 ? "pkmsg" : "msg";
|
|
96
|
+
return { type: type, ciphertext: Buffer.from(body, "binary") };
|
|
150
97
|
}, jid);
|
|
151
98
|
},
|
|
152
|
-
async encryptGroupMessage({ group, meId, data }) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const { [senderNameStr]: senderKey } = await auth.keys.get(
|
|
99
|
+
async encryptGroupMessage({ group: group, meId: meId, data: data }) {
|
|
100
|
+
const senderName = jidToSignalSenderKeyName(group, meId);
|
|
101
|
+
const builder = new GroupSessionBuilder(storage);
|
|
102
|
+
const senderNameStr = senderName.toString();
|
|
103
|
+
return parsedKeys.transaction(async () => {
|
|
104
|
+
const { [senderNameStr]: senderKey } = await auth.keys.get("sender-key", [
|
|
105
|
+
senderNameStr,
|
|
106
|
+
]);
|
|
158
107
|
if (!senderKey) {
|
|
159
|
-
await storage.storeSenderKey(senderName, new
|
|
108
|
+
await storage.storeSenderKey(senderName, new SenderKeyRecord());
|
|
160
109
|
}
|
|
161
110
|
const senderKeyDistributionMessage = await builder.create(senderName);
|
|
162
|
-
const session = new
|
|
111
|
+
const session = new GroupCipher(storage, senderName);
|
|
163
112
|
const ciphertext = await session.encrypt(data);
|
|
164
113
|
return {
|
|
165
|
-
ciphertext,
|
|
166
|
-
senderKeyDistributionMessage: senderKeyDistributionMessage.serialize()
|
|
114
|
+
ciphertext: ciphertext,
|
|
115
|
+
senderKeyDistributionMessage: senderKeyDistributionMessage.serialize(),
|
|
167
116
|
};
|
|
168
117
|
}, group);
|
|
169
118
|
},
|
|
170
|
-
async injectE2ESession({ jid, session }) {
|
|
171
|
-
|
|
172
|
-
|
|
119
|
+
async injectE2ESession({ jid: jid, session: session }) {
|
|
120
|
+
logger.trace({ jid: jid }, "injecting E2EE session");
|
|
121
|
+
const cipher = new SessionBuilder(storage, jidToSignalProtocolAddress(jid));
|
|
122
|
+
return parsedKeys.transaction(async () => {
|
|
123
|
+
await cipher.initOutgoing(session);
|
|
124
|
+
}, jid);
|
|
173
125
|
},
|
|
174
126
|
jidToSignalProtocolAddress(jid) {
|
|
175
127
|
return jidToSignalProtocolAddress(jid).toString();
|
|
176
128
|
},
|
|
177
|
-
|
|
178
|
-
// Sebelumnya dipanggil tapi tidak pernah diimplementasikan di sini, jadi fitur auto
|
|
179
|
-
// session recreation diam-diam selalu gagal (ketangkep try/catch, cuma log warning).
|
|
129
|
+
lidMapping: lidMapping,
|
|
180
130
|
async validateSession(jid) {
|
|
181
131
|
try {
|
|
182
132
|
const addr = jidToSignalProtocolAddress(jid);
|
|
183
133
|
const session = await storage.loadSession(addr.toString());
|
|
184
134
|
if (!session) {
|
|
185
|
-
return { exists: false, reason:
|
|
135
|
+
return { exists: false, reason: "no session" };
|
|
186
136
|
}
|
|
187
|
-
if (
|
|
188
|
-
return { exists: false, reason:
|
|
137
|
+
if (!session.haveOpenSession()) {
|
|
138
|
+
return { exists: false, reason: "no open session" };
|
|
189
139
|
}
|
|
190
140
|
return { exists: true };
|
|
191
141
|
} catch (error) {
|
|
192
|
-
return { exists: false, reason:
|
|
142
|
+
return { exists: false, reason: "validation error" };
|
|
193
143
|
}
|
|
194
|
-
}
|
|
144
|
+
},
|
|
145
|
+
async deleteSession(jids) {
|
|
146
|
+
if (!jids.length) return;
|
|
147
|
+
const sessionUpdates = {};
|
|
148
|
+
jids.forEach((jid) => {
|
|
149
|
+
const addr = jidToSignalProtocolAddress(jid);
|
|
150
|
+
sessionUpdates[addr.toString()] = null;
|
|
151
|
+
});
|
|
152
|
+
return parsedKeys.transaction(async () => {
|
|
153
|
+
await auth.keys.set({ session: sessionUpdates });
|
|
154
|
+
}, `delete-${jids.length}-sessions`);
|
|
155
|
+
},
|
|
156
|
+
async migrateSession(fromJid, toJid) {
|
|
157
|
+
if (!fromJid || (!isLidUser(toJid) && !isHostedLidUser(toJid))) {
|
|
158
|
+
return { migrated: 0, skipped: 0, total: 0 };
|
|
159
|
+
}
|
|
160
|
+
if (!isPnUser(fromJid) && !isHostedPnUser(fromJid)) {
|
|
161
|
+
return { migrated: 0, skipped: 0, total: 1 };
|
|
162
|
+
}
|
|
163
|
+
const { user: user } = jidDecode(fromJid);
|
|
164
|
+
logger.debug({ fromJid: fromJid }, "bulk device migration - loading all user devices");
|
|
165
|
+
const { [user]: userDevices } = await parsedKeys.get("device-list", [user]);
|
|
166
|
+
if (!userDevices) {
|
|
167
|
+
return { migrated: 0, skipped: 0, total: 0 };
|
|
168
|
+
}
|
|
169
|
+
const { device: fromDevice } = jidDecode(fromJid);
|
|
170
|
+
const fromDeviceStr = fromDevice?.toString() || "0";
|
|
171
|
+
if (!userDevices.includes(fromDeviceStr)) {
|
|
172
|
+
userDevices.push(fromDeviceStr);
|
|
173
|
+
}
|
|
174
|
+
const uncachedDevices = userDevices.filter((device) => {
|
|
175
|
+
const deviceKey = `${user}.${device}`;
|
|
176
|
+
return !migratedSessionCache.has(deviceKey);
|
|
177
|
+
});
|
|
178
|
+
const deviceSessionKeys = uncachedDevices.map((device) => `${user}.${device}`);
|
|
179
|
+
const existingSessions = await parsedKeys.get("session", deviceSessionKeys);
|
|
180
|
+
const deviceJids = [];
|
|
181
|
+
for (const [sessionKey, sessionData] of Object.entries(existingSessions)) {
|
|
182
|
+
if (sessionData) {
|
|
183
|
+
const deviceStr = sessionKey.split(".")[1];
|
|
184
|
+
if (!deviceStr) continue;
|
|
185
|
+
const deviceNum = parseInt(deviceStr);
|
|
186
|
+
let jid =
|
|
187
|
+
deviceNum === 0
|
|
188
|
+
? `${user}@s.whatsapp.net`
|
|
189
|
+
: `${user}:${deviceNum}@s.whatsapp.net`;
|
|
190
|
+
if (deviceNum === 99) {
|
|
191
|
+
jid = `${user}:99@hosted`;
|
|
192
|
+
}
|
|
193
|
+
deviceJids.push(jid);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
logger.debug(
|
|
197
|
+
{
|
|
198
|
+
fromJid: fromJid,
|
|
199
|
+
totalDevices: userDevices.length,
|
|
200
|
+
devicesWithSessions: deviceJids.length,
|
|
201
|
+
devices: deviceJids,
|
|
202
|
+
},
|
|
203
|
+
"bulk device migration complete - all user devices processed"
|
|
204
|
+
);
|
|
205
|
+
return parsedKeys.transaction(
|
|
206
|
+
async () => {
|
|
207
|
+
const migrationOps = deviceJids.map((jid) => {
|
|
208
|
+
const lidWithDevice = transferDevice(jid, toJid);
|
|
209
|
+
const fromDecoded = jidDecode(jid);
|
|
210
|
+
const toDecoded = jidDecode(lidWithDevice);
|
|
211
|
+
return {
|
|
212
|
+
fromJid: jid,
|
|
213
|
+
toJid: lidWithDevice,
|
|
214
|
+
pnUser: fromDecoded.user,
|
|
215
|
+
lidUser: toDecoded.user,
|
|
216
|
+
deviceId: fromDecoded.device || 0,
|
|
217
|
+
fromAddr: jidToSignalProtocolAddress(jid),
|
|
218
|
+
toAddr: jidToSignalProtocolAddress(lidWithDevice),
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
const totalOps = migrationOps.length;
|
|
222
|
+
let migratedCount = 0;
|
|
223
|
+
const pnAddrStrings = Array.from(
|
|
224
|
+
new Set(migrationOps.map((op) => op.fromAddr.toString()))
|
|
225
|
+
);
|
|
226
|
+
const pnSessions = await parsedKeys.get("session", pnAddrStrings);
|
|
227
|
+
const sessionUpdates = {};
|
|
228
|
+
for (const op of migrationOps) {
|
|
229
|
+
const pnAddrStr = op.fromAddr.toString();
|
|
230
|
+
const lidAddrStr = op.toAddr.toString();
|
|
231
|
+
const pnSession = pnSessions[pnAddrStr];
|
|
232
|
+
if (pnSession) {
|
|
233
|
+
const fromSession = SessionRecord.deserialize(pnSession);
|
|
234
|
+
if (fromSession.haveOpenSession()) {
|
|
235
|
+
sessionUpdates[lidAddrStr] = fromSession.serialize();
|
|
236
|
+
sessionUpdates[pnAddrStr] = null;
|
|
237
|
+
migratedCount++;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (Object.keys(sessionUpdates).length > 0) {
|
|
242
|
+
await parsedKeys.set({ session: sessionUpdates });
|
|
243
|
+
logger.debug(
|
|
244
|
+
{ migratedSessions: migratedCount },
|
|
245
|
+
"bulk session migration complete"
|
|
246
|
+
);
|
|
247
|
+
for (const op of migrationOps) {
|
|
248
|
+
if (sessionUpdates[op.toAddr.toString()]) {
|
|
249
|
+
const deviceKey = `${op.pnUser}.${op.deviceId}`;
|
|
250
|
+
migratedSessionCache.set(deviceKey, true);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const skippedCount = totalOps - migratedCount;
|
|
255
|
+
return {
|
|
256
|
+
migrated: migratedCount,
|
|
257
|
+
skipped: skippedCount,
|
|
258
|
+
total: totalOps,
|
|
259
|
+
};
|
|
260
|
+
},
|
|
261
|
+
`migrate-${deviceJids.length}-sessions-${jidDecode(toJid)?.user}`
|
|
262
|
+
);
|
|
263
|
+
},
|
|
195
264
|
};
|
|
265
|
+
return repository;
|
|
196
266
|
}
|
|
197
267
|
const jidToSignalProtocolAddress = (jid) => {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
268
|
+
const decoded = jidDecode(jid);
|
|
269
|
+
const { user: user, device: device, server: server, domainType: domainType } = decoded;
|
|
270
|
+
if (!user) {
|
|
271
|
+
throw new Error(
|
|
272
|
+
`JID decoded but user is empty: "${jid}" -> user: "${user}", server: "${server}", device: ${device}`
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
const signalUser = domainType !== WAJIDDomains.WHATSAPP ? `${user}_${domainType}` : user;
|
|
276
|
+
const finalDevice = device || 0;
|
|
277
|
+
if (device === 99 && decoded.server !== "hosted" && decoded.server !== "hosted.lid") {
|
|
278
|
+
throw new Error(
|
|
279
|
+
"Unexpected non-hosted device JID with device 99. This ID seems invalid. ID:" + jid
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
return new ProtocolAddress(signalUser, finalDevice);
|
|
203
283
|
};
|
|
204
|
-
|
|
284
|
+
const jidToSignalSenderKeyName = (group, user) =>
|
|
285
|
+
new SenderKeyName(group, jidToSignalProtocolAddress(user));
|
|
286
|
+
function signalStorage({ creds: creds, keys: keys }, lidMapping) {
|
|
287
|
+
const resolveLIDSignalAddress = async (id) => {
|
|
288
|
+
if (id.includes(".")) {
|
|
289
|
+
const [deviceId, device] = id.split(".");
|
|
290
|
+
const [user, domainType_] = deviceId.split("_");
|
|
291
|
+
const domainType = parseInt(domainType_ || "0");
|
|
292
|
+
if (domainType === WAJIDDomains.LID || domainType === WAJIDDomains.HOSTED_LID)
|
|
293
|
+
return id;
|
|
294
|
+
const pnJid = `${user}${device !== "0" ? `:${device}` : ""}@${domainType === WAJIDDomains.HOSTED ? "hosted" : "s.whatsapp.net"}`;
|
|
295
|
+
const lidForPN = await lidMapping.getLIDForPN(pnJid);
|
|
296
|
+
if (lidForPN) {
|
|
297
|
+
const lidAddr = jidToSignalProtocolAddress(lidForPN);
|
|
298
|
+
return lidAddr.toString();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return id;
|
|
302
|
+
};
|
|
205
303
|
return {
|
|
206
304
|
loadSession: async (id) => {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
305
|
+
try {
|
|
306
|
+
const wireJid = await resolveLIDSignalAddress(id);
|
|
307
|
+
const { [wireJid]: sess } = await keys.get("session", [wireJid]);
|
|
308
|
+
if (sess) {
|
|
309
|
+
return SessionRecord.deserialize(sess);
|
|
310
|
+
}
|
|
311
|
+
} catch (e) {
|
|
312
|
+
return null;
|
|
210
313
|
}
|
|
314
|
+
return null;
|
|
211
315
|
},
|
|
212
316
|
storeSession: async (id, session) => {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
removeSession: async (id) => {
|
|
216
|
-
await keys.set({ session: { [id]: null } });
|
|
217
|
-
},
|
|
218
|
-
isTrustedIdentity: () => {
|
|
219
|
-
return true;
|
|
220
|
-
},
|
|
221
|
-
loadIdentityKey: async (id) => {
|
|
222
|
-
const { [id]: key } = await keys.get('identity-key', [id]);
|
|
223
|
-
return key || undefined;
|
|
224
|
-
},
|
|
225
|
-
saveIdentity: async (id, identityKey) => {
|
|
226
|
-
const { [id]: existingKey } = await keys.get('identity-key', [id]);
|
|
227
|
-
const keysMatch = existingKey && existingKey.length === identityKey.length &&
|
|
228
|
-
Buffer.compare(Buffer.from(existingKey), Buffer.from(identityKey)) === 0;
|
|
229
|
-
if (existingKey && !keysMatch) {
|
|
230
|
-
// Identity berubah - hapus sesi lama (bakal ke-generate ulang dari
|
|
231
|
-
// pkmsg yang lagi diproses) dan simpan identity key yang baru.
|
|
232
|
-
await keys.set({
|
|
233
|
-
session: { [id]: null },
|
|
234
|
-
'identity-key': { [id]: identityKey }
|
|
235
|
-
});
|
|
236
|
-
return true;
|
|
237
|
-
}
|
|
238
|
-
if (!existingKey) {
|
|
239
|
-
// Kontak baru - Trust On First Use (TOFU), sama kayak WhatsApp Web.
|
|
240
|
-
await keys.set({ 'identity-key': { [id]: identityKey } });
|
|
241
|
-
return true;
|
|
242
|
-
}
|
|
243
|
-
return false;
|
|
317
|
+
const wireJid = await resolveLIDSignalAddress(id);
|
|
318
|
+
await keys.set({ session: { [wireJid]: session.serialize() } });
|
|
244
319
|
},
|
|
320
|
+
isTrustedIdentity: () => true,
|
|
245
321
|
loadPreKey: async (id) => {
|
|
246
322
|
const keyId = id.toString();
|
|
247
|
-
const { [keyId]: key } = await keys.get(
|
|
323
|
+
const { [keyId]: key } = await keys.get("pre-key", [keyId]);
|
|
248
324
|
if (key) {
|
|
249
325
|
return {
|
|
250
326
|
privKey: Buffer.from(key.private),
|
|
251
|
-
pubKey: Buffer.from(key.public)
|
|
327
|
+
pubKey: Buffer.from(key.public),
|
|
252
328
|
};
|
|
253
329
|
}
|
|
254
330
|
},
|
|
255
|
-
removePreKey: (id) => keys.set({
|
|
331
|
+
removePreKey: (id) => keys.set({ "pre-key": { [id]: null } }),
|
|
256
332
|
loadSignedPreKey: () => {
|
|
257
333
|
const key = creds.signedPreKey;
|
|
258
334
|
return {
|
|
259
335
|
privKey: Buffer.from(key.keyPair.private),
|
|
260
|
-
pubKey: Buffer.from(key.keyPair.public)
|
|
336
|
+
pubKey: Buffer.from(key.keyPair.public),
|
|
261
337
|
};
|
|
262
338
|
},
|
|
263
339
|
loadSenderKey: async (senderKeyName) => {
|
|
264
340
|
const keyId = senderKeyName.toString();
|
|
265
|
-
const { [keyId]: key } = await keys.get(
|
|
341
|
+
const { [keyId]: key } = await keys.get("sender-key", [keyId]);
|
|
266
342
|
if (key) {
|
|
267
|
-
return
|
|
343
|
+
return SenderKeyRecord.deserialize(key);
|
|
268
344
|
}
|
|
269
|
-
return new
|
|
345
|
+
return new SenderKeyRecord();
|
|
270
346
|
},
|
|
271
347
|
storeSenderKey: async (senderKeyName, key) => {
|
|
272
348
|
const keyId = senderKeyName.toString();
|
|
273
349
|
const serialized = JSON.stringify(key.serialize());
|
|
274
|
-
await keys.set({
|
|
350
|
+
await keys.set({
|
|
351
|
+
"sender-key": { [keyId]: Buffer.from(serialized, "utf-8") },
|
|
352
|
+
});
|
|
275
353
|
},
|
|
276
354
|
getOurRegistrationId: () => creds.registrationId,
|
|
277
355
|
getOurIdentity: () => {
|
|
278
|
-
const { signedIdentityKey } = creds;
|
|
356
|
+
const { signedIdentityKey: signedIdentityKey } = creds;
|
|
279
357
|
return {
|
|
280
358
|
privKey: Buffer.from(signedIdentityKey.private),
|
|
281
|
-
pubKey: (
|
|
359
|
+
pubKey: Buffer.from(generateSignalPubKey(signedIdentityKey.public)),
|
|
282
360
|
};
|
|
283
|
-
}
|
|
361
|
+
},
|
|
284
362
|
};
|
|
285
363
|
}
|
|
364
|
+
module.exports = { makeLibSignalRepository: makeLibSignalRepository };
|