@pontalabs/baileys 1.0.6 → 1.0.8
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/LICENSE +1 -1
- package/README.md +839 -267
- package/WAProto/GenerateStatics.sh +4 -3
- package/WAProto/WAProto.proto +511 -1215
- package/WAProto/index.d.ts +55 -14017
- package/WAProto/index.js +29 -97689
- package/lib/Defaults/index.d.ts +74 -72
- package/lib/Defaults/index.js +108 -94
- package/lib/Signal/Group/ciphertext-message.d.ts +7 -8
- package/lib/Signal/Group/ciphertext-message.js +16 -9
- package/lib/Signal/Group/group-session-builder.d.ts +13 -11
- package/lib/Signal/Group/group-session-builder.js +61 -19
- package/lib/Signal/Group/group_cipher.d.ts +16 -14
- package/lib/Signal/Group/group_cipher.js +70 -41
- package/lib/Signal/Group/index.d.ts +11 -12
- package/lib/Signal/Group/index.js +61 -12
- package/lib/Signal/Group/keyhelper.d.ts +14 -9
- package/lib/Signal/Group/keyhelper.js +58 -10
- package/lib/Signal/Group/sender-chain-key.d.ts +13 -13
- package/lib/Signal/Group/sender-chain-key.js +34 -13
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -16
- package/lib/Signal/Group/sender-key-distribution-message.js +36 -28
- package/lib/Signal/Group/sender-key-message.d.ts +18 -18
- package/lib/Signal/Group/sender-key-message.js +45 -38
- package/lib/Signal/Group/sender-key-name.d.ts +15 -14
- package/lib/Signal/Group/sender-key-name.js +31 -20
- package/lib/Signal/Group/sender-key-record.d.ts +25 -24
- package/lib/Signal/Group/sender-key-record.js +35 -18
- package/lib/Signal/Group/sender-key-state.d.ts +34 -29
- package/lib/Signal/Group/sender-key-state.js +100 -37
- package/lib/Signal/Group/sender-message-key.d.ts +10 -11
- package/lib/Signal/Group/sender-message-key.js +22 -15
- package/lib/Signal/libsignal.d.ts +8 -5
- package/lib/Signal/libsignal.js +142 -288
- package/lib/Signal/lid-mapping.d.ts +28 -23
- package/lib/Signal/lid-mapping.js +184 -277
- package/lib/Socket/Client/index.d.ts +2 -3
- package/lib/Socket/Client/index.js +22 -3
- package/lib/Socket/Client/types.d.ts +15 -15
- package/lib/Socket/Client/types.js +15 -8
- package/lib/Socket/Client/websocket.d.ts +12 -12
- package/lib/Socket/Client/websocket.js +37 -29
- package/lib/Socket/business.d.ts +178 -208
- package/lib/Socket/business.js +127 -91
- package/lib/Socket/chats.d.ts +93 -120
- package/lib/Socket/chats.js +652 -727
- package/lib/Socket/community.js +10 -2
- package/lib/Socket/groups.d.ts +111 -143
- package/lib/Socket/groups.js +186 -165
- package/lib/Socket/index.d.ts +183 -252
- package/lib/Socket/index.js +18 -38
- package/lib/Socket/messages-recv.d.ts +167 -196
- package/lib/Socket/messages-recv.js +1567 -1443
- package/lib/Socket/messages-send.d.ts +158 -192
- package/lib/Socket/messages-send.js +1208 -1102
- package/lib/Socket/newsletter.d.ts +138 -163
- package/lib/Socket/newsletter.js +249 -153
- package/lib/Socket/socket.d.ts +36 -50
- package/lib/Socket/socket.js +820 -749
- package/lib/Store/index.d.ts +4 -4
- package/lib/Store/index.js +24 -4
- package/lib/Store/make-in-memory-store.d.ts +104 -44
- package/lib/Store/make-in-memory-store.js +213 -199
- package/lib/Store/make-ordered-dictionary.d.ts +12 -13
- package/lib/Store/make-ordered-dictionary.js +45 -38
- package/lib/Store/object-repository.d.ts +10 -11
- package/lib/Store/object-repository.js +16 -9
- package/lib/Types/Auth.d.ts +97 -93
- package/lib/Types/Auth.js +3 -2
- package/lib/Types/Bussines.js +3 -2
- package/lib/Types/Call.d.ts +13 -14
- package/lib/Types/Call.js +3 -2
- package/lib/Types/Chat.d.ts +97 -78
- package/lib/Types/Chat.js +9 -8
- package/lib/Types/Contact.d.ts +9 -12
- package/lib/Types/Contact.js +3 -2
- package/lib/Types/Events.d.ts +176 -206
- package/lib/Types/Events.js +3 -2
- package/lib/Types/GroupMetadata.d.ts +48 -53
- package/lib/Types/GroupMetadata.js +3 -2
- package/lib/Types/Label.d.ts +14 -13
- package/lib/Types/Label.js +30 -24
- package/lib/Types/LabelAssociation.d.ts +20 -15
- package/lib/Types/LabelAssociation.js +12 -6
- package/lib/Types/Message.d.ts +412 -248
- package/lib/Types/Message.js +19 -17
- package/lib/Types/Product.d.ts +71 -58
- package/lib/Types/Product.js +3 -2
- package/lib/Types/Signal.d.ts +82 -71
- package/lib/Types/Signal.js +3 -2
- package/lib/Types/Socket.d.ts +81 -76
- package/lib/Types/Socket.js +3 -3
- package/lib/Types/State.d.ts +19 -75
- package/lib/Types/State.js +14 -56
- package/lib/Types/USync.d.ts +8 -8
- package/lib/Types/USync.js +3 -2
- package/lib/Types/index.d.ts +62 -47
- package/lib/Types/index.js +50 -26
- package/lib/Utils/auth-utils.d.ts +10 -13
- package/lib/Utils/auth-utils.js +472 -213
- package/lib/Utils/business.d.ts +20 -14
- package/lib/Utils/business.js +134 -110
- package/lib/Utils/chat-utils.d.ts +70 -88
- package/lib/Utils/chat-utils.js +403 -466
- package/lib/Utils/crypto.d.ts +46 -27
- package/lib/Utils/crypto.js +188 -117
- package/lib/Utils/decode-wa-message.d.ts +45 -58
- package/lib/Utils/decode-wa-message.js +311 -212
- package/lib/Utils/event-buffer.d.ts +17 -14
- package/lib/Utils/event-buffer.js +296 -321
- package/lib/Utils/generics.d.ts +92 -66
- package/lib/Utils/generics.js +436 -270
- package/lib/Utils/history.d.ts +23 -24
- package/lib/Utils/history.js +76 -106
- package/lib/Utils/index.d.ts +21 -24
- package/lib/Utils/index.js +41 -24
- package/lib/Utils/link-preview.d.ts +14 -12
- package/lib/Utils/link-preview.js +75 -40
- package/lib/Utils/logger.d.ts +11 -10
- package/lib/Utils/logger.js +7 -3
- package/lib/Utils/lt-hash.d.ts +14 -8
- package/lib/Utils/lt-hash.js +53 -3
- package/lib/Utils/make-mutex.d.ts +7 -7
- package/lib/Utils/make-mutex.js +44 -28
- package/lib/Utils/message-retry-manager.d.ts +88 -115
- package/lib/Utils/message-retry-manager.js +160 -265
- package/lib/Utils/messages-media.d.ts +107 -105
- package/lib/Utils/messages-media.js +619 -548
- package/lib/Utils/messages.d.ts +66 -52
- package/lib/Utils/messages.js +1558 -1730
- package/lib/Utils/noise-handler.d.ts +18 -18
- package/lib/Utils/noise-handler.js +130 -176
- package/lib/Utils/process-message.d.ts +32 -43
- package/lib/Utils/process-message.js +282 -484
- package/lib/Utils/rich-message-utils.js +724 -1220
- package/lib/Utils/signal.d.ts +32 -37
- package/lib/Utils/signal.js +105 -140
- package/lib/Utils/use-multi-file-auth-state.d.ts +5 -5
- package/lib/Utils/use-multi-file-auth-state.js +120 -70
- package/lib/Utils/use-single-file-auth-state.d.ts +13 -11
- package/lib/Utils/use-single-file-auth-state.js +66 -92
- package/lib/Utils/validate-connection.d.ts +13 -11
- package/lib/Utils/validate-connection.js +113 -128
- package/lib/WABinary/constants.d.ts +27 -25
- package/lib/WABinary/constants.js +1292 -1451
- package/lib/WABinary/decode.d.ts +9 -7
- package/lib/WABinary/decode.js +189 -163
- package/lib/WABinary/encode.d.ts +3 -3
- package/lib/WABinary/encode.js +155 -110
- package/lib/WABinary/generic-utils.d.ts +27 -14
- package/lib/WABinary/generic-utils.js +105 -177
- package/lib/WABinary/index.d.ts +5 -6
- package/lib/WABinary/index.js +25 -6
- package/lib/WABinary/jid-utils.d.ts +54 -41
- package/lib/WABinary/jid-utils.js +152 -83
- package/lib/WABinary/types.d.ts +13 -10
- package/lib/WABinary/types.js +3 -2
- package/lib/WAM/BinaryInfo.d.ts +15 -8
- package/lib/WAM/BinaryInfo.js +14 -7
- package/lib/WAM/constants.d.ts +37 -30
- package/lib/WAM/constants.js +11983 -19465
- package/lib/WAM/encode.d.ts +3 -3
- package/lib/WAM/encode.js +109 -95
- package/lib/WAM/index.d.ts +3 -4
- package/lib/WAM/index.js +23 -4
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -9
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +21 -37
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -19
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +26 -18
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -11
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +20 -12
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -11
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +24 -16
- package/lib/WAUSync/Protocols/index.d.ts +6 -6
- package/lib/WAUSync/Protocols/index.js +26 -6
- package/lib/WAUSync/USyncQuery.d.ts +28 -27
- package/lib/WAUSync/USyncQuery.js +62 -68
- package/lib/WAUSync/USyncUser.d.ts +10 -15
- package/lib/WAUSync/USyncUser.js +19 -20
- package/lib/WAUSync/index.d.ts +3 -4
- package/lib/WAUSync/index.js +23 -4
- package/lib/index.d.ts +12 -11
- package/lib/index.js +39 -12
- package/package.json +43 -87
- package/engine-requirements.js +0 -10
|
@@ -1,26 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict"
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true })
|
|
3
|
+
|
|
4
|
+
const crypto_1 = require("libsignal/src/crypto")
|
|
5
|
+
|
|
6
|
+
class SenderMessageKey {
|
|
3
7
|
constructor(iteration, seed) {
|
|
4
|
-
const derivative = deriveSecrets(seed, Buffer.alloc(32), Buffer.from('WhisperGroup'))
|
|
5
|
-
const keys = new Uint8Array(32)
|
|
6
|
-
keys.set(new Uint8Array(derivative[0].slice(16)))
|
|
7
|
-
keys.set(new Uint8Array(derivative[1].slice(0, 16)), 16)
|
|
8
|
-
this.iv = Buffer.from(derivative[0].slice(0, 16))
|
|
9
|
-
this.cipherKey = Buffer.from(keys.buffer)
|
|
10
|
-
this.iteration = iteration
|
|
11
|
-
this.seed = seed
|
|
8
|
+
const derivative = (0, crypto_1.deriveSecrets)(seed, Buffer.alloc(32), Buffer.from('WhisperGroup'))
|
|
9
|
+
const keys = new Uint8Array(32)
|
|
10
|
+
keys.set(new Uint8Array(derivative[0].slice(16)))
|
|
11
|
+
keys.set(new Uint8Array(derivative[1].slice(0, 16)), 16)
|
|
12
|
+
this.iv = Buffer.from(derivative[0].slice(0, 16))
|
|
13
|
+
this.cipherKey = Buffer.from(keys.buffer)
|
|
14
|
+
this.iteration = iteration
|
|
15
|
+
this.seed = seed
|
|
12
16
|
}
|
|
13
17
|
getIteration() {
|
|
14
|
-
return this.iteration
|
|
18
|
+
return this.iteration
|
|
15
19
|
}
|
|
16
20
|
getIv() {
|
|
17
|
-
return this.iv
|
|
21
|
+
return this.iv
|
|
18
22
|
}
|
|
19
23
|
getCipherKey() {
|
|
20
|
-
return this.cipherKey
|
|
24
|
+
return this.cipherKey
|
|
21
25
|
}
|
|
22
26
|
getSeed() {
|
|
23
|
-
return this.seed
|
|
27
|
+
return this.seed
|
|
24
28
|
}
|
|
25
29
|
}
|
|
26
|
-
|
|
30
|
+
|
|
31
|
+
module.exports = {
|
|
32
|
+
SenderMessageKey
|
|
33
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
export declare function makeLibSignalRepository(auth: SignalAuthState,
|
|
5
|
-
|
|
1
|
+
import { SignalAuthState } from '../Types'
|
|
2
|
+
import { SignalRepository } from '../Types/Signal'
|
|
3
|
+
|
|
4
|
+
export declare function makeLibSignalRepository(auth: SignalAuthState, onWhatsAppFunc?: (...jids: string[]) => Promise<{
|
|
5
|
+
jid: string
|
|
6
|
+
exists: boolean
|
|
7
|
+
lid: string
|
|
8
|
+
}[] | undefined>): SignalRepository
|
package/lib/Signal/libsignal.js
CHANGED
|
@@ -1,80 +1,101 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.makeLibSignalRepository = makeLibSignalRepository;
|
|
37
|
+
const libsignal = __importStar(require("libsignal"));
|
|
38
|
+
const { PreKeyWhisperMessage } = require("libsignal/src/protobufs");
|
|
39
|
+
const Utils_1 = require("../Utils");
|
|
40
|
+
const WABinary_1 = require("../WABinary");
|
|
41
|
+
const sender_key_name_1 = require("./Group/sender-key-name");
|
|
42
|
+
const sender_key_record_1 = require("./Group/sender-key-record");
|
|
43
|
+
const Group_1 = require("./Group");
|
|
44
|
+
const LIDMappingStore_1 = require("./lid-mapping")
|
|
45
|
+
|
|
46
|
+
// FIX: sebelumnya pontalabs gak punya deteksi perubahan identity key sama
|
|
47
|
+
// sekali. Kalau identity kontak berubah (kontak install ulang WA, atau kena
|
|
48
|
+
// resync multi-device pas ada linked device lain online), sesi lama tetap
|
|
49
|
+
// dipakai terus dan selalu gagal decrypt "Bad MAC" berulang-ulang sampai
|
|
50
|
+
// akhirnya kena threshold retry enableAutoSessionRecreation. Dengan deteksi
|
|
51
|
+
// ini, begitu identity berubah, sesi langsung direset SAAT ITU JUGA - gak
|
|
52
|
+
// perlu nunggu beberapa pesan gagal dulu.
|
|
13
53
|
function extractIdentityFromPkmsg(ciphertext) {
|
|
14
54
|
try {
|
|
15
55
|
if (!ciphertext || ciphertext.length < 2) {
|
|
16
56
|
return undefined;
|
|
17
57
|
}
|
|
18
|
-
// Version byte check (version 3)
|
|
19
58
|
const version = ciphertext[0];
|
|
20
59
|
if ((version & 0xf) !== 3) {
|
|
21
60
|
return undefined;
|
|
22
61
|
}
|
|
23
|
-
// Parse protobuf (skip version byte)
|
|
24
62
|
const preKeyProto = PreKeyWhisperMessage.decode(ciphertext.slice(1));
|
|
25
|
-
if (preKeyProto.identityKey
|
|
26
|
-
return
|
|
63
|
+
if (preKeyProto.identityKey && preKeyProto.identityKey.length === 33) {
|
|
64
|
+
return Buffer.from(preKeyProto.identityKey);
|
|
27
65
|
}
|
|
28
66
|
return undefined;
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
67
|
+
} catch {
|
|
31
68
|
return undefined;
|
|
32
69
|
}
|
|
33
70
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
ttlAutopurge: true,
|
|
41
|
-
updateAgeOnGet: true
|
|
42
|
-
});
|
|
43
|
-
const ensureSenderKeyAndCreateSkdm = async (group, meId) => {
|
|
44
|
-
const senderName = jidToSignalSenderKeyName(group, meId);
|
|
45
|
-
const senderNameStr = senderName.toString();
|
|
46
|
-
const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr]);
|
|
47
|
-
if (!senderKey) {
|
|
48
|
-
await storage.storeSenderKey(senderName, new SenderKeyRecord());
|
|
49
|
-
}
|
|
50
|
-
const skdm = await new GroupSessionBuilder(storage).create(senderName);
|
|
51
|
-
return { senderName, skdm };
|
|
52
|
-
};
|
|
53
|
-
const repository = {
|
|
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,
|
|
54
77
|
decryptGroupMessage({ group, authorJid, msg }) {
|
|
55
78
|
const senderName = jidToSignalSenderKeyName(group, authorJid);
|
|
56
|
-
const cipher = new GroupCipher(storage, senderName);
|
|
57
|
-
//
|
|
58
|
-
|
|
79
|
+
const cipher = new Group_1.GroupCipher(storage, senderName);
|
|
80
|
+
// Dibungkus transaction() biar atomic - konsisten sama operasi Signal
|
|
81
|
+
// lainnya, cegah race condition kalau ada beberapa pesan grup dari
|
|
82
|
+
// sender yang sama numpuk barengan.
|
|
83
|
+
return auth.keys.transaction(async () => {
|
|
59
84
|
return cipher.decrypt(msg);
|
|
60
85
|
}, group);
|
|
61
86
|
},
|
|
62
87
|
async processSenderKeyDistributionMessage({ item, authorJid }) {
|
|
63
|
-
const builder = new GroupSessionBuilder(storage);
|
|
88
|
+
const builder = new Group_1.GroupSessionBuilder(storage);
|
|
64
89
|
if (!item.groupId) {
|
|
65
90
|
throw new Error('Group ID is required for sender key distribution message');
|
|
66
91
|
}
|
|
67
92
|
const senderName = jidToSignalSenderKeyName(item.groupId, authorJid);
|
|
68
|
-
const senderMsg = new SenderKeyDistributionMessage(null, null, null, null, item.axolotlSenderKeyDistributionMessage);
|
|
93
|
+
const senderMsg = new Group_1.SenderKeyDistributionMessage(null, null, null, null, item.axolotlSenderKeyDistributionMessage);
|
|
69
94
|
const senderNameStr = senderName.toString();
|
|
70
|
-
|
|
71
|
-
if (!senderKey) {
|
|
72
|
-
await storage.storeSenderKey(senderName, new SenderKeyRecord());
|
|
73
|
-
}
|
|
74
|
-
return parsedKeys.transaction(async () => {
|
|
95
|
+
return auth.keys.transaction(async () => {
|
|
75
96
|
const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr]);
|
|
76
97
|
if (!senderKey) {
|
|
77
|
-
await storage.storeSenderKey(senderName, new SenderKeyRecord());
|
|
98
|
+
await storage.storeSenderKey(senderName, new sender_key_record_1.SenderKeyRecord());
|
|
78
99
|
}
|
|
79
100
|
await builder.process(senderName, senderMsg);
|
|
80
101
|
}, item.groupId);
|
|
@@ -82,91 +103,80 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
82
103
|
async decryptMessage({ jid, type, ciphertext }) {
|
|
83
104
|
const addr = jidToSignalProtocolAddress(jid);
|
|
84
105
|
const session = new libsignal.SessionCipher(storage, addr);
|
|
85
|
-
//
|
|
106
|
+
// Sebelum decrypt pkmsg (pesan yang buka sesi baru), cek dulu apakah
|
|
107
|
+
// identity key pengirim berubah dibanding yang tersimpan. Kalau iya,
|
|
108
|
+
// sesi lama otomatis direset supaya gak nyoba decrypt pakai sesi basi.
|
|
86
109
|
if (type === 'pkmsg') {
|
|
87
110
|
const identityKey = extractIdentityFromPkmsg(ciphertext);
|
|
88
111
|
if (identityKey) {
|
|
89
112
|
const addrStr = addr.toString();
|
|
90
113
|
const identityChanged = await storage.saveIdentity(addrStr, identityKey);
|
|
91
114
|
if (identityChanged) {
|
|
92
|
-
logger
|
|
115
|
+
logger?.info?.({ jid, addr: addrStr }, 'identity key changed or new contact, session will be re-established');
|
|
93
116
|
}
|
|
94
117
|
}
|
|
95
118
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
119
|
+
try {
|
|
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')
|
|
105
139
|
}
|
|
106
|
-
|
|
140
|
+
throw error
|
|
107
141
|
}
|
|
108
|
-
// If it's not a sync message, we need to ensure atomicity
|
|
109
|
-
// For regular messages, we use a transaction to ensure atomicity
|
|
110
|
-
return parsedKeys.transaction(async () => {
|
|
111
|
-
return await doDecrypt();
|
|
112
|
-
}, jid);
|
|
113
142
|
},
|
|
114
143
|
async encryptMessage({ jid, data }) {
|
|
115
144
|
const addr = jidToSignalProtocolAddress(jid);
|
|
116
145
|
const cipher = new libsignal.SessionCipher(storage, addr);
|
|
117
|
-
|
|
118
|
-
return parsedKeys.transaction(async () => {
|
|
146
|
+
return auth.keys.transaction(async () => {
|
|
119
147
|
const { type: sigType, body } = await cipher.encrypt(data);
|
|
120
148
|
const type = sigType === 3 ? 'pkmsg' : 'msg';
|
|
121
149
|
return { type, ciphertext: Buffer.from(body, 'binary') };
|
|
122
150
|
}, jid);
|
|
123
151
|
},
|
|
124
152
|
async encryptGroupMessage({ group, meId, data }) {
|
|
125
|
-
return
|
|
126
|
-
const
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
|
|
153
|
+
return auth.keys.transaction(async () => {
|
|
154
|
+
const senderName = jidToSignalSenderKeyName(group, meId);
|
|
155
|
+
const builder = new Group_1.GroupSessionBuilder(storage);
|
|
156
|
+
const senderNameStr = senderName.toString();
|
|
157
|
+
const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr]);
|
|
158
|
+
if (!senderKey) {
|
|
159
|
+
await storage.storeSenderKey(senderName, new sender_key_record_1.SenderKeyRecord());
|
|
160
|
+
}
|
|
161
|
+
const senderKeyDistributionMessage = await builder.create(senderName);
|
|
162
|
+
const session = new Group_1.GroupCipher(storage, senderName);
|
|
163
|
+
const ciphertext = await session.encrypt(data);
|
|
164
|
+
return {
|
|
165
|
+
ciphertext,
|
|
166
|
+
senderKeyDistributionMessage: senderKeyDistributionMessage.serialize()
|
|
167
|
+
};
|
|
135
168
|
}, group);
|
|
136
169
|
},
|
|
137
|
-
async hasSenderKey({ group, meId }) {
|
|
138
|
-
const senderName = jidToSignalSenderKeyName(group, meId).toString();
|
|
139
|
-
const { [senderName]: key } = await auth.keys.get('sender-key', [senderName]);
|
|
140
|
-
return !!key;
|
|
141
|
-
},
|
|
142
|
-
async getSessionInfo(jid) {
|
|
143
|
-
const addr = jidToSignalProtocolAddress(jid).toString();
|
|
144
|
-
const session = (await storage.loadSession(addr));
|
|
145
|
-
if (!session) {
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
const open = session.getOpenSession?.();
|
|
149
|
-
const baseKey = open?.indexInfo?.baseKey;
|
|
150
|
-
const registrationId = open?.registrationId;
|
|
151
|
-
if (!baseKey || typeof registrationId !== 'number') {
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
154
|
-
return { baseKey: new Uint8Array(baseKey), registrationId };
|
|
155
|
-
},
|
|
156
170
|
async injectE2ESession({ jid, session }) {
|
|
157
|
-
logger.trace({ jid }, 'injecting E2EE session');
|
|
158
171
|
const cipher = new libsignal.SessionBuilder(storage, jidToSignalProtocolAddress(jid));
|
|
159
|
-
|
|
160
|
-
// libsignal runtime accepts an absent prekey (initOutgoing checks `device.preKey && ...`)
|
|
161
|
-
// but the bundled .d.ts marks it required.
|
|
162
|
-
await cipher.initOutgoing(session);
|
|
163
|
-
}, jid);
|
|
172
|
+
await cipher.initOutgoing(session);
|
|
164
173
|
},
|
|
165
174
|
jidToSignalProtocolAddress(jid) {
|
|
166
175
|
return jidToSignalProtocolAddress(jid).toString();
|
|
167
176
|
},
|
|
168
|
-
//
|
|
169
|
-
|
|
177
|
+
// Dipakai oleh sendRetryRequest (messages-recv.js) untuk enableAutoSessionRecreation.
|
|
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).
|
|
170
180
|
async validateSession(jid) {
|
|
171
181
|
try {
|
|
172
182
|
const addr = jidToSignalProtocolAddress(jid);
|
|
@@ -174,215 +184,60 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
174
184
|
if (!session) {
|
|
175
185
|
return { exists: false, reason: 'no session' };
|
|
176
186
|
}
|
|
177
|
-
if (!session.haveOpenSession()) {
|
|
187
|
+
if (typeof session.haveOpenSession === 'function' && !session.haveOpenSession()) {
|
|
178
188
|
return { exists: false, reason: 'no open session' };
|
|
179
189
|
}
|
|
180
190
|
return { exists: true };
|
|
181
|
-
}
|
|
182
|
-
catch (error) {
|
|
191
|
+
} catch (error) {
|
|
183
192
|
return { exists: false, reason: 'validation error' };
|
|
184
193
|
}
|
|
185
|
-
},
|
|
186
|
-
async deleteSession(jids) {
|
|
187
|
-
if (!jids.length)
|
|
188
|
-
return;
|
|
189
|
-
// Convert JIDs to signal addresses and prepare for bulk deletion
|
|
190
|
-
const sessionUpdates = {};
|
|
191
|
-
jids.forEach(jid => {
|
|
192
|
-
const addr = jidToSignalProtocolAddress(jid);
|
|
193
|
-
sessionUpdates[addr.toString()] = null;
|
|
194
|
-
});
|
|
195
|
-
// Single transaction for all deletions
|
|
196
|
-
return parsedKeys.transaction(async () => {
|
|
197
|
-
await auth.keys.set({ session: sessionUpdates });
|
|
198
|
-
}, `delete-${jids.length}-sessions`);
|
|
199
|
-
},
|
|
200
|
-
close() {
|
|
201
|
-
migratedSessionCache.clear();
|
|
202
|
-
lidMapping.close();
|
|
203
|
-
},
|
|
204
|
-
async migrateSession(fromJid, toJid) {
|
|
205
|
-
// TODO: use usync to handle this entire mess
|
|
206
|
-
if (!fromJid || (!isLidUser(toJid) && !isHostedLidUser(toJid)))
|
|
207
|
-
return { migrated: 0, skipped: 0, total: 0 };
|
|
208
|
-
// Only support PN to LID migration
|
|
209
|
-
if (!isPnUser(fromJid) && !isHostedPnUser(fromJid)) {
|
|
210
|
-
return { migrated: 0, skipped: 0, total: 1 };
|
|
211
|
-
}
|
|
212
|
-
const { user } = jidDecode(fromJid);
|
|
213
|
-
logger.debug({ fromJid }, 'bulk device migration - loading all user devices');
|
|
214
|
-
// Get user's device list from storage
|
|
215
|
-
const { [user]: userDevices } = await parsedKeys.get('device-list', [user]);
|
|
216
|
-
if (!userDevices) {
|
|
217
|
-
return { migrated: 0, skipped: 0, total: 0 };
|
|
218
|
-
}
|
|
219
|
-
const { device: fromDevice } = jidDecode(fromJid);
|
|
220
|
-
const fromDeviceStr = fromDevice?.toString() || '0';
|
|
221
|
-
if (!userDevices.includes(fromDeviceStr)) {
|
|
222
|
-
userDevices.push(fromDeviceStr);
|
|
223
|
-
}
|
|
224
|
-
// Filter out cached devices before database fetch
|
|
225
|
-
const uncachedDevices = userDevices.filter(device => {
|
|
226
|
-
const deviceKey = `${user}.${device}`;
|
|
227
|
-
return !migratedSessionCache.has(deviceKey);
|
|
228
|
-
});
|
|
229
|
-
// Bulk check session existence only for uncached devices
|
|
230
|
-
const deviceSessionKeys = uncachedDevices.map(device => `${user}.${device}`);
|
|
231
|
-
const existingSessions = await parsedKeys.get('session', deviceSessionKeys);
|
|
232
|
-
// Step 3: Convert existing sessions to JIDs (only migrate sessions that exist)
|
|
233
|
-
const deviceJids = [];
|
|
234
|
-
for (const [sessionKey, sessionData] of Object.entries(existingSessions)) {
|
|
235
|
-
if (sessionData) {
|
|
236
|
-
// Session exists in storage
|
|
237
|
-
const deviceStr = sessionKey.split('.')[1];
|
|
238
|
-
if (!deviceStr)
|
|
239
|
-
continue;
|
|
240
|
-
const deviceNum = parseInt(deviceStr);
|
|
241
|
-
let jid = deviceNum === 0 ? `${user}@s.whatsapp.net` : `${user}:${deviceNum}@s.whatsapp.net`;
|
|
242
|
-
if (deviceNum === 99) {
|
|
243
|
-
jid = `${user}:99@hosted`;
|
|
244
|
-
}
|
|
245
|
-
deviceJids.push(jid);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
logger.debug({
|
|
249
|
-
fromJid,
|
|
250
|
-
totalDevices: userDevices.length,
|
|
251
|
-
devicesWithSessions: deviceJids.length,
|
|
252
|
-
devices: deviceJids
|
|
253
|
-
}, 'bulk device migration complete - all user devices processed');
|
|
254
|
-
// Single transaction for all migrations
|
|
255
|
-
return parsedKeys.transaction(async () => {
|
|
256
|
-
const migrationOps = deviceJids.map(jid => {
|
|
257
|
-
const lidWithDevice = transferDevice(jid, toJid);
|
|
258
|
-
const fromDecoded = jidDecode(jid);
|
|
259
|
-
const toDecoded = jidDecode(lidWithDevice);
|
|
260
|
-
return {
|
|
261
|
-
fromJid: jid,
|
|
262
|
-
toJid: lidWithDevice,
|
|
263
|
-
pnUser: fromDecoded.user,
|
|
264
|
-
lidUser: toDecoded.user,
|
|
265
|
-
deviceId: fromDecoded.device || 0,
|
|
266
|
-
fromAddr: jidToSignalProtocolAddress(jid),
|
|
267
|
-
toAddr: jidToSignalProtocolAddress(lidWithDevice)
|
|
268
|
-
};
|
|
269
|
-
});
|
|
270
|
-
const totalOps = migrationOps.length;
|
|
271
|
-
let migratedCount = 0;
|
|
272
|
-
// Bulk fetch PN sessions - already exist (verified during device discovery)
|
|
273
|
-
const pnAddrStrings = Array.from(new Set(migrationOps.map(op => op.fromAddr.toString())));
|
|
274
|
-
const pnSessions = await parsedKeys.get('session', pnAddrStrings);
|
|
275
|
-
// Prepare bulk session updates (PN → LID migration + deletion)
|
|
276
|
-
const sessionUpdates = {};
|
|
277
|
-
for (const op of migrationOps) {
|
|
278
|
-
const pnAddrStr = op.fromAddr.toString();
|
|
279
|
-
const lidAddrStr = op.toAddr.toString();
|
|
280
|
-
const pnSession = pnSessions[pnAddrStr];
|
|
281
|
-
if (pnSession) {
|
|
282
|
-
// Session exists (guaranteed from device discovery)
|
|
283
|
-
const fromSession = libsignal.SessionRecord.deserialize(pnSession);
|
|
284
|
-
if (fromSession.haveOpenSession()) {
|
|
285
|
-
// Queue for bulk update: copy to LID, delete from PN
|
|
286
|
-
sessionUpdates[lidAddrStr] = fromSession.serialize();
|
|
287
|
-
sessionUpdates[pnAddrStr] = null;
|
|
288
|
-
migratedCount++;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
// Single bulk session update for all migrations
|
|
293
|
-
if (Object.keys(sessionUpdates).length > 0) {
|
|
294
|
-
await parsedKeys.set({ session: sessionUpdates });
|
|
295
|
-
logger.debug({ migratedSessions: migratedCount }, 'bulk session migration complete');
|
|
296
|
-
// Cache device-level migrations
|
|
297
|
-
for (const op of migrationOps) {
|
|
298
|
-
if (sessionUpdates[op.toAddr.toString()]) {
|
|
299
|
-
const deviceKey = `${op.pnUser}.${op.deviceId}`;
|
|
300
|
-
migratedSessionCache.set(deviceKey, true);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
const skippedCount = totalOps - migratedCount;
|
|
305
|
-
return { migrated: migratedCount, skipped: skippedCount, total: totalOps };
|
|
306
|
-
}, `migrate-${deviceJids.length}-sessions-${jidDecode(toJid)?.user}`);
|
|
307
194
|
}
|
|
308
195
|
};
|
|
309
|
-
return repository;
|
|
310
196
|
}
|
|
311
197
|
const jidToSignalProtocolAddress = (jid) => {
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
if (!user) {
|
|
315
|
-
throw new Error(`JID decoded but user is empty: "${jid}" -> user: "${user}", server: "${server}", device: ${device}`);
|
|
316
|
-
}
|
|
317
|
-
const signalUser = domainType !== WAJIDDomains.WHATSAPP ? `${user}_${domainType}` : user;
|
|
318
|
-
const finalDevice = device || 0;
|
|
319
|
-
if (device === 99 && decoded.server !== 'hosted' && decoded.server !== 'hosted.lid') {
|
|
320
|
-
throw new Error('Unexpected non-hosted device JID with device 99. This ID seems invalid. ID:' + jid);
|
|
321
|
-
}
|
|
322
|
-
return new libsignal.ProtocolAddress(signalUser, finalDevice);
|
|
198
|
+
const { user, device } = (0, WABinary_1.jidDecode)(jid);
|
|
199
|
+
return new libsignal.ProtocolAddress(user, device || 0);
|
|
323
200
|
};
|
|
324
201
|
const jidToSignalSenderKeyName = (group, user) => {
|
|
325
|
-
return new SenderKeyName(group, jidToSignalProtocolAddress(user));
|
|
202
|
+
return new sender_key_name_1.SenderKeyName(group, jidToSignalProtocolAddress(user));
|
|
326
203
|
};
|
|
327
|
-
function signalStorage({ creds, keys }
|
|
328
|
-
// Shared function to resolve PN signal address to LID if mapping exists
|
|
329
|
-
const resolveLIDSignalAddress = async (id) => {
|
|
330
|
-
if (id.includes('.')) {
|
|
331
|
-
const [deviceId, device] = id.split('.');
|
|
332
|
-
const [user, domainType_] = deviceId.split('_');
|
|
333
|
-
const domainType = parseInt(domainType_ || '0');
|
|
334
|
-
if (domainType === WAJIDDomains.LID || domainType === WAJIDDomains.HOSTED_LID)
|
|
335
|
-
return id;
|
|
336
|
-
const pnJid = `${user}${device !== '0' ? `:${device}` : ''}@${domainType === WAJIDDomains.HOSTED ? 'hosted' : 's.whatsapp.net'}`;
|
|
337
|
-
const lidForPN = await lidMapping.getLIDForPN(pnJid);
|
|
338
|
-
if (lidForPN) {
|
|
339
|
-
const lidAddr = jidToSignalProtocolAddress(lidForPN);
|
|
340
|
-
return lidAddr.toString();
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
return id;
|
|
344
|
-
};
|
|
204
|
+
function signalStorage({ creds, keys }) {
|
|
345
205
|
return {
|
|
346
206
|
loadSession: async (id) => {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
if (sess) {
|
|
351
|
-
return libsignal.SessionRecord.deserialize(sess);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
catch (e) {
|
|
355
|
-
return null;
|
|
207
|
+
const { [id]: sess } = await keys.get('session', [id]);
|
|
208
|
+
if (sess) {
|
|
209
|
+
return libsignal.SessionRecord.deserialize(sess);
|
|
356
210
|
}
|
|
357
|
-
return null;
|
|
358
211
|
},
|
|
359
212
|
storeSession: async (id, session) => {
|
|
360
|
-
|
|
361
|
-
|
|
213
|
+
await keys.set({ session: { [id]: session.serialize() } });
|
|
214
|
+
},
|
|
215
|
+
removeSession: async (id) => {
|
|
216
|
+
await keys.set({ session: { [id]: null } });
|
|
362
217
|
},
|
|
363
218
|
isTrustedIdentity: () => {
|
|
364
|
-
return true;
|
|
219
|
+
return true;
|
|
365
220
|
},
|
|
366
221
|
loadIdentityKey: async (id) => {
|
|
367
|
-
const
|
|
368
|
-
const { [wireJid]: key } = await keys.get('identity-key', [wireJid]);
|
|
222
|
+
const { [id]: key } = await keys.get('identity-key', [id]);
|
|
369
223
|
return key || undefined;
|
|
370
224
|
},
|
|
371
225
|
saveIdentity: async (id, identityKey) => {
|
|
372
|
-
const
|
|
373
|
-
const
|
|
374
|
-
|
|
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;
|
|
375
229
|
if (existingKey && !keysMatch) {
|
|
376
|
-
// Identity
|
|
230
|
+
// Identity berubah - hapus sesi lama (bakal ke-generate ulang dari
|
|
231
|
+
// pkmsg yang lagi diproses) dan simpan identity key yang baru.
|
|
377
232
|
await keys.set({
|
|
378
|
-
session: { [
|
|
379
|
-
'identity-key': { [
|
|
233
|
+
session: { [id]: null },
|
|
234
|
+
'identity-key': { [id]: identityKey }
|
|
380
235
|
});
|
|
381
236
|
return true;
|
|
382
237
|
}
|
|
383
238
|
if (!existingKey) {
|
|
384
|
-
//
|
|
385
|
-
await keys.set({ 'identity-key': { [
|
|
239
|
+
// Kontak baru - Trust On First Use (TOFU), sama kayak WhatsApp Web.
|
|
240
|
+
await keys.set({ 'identity-key': { [id]: identityKey } });
|
|
386
241
|
return true;
|
|
387
242
|
}
|
|
388
243
|
return false;
|
|
@@ -409,9 +264,9 @@ function signalStorage({ creds, keys }, lidMapping) {
|
|
|
409
264
|
const keyId = senderKeyName.toString();
|
|
410
265
|
const { [keyId]: key } = await keys.get('sender-key', [keyId]);
|
|
411
266
|
if (key) {
|
|
412
|
-
return SenderKeyRecord.deserialize(key);
|
|
267
|
+
return sender_key_record_1.SenderKeyRecord.deserialize(key);
|
|
413
268
|
}
|
|
414
|
-
return new SenderKeyRecord();
|
|
269
|
+
return new sender_key_record_1.SenderKeyRecord();
|
|
415
270
|
},
|
|
416
271
|
storeSenderKey: async (senderKeyName, key) => {
|
|
417
272
|
const keyId = senderKeyName.toString();
|
|
@@ -423,9 +278,8 @@ function signalStorage({ creds, keys }, lidMapping) {
|
|
|
423
278
|
const { signedIdentityKey } = creds;
|
|
424
279
|
return {
|
|
425
280
|
privKey: Buffer.from(signedIdentityKey.private),
|
|
426
|
-
pubKey:
|
|
281
|
+
pubKey: (0, Utils_1.generateSignalPubKey)(signedIdentityKey.public)
|
|
427
282
|
};
|
|
428
283
|
}
|
|
429
284
|
};
|
|
430
285
|
}
|
|
431
|
-
//# sourceMappingURL=libsignal.js.map
|