@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/Utils/signal.js
CHANGED
|
@@ -1,166 +1,183 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const { KEY_BUNDLE_TYPE: KEY_BUNDLE_TYPE } = require("../Defaults/constants");
|
|
4
|
+
const {
|
|
5
|
+
S_WHATSAPP_NET: S_WHATSAPP_NET,
|
|
6
|
+
getBinaryNodeChild: getBinaryNodeChild,
|
|
7
|
+
getBinaryNodeChildren: getBinaryNodeChildren,
|
|
8
|
+
getBinaryNodeChildUInt: getBinaryNodeChildUInt,
|
|
9
|
+
getBinaryNodeChildBuffer: getBinaryNodeChildBuffer,
|
|
10
|
+
assertNodeErrorFree: assertNodeErrorFree,
|
|
11
|
+
jidDecode: jidDecode,
|
|
12
|
+
getServerFromDomainType: getServerFromDomainType,
|
|
13
|
+
WAJIDDomains: WAJIDDomains,
|
|
14
|
+
} = require("../WABinary");
|
|
15
|
+
const { Curve: Curve, generateSignalPubKey: generateSignalPubKey } = require("./crypto");
|
|
16
|
+
const { encodeBigEndian: encodeBigEndian } = require("./generics");
|
|
17
|
+
function chunk(array, size) {
|
|
18
|
+
const chunks = [];
|
|
19
|
+
for (let i = 0; i < array.length; i += size) {
|
|
20
|
+
chunks.push(array.slice(i, i + size));
|
|
15
21
|
}
|
|
22
|
+
return chunks;
|
|
16
23
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
const createSignalIdentity = (wid, accountSignatureKey) => ({
|
|
25
|
+
identifier: { name: wid, deviceId: 0 },
|
|
26
|
+
identifierKey: generateSignalPubKey(accountSignatureKey),
|
|
27
|
+
});
|
|
28
|
+
const getPreKeys = async ({ get: get }, min, limit) => {
|
|
29
|
+
const idList = [];
|
|
20
30
|
for (let id = min; id < limit; id++) {
|
|
21
|
-
idList.push(id.toString())
|
|
31
|
+
idList.push(id.toString());
|
|
22
32
|
}
|
|
23
|
-
return get(
|
|
24
|
-
}
|
|
25
|
-
|
|
33
|
+
return get("pre-key", idList);
|
|
34
|
+
};
|
|
26
35
|
const generateOrGetPreKeys = (creds, range) => {
|
|
27
|
-
const avaliable = creds.nextPreKeyId - creds.firstUnuploadedPreKeyId
|
|
28
|
-
const remaining = range - avaliable
|
|
29
|
-
const lastPreKeyId = creds.nextPreKeyId + remaining - 1
|
|
30
|
-
const newPreKeys = {}
|
|
36
|
+
const avaliable = creds.nextPreKeyId - creds.firstUnuploadedPreKeyId;
|
|
37
|
+
const remaining = range - avaliable;
|
|
38
|
+
const lastPreKeyId = creds.nextPreKeyId + remaining - 1;
|
|
39
|
+
const newPreKeys = {};
|
|
31
40
|
if (remaining > 0) {
|
|
32
41
|
for (let i = creds.nextPreKeyId; i <= lastPreKeyId; i++) {
|
|
33
|
-
newPreKeys[i] =
|
|
42
|
+
newPreKeys[i] = Curve.generateKeyPair();
|
|
34
43
|
}
|
|
35
44
|
}
|
|
36
45
|
return {
|
|
37
|
-
newPreKeys,
|
|
38
|
-
lastPreKeyId,
|
|
46
|
+
newPreKeys: newPreKeys,
|
|
47
|
+
lastPreKeyId: lastPreKeyId,
|
|
39
48
|
preKeysRange: [creds.firstUnuploadedPreKeyId, range],
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
49
|
+
};
|
|
50
|
+
};
|
|
43
51
|
const xmppSignedPreKey = (key) => ({
|
|
44
|
-
tag:
|
|
52
|
+
tag: "skey",
|
|
45
53
|
attrs: {},
|
|
46
54
|
content: [
|
|
47
|
-
{ tag:
|
|
48
|
-
{ tag:
|
|
49
|
-
{ tag:
|
|
50
|
-
]
|
|
51
|
-
})
|
|
52
|
-
|
|
55
|
+
{ tag: "id", attrs: {}, content: encodeBigEndian(key.keyId, 3) },
|
|
56
|
+
{ tag: "value", attrs: {}, content: key.keyPair.public },
|
|
57
|
+
{ tag: "signature", attrs: {}, content: key.signature },
|
|
58
|
+
],
|
|
59
|
+
});
|
|
53
60
|
const xmppPreKey = (pair, id) => ({
|
|
54
|
-
tag:
|
|
61
|
+
tag: "key",
|
|
55
62
|
attrs: {},
|
|
56
63
|
content: [
|
|
57
|
-
{ tag:
|
|
58
|
-
{ tag:
|
|
59
|
-
]
|
|
60
|
-
})
|
|
61
|
-
|
|
64
|
+
{ tag: "id", attrs: {}, content: encodeBigEndian(id, 3) },
|
|
65
|
+
{ tag: "value", attrs: {}, content: pair.public },
|
|
66
|
+
],
|
|
67
|
+
});
|
|
62
68
|
const parseAndInjectE2ESessions = async (node, repository) => {
|
|
63
|
-
const extractKey = (key) =>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
const extractKey = (key) =>
|
|
70
|
+
key
|
|
71
|
+
? {
|
|
72
|
+
keyId: getBinaryNodeChildUInt(key, "id", 3),
|
|
73
|
+
publicKey: generateSignalPubKey(getBinaryNodeChildBuffer(key, "value")),
|
|
74
|
+
signature: getBinaryNodeChildBuffer(key, "signature"),
|
|
75
|
+
}
|
|
76
|
+
: undefined;
|
|
77
|
+
const nodes = getBinaryNodeChildren(getBinaryNodeChild(node, "list"), "user");
|
|
69
78
|
for (const node of nodes) {
|
|
70
|
-
|
|
79
|
+
assertNodeErrorFree(node);
|
|
71
80
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// but blocks even loop if we're using it inside keys.transaction, and it makes it "sync" actually
|
|
75
|
-
// This way we chunk it in smaller parts and between those parts we can yield to the event loop
|
|
76
|
-
// It's rare case when you need to E2E sessions for so many users, but it's possible
|
|
77
|
-
const chunkSize = 100
|
|
78
|
-
const chunks = lodash_1.chunk(nodes, chunkSize)
|
|
81
|
+
const chunkSize = 100;
|
|
82
|
+
const chunks = chunk(nodes, chunkSize);
|
|
79
83
|
for (const nodesChunk of chunks) {
|
|
80
|
-
|
|
81
|
-
const signedKey =
|
|
82
|
-
const key =
|
|
83
|
-
const identity =
|
|
84
|
-
const jid = node.attrs.jid
|
|
85
|
-
const registrationId =
|
|
84
|
+
for (const node of nodesChunk) {
|
|
85
|
+
const signedKey = getBinaryNodeChild(node, "skey");
|
|
86
|
+
const key = getBinaryNodeChild(node, "key");
|
|
87
|
+
const identity = getBinaryNodeChildBuffer(node, "identity");
|
|
88
|
+
const jid = node.attrs.jid;
|
|
89
|
+
const registrationId = getBinaryNodeChildUInt(node, "registration", 4);
|
|
86
90
|
await repository.injectE2ESession({
|
|
87
|
-
jid,
|
|
91
|
+
jid: jid,
|
|
88
92
|
session: {
|
|
89
93
|
registrationId: registrationId,
|
|
90
|
-
identityKey:
|
|
94
|
+
identityKey: generateSignalPubKey(identity),
|
|
91
95
|
signedPreKey: extractKey(signedKey),
|
|
92
|
-
preKey: extractKey(key)
|
|
93
|
-
}
|
|
94
|
-
})
|
|
95
|
-
}
|
|
96
|
+
preKey: extractKey(key),
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
96
100
|
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
const extracted = []
|
|
101
|
+
};
|
|
102
|
+
const extractDeviceJids = (result, myJid, myLid, excludeZeroDevices) => {
|
|
103
|
+
const { user: myUser, device: myDevice } = jidDecode(myJid);
|
|
104
|
+
const extracted = [];
|
|
102
105
|
for (const userResult of result) {
|
|
103
|
-
const { devices, id } = userResult
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
|
|
106
|
+
const { devices: devices, id: id } = userResult;
|
|
107
|
+
const decoded = jidDecode(id),
|
|
108
|
+
{ user: user, server: server } = decoded;
|
|
109
|
+
let { domainType: domainType } = decoded;
|
|
110
|
+
const deviceList = devices?.deviceList;
|
|
111
|
+
if (!Array.isArray(deviceList)) continue;
|
|
112
|
+
for (const { id: device, keyIndex: keyIndex, isHosted: isHosted } of deviceList) {
|
|
113
|
+
if (
|
|
114
|
+
(!excludeZeroDevices || device !== 0) &&
|
|
115
|
+
((myUser !== user && myLid !== user) || myDevice !== device) &&
|
|
116
|
+
(device === 0 || !!keyIndex)
|
|
117
|
+
) {
|
|
118
|
+
if (isHosted) {
|
|
119
|
+
domainType =
|
|
120
|
+
domainType === WAJIDDomains.LID
|
|
121
|
+
? WAJIDDomains.HOSTED_LID
|
|
122
|
+
: WAJIDDomains.HOSTED;
|
|
113
123
|
}
|
|
124
|
+
extracted.push({
|
|
125
|
+
user: user,
|
|
126
|
+
device: device,
|
|
127
|
+
domainType: domainType,
|
|
128
|
+
server: getServerFromDomainType(server, domainType),
|
|
129
|
+
});
|
|
114
130
|
}
|
|
115
131
|
}
|
|
116
132
|
}
|
|
117
|
-
return extracted
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const { newPreKeys, lastPreKeyId, preKeysRange } = generateOrGetPreKeys(creds, count)
|
|
133
|
+
return extracted;
|
|
134
|
+
};
|
|
135
|
+
const getNextPreKeys = async ({ creds: creds, keys: keys }, count) => {
|
|
136
|
+
const {
|
|
137
|
+
newPreKeys: newPreKeys,
|
|
138
|
+
lastPreKeyId: lastPreKeyId,
|
|
139
|
+
preKeysRange: preKeysRange,
|
|
140
|
+
} = generateOrGetPreKeys(creds, count);
|
|
126
141
|
const update = {
|
|
127
142
|
nextPreKeyId: Math.max(lastPreKeyId + 1, creds.nextPreKeyId),
|
|
128
|
-
firstUnuploadedPreKeyId: Math.max(creds.firstUnuploadedPreKeyId, lastPreKeyId + 1)
|
|
129
|
-
}
|
|
130
|
-
await keys.set({
|
|
131
|
-
const preKeys = await getPreKeys(keys, preKeysRange[0], preKeysRange[0] + preKeysRange[1])
|
|
132
|
-
return { update, preKeys }
|
|
133
|
-
}
|
|
134
|
-
|
|
143
|
+
firstUnuploadedPreKeyId: Math.max(creds.firstUnuploadedPreKeyId, lastPreKeyId + 1),
|
|
144
|
+
};
|
|
145
|
+
await keys.set({ "pre-key": newPreKeys });
|
|
146
|
+
const preKeys = await getPreKeys(keys, preKeysRange[0], preKeysRange[0] + preKeysRange[1]);
|
|
147
|
+
return { update: update, preKeys: preKeys };
|
|
148
|
+
};
|
|
135
149
|
const getNextPreKeysNode = async (state, count) => {
|
|
136
|
-
const { creds } = state
|
|
137
|
-
const { update, preKeys } = await getNextPreKeys(state, count)
|
|
150
|
+
const { creds: creds } = state;
|
|
151
|
+
const { update: update, preKeys: preKeys } = await getNextPreKeys(state, count);
|
|
138
152
|
const node = {
|
|
139
|
-
tag:
|
|
140
|
-
attrs: {
|
|
141
|
-
xmlns: 'encrypt',
|
|
142
|
-
type: 'set',
|
|
143
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
144
|
-
},
|
|
153
|
+
tag: "iq",
|
|
154
|
+
attrs: { xmlns: "encrypt", type: "set", to: S_WHATSAPP_NET },
|
|
145
155
|
content: [
|
|
146
|
-
{
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
+
{
|
|
157
|
+
tag: "registration",
|
|
158
|
+
attrs: {},
|
|
159
|
+
content: encodeBigEndian(creds.registrationId),
|
|
160
|
+
},
|
|
161
|
+
{ tag: "type", attrs: {}, content: KEY_BUNDLE_TYPE },
|
|
162
|
+
{ tag: "identity", attrs: {}, content: creds.signedIdentityKey.public },
|
|
163
|
+
{
|
|
164
|
+
tag: "list",
|
|
165
|
+
attrs: {},
|
|
166
|
+
content: Object.keys(preKeys).map((k) => xmppPreKey(preKeys[+k], +k)),
|
|
167
|
+
},
|
|
168
|
+
xmppSignedPreKey(creds.signedPreKey),
|
|
169
|
+
],
|
|
170
|
+
};
|
|
171
|
+
return { update: update, node: node };
|
|
172
|
+
};
|
|
156
173
|
module.exports = {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
174
|
+
createSignalIdentity: createSignalIdentity,
|
|
175
|
+
getPreKeys: getPreKeys,
|
|
176
|
+
generateOrGetPreKeys: generateOrGetPreKeys,
|
|
177
|
+
xmppSignedPreKey: xmppSignedPreKey,
|
|
178
|
+
xmppPreKey: xmppPreKey,
|
|
179
|
+
parseAndInjectE2ESessions: parseAndInjectE2ESessions,
|
|
180
|
+
extractDeviceJids: extractDeviceJids,
|
|
181
|
+
getNextPreKeys: getNextPreKeys,
|
|
182
|
+
getNextPreKeysNode: getNextPreKeysNode,
|
|
183
|
+
};
|
|
@@ -1,171 +1,104 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const promises_1 = require("fs/promises")
|
|
11
|
-
const { rename: fsRename } = promises_1
|
|
12
|
-
const path_1 = require("path")
|
|
13
|
-
const WAProto_1 = require("../../WAProto")
|
|
14
|
-
const auth_utils_1 = require("./auth-utils")
|
|
15
|
-
const generics_1 = require("./generics")
|
|
16
|
-
// We need to lock files due to the fact that we are using async functions to read and write files
|
|
17
|
-
// https://github.com/WhiskeySockets/Baileys/issues/794
|
|
18
|
-
// https://github.com/nodejs/node/issues/26338
|
|
19
|
-
// Use a Map to store mutexes for each file path
|
|
20
|
-
const fileLocks = new Map()
|
|
21
|
-
|
|
22
|
-
// Get or create a mutex for a specific file path
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const { Mutex: Mutex } = require("async-mutex");
|
|
4
|
+
const { promises: promises } = require("fs");
|
|
5
|
+
const { join: join } = require("path");
|
|
6
|
+
const { proto: proto } = require("../../WAProto");
|
|
7
|
+
const { initAuthCreds: initAuthCreds } = require("./auth-utils");
|
|
8
|
+
const { BufferJSON: BufferJSON } = require("./generics");
|
|
9
|
+
const fileLocks = new Map();
|
|
23
10
|
const getFileLock = (path) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Lepas mutex dari Map begitu tidak dipakai lagi supaya tidak numpuk terus (memory leak)
|
|
34
|
-
// selama proses hidup lama (bot jalan berbulan-bulan dengan ribuan file sesi berbeda).
|
|
35
|
-
const releaseFileLock = (path) => {
|
|
36
|
-
fileLocks.delete(path)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* stores the full authentication state in a single folder.
|
|
41
|
-
* Far more efficient than singlefileauthstate
|
|
42
|
-
*
|
|
43
|
-
* Again, I wouldn't endorse this for any production level use other than perhaps a bot.
|
|
44
|
-
* Would recommend writing an auth state for use with a proper SQL or No-SQL DB
|
|
45
|
-
* */
|
|
11
|
+
let mutex = fileLocks.get(path);
|
|
12
|
+
if (!mutex) {
|
|
13
|
+
mutex = new Mutex();
|
|
14
|
+
fileLocks.set(path, mutex);
|
|
15
|
+
}
|
|
16
|
+
return mutex;
|
|
17
|
+
};
|
|
46
18
|
const useMultiFileAuthState = async (folder) => {
|
|
47
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
48
19
|
const writeData = async (data, file) => {
|
|
49
|
-
const filePath =
|
|
50
|
-
const mutex = getFileLock(filePath)
|
|
20
|
+
const filePath = join(folder, fixFileName(file));
|
|
21
|
+
const mutex = getFileLock(filePath);
|
|
51
22
|
return mutex.acquire().then(async (release) => {
|
|
52
23
|
try {
|
|
53
|
-
|
|
54
|
-
// kebaca dalam kondisi setengah tertulis kalau proses mati di tengah jalan.
|
|
55
|
-
const tmpPath = filePath + '.tmp'
|
|
56
|
-
await promises_1.writeFile(tmpPath, JSON.stringify(data, generics_1.BufferJSON.replacer))
|
|
57
|
-
await fsRename(tmpPath, filePath)
|
|
24
|
+
await promises.writeFile(filePath, JSON.stringify(data, BufferJSON.replacer));
|
|
58
25
|
} finally {
|
|
59
|
-
release()
|
|
60
|
-
releaseFileLock(filePath)
|
|
26
|
+
release();
|
|
61
27
|
}
|
|
62
|
-
})
|
|
63
|
-
}
|
|
28
|
+
});
|
|
29
|
+
};
|
|
64
30
|
const readData = async (file) => {
|
|
65
|
-
const filePath = path_1.join(folder, fixFileName(file))
|
|
66
31
|
try {
|
|
67
|
-
const
|
|
32
|
+
const filePath = join(folder, fixFileName(file));
|
|
33
|
+
const mutex = getFileLock(filePath);
|
|
68
34
|
const data = await mutex.acquire().then(async (release) => {
|
|
69
35
|
try {
|
|
70
|
-
return await
|
|
36
|
+
return await promises.readFile(filePath, { encoding: "utf-8" });
|
|
71
37
|
} finally {
|
|
72
|
-
release()
|
|
73
|
-
releaseFileLock(filePath)
|
|
38
|
+
release();
|
|
74
39
|
}
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
return JSON.parse(data, generics_1.BufferJSON.reviver)
|
|
40
|
+
});
|
|
41
|
+
return JSON.parse(data, BufferJSON.reviver);
|
|
78
42
|
} catch (error) {
|
|
79
|
-
|
|
80
|
-
// gagal) itu wajib kelihatan di log, bukan diam-diam dianggap "null"/hilang.
|
|
81
|
-
if (error?.code !== 'ENOENT') {
|
|
82
|
-
console.warn(`[useMultiFileAuthState] Gagal membaca/parse ${filePath}:`, error?.message || error)
|
|
83
|
-
}
|
|
84
|
-
return null
|
|
43
|
+
return null;
|
|
85
44
|
}
|
|
86
|
-
}
|
|
45
|
+
};
|
|
87
46
|
const removeData = async (file) => {
|
|
88
|
-
const filePath = path_1.join(folder, fixFileName(file))
|
|
89
47
|
try {
|
|
90
|
-
const
|
|
48
|
+
const filePath = join(folder, fixFileName(file));
|
|
49
|
+
const mutex = getFileLock(filePath);
|
|
91
50
|
await mutex.acquire().then(async (release) => {
|
|
92
|
-
|
|
93
|
-
await
|
|
51
|
+
try {
|
|
52
|
+
await promises.unlink(filePath);
|
|
94
53
|
} finally {
|
|
95
|
-
release()
|
|
96
|
-
releaseFileLock(filePath)
|
|
54
|
+
release();
|
|
97
55
|
}
|
|
98
|
-
})
|
|
56
|
+
});
|
|
99
57
|
} catch {}
|
|
100
|
-
}
|
|
101
|
-
const folderInfo = await
|
|
58
|
+
};
|
|
59
|
+
const folderInfo = await promises.stat(folder).catch(() => {});
|
|
102
60
|
if (folderInfo) {
|
|
103
61
|
if (!folderInfo.isDirectory()) {
|
|
104
|
-
throw new Error(
|
|
62
|
+
throw new Error(
|
|
63
|
+
`found something that is not a directory at ${folder}, either delete it or specify a different location`
|
|
64
|
+
);
|
|
105
65
|
}
|
|
66
|
+
} else {
|
|
67
|
+
await promises.mkdir(folder, { recursive: true });
|
|
106
68
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
const fixFileName = (file) => {
|
|
111
|
-
return file?.replace(/\//g, '__')?.replace(/:/g, '-')
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Bersihkan file .tmp "yatim" yang tertinggal dari proses sebelumnya yang mati
|
|
115
|
-
// di tengah proses rename (atomic write). File-file ini tidak berguna dan kalau
|
|
116
|
-
// dibiarkan menumpuk, cuma buang-buang disk.
|
|
117
|
-
try {
|
|
118
|
-
const entries = await promises_1.readdir(folder)
|
|
119
|
-
await Promise.all(
|
|
120
|
-
entries
|
|
121
|
-
.filter((name) => name.endsWith('.tmp'))
|
|
122
|
-
.map((name) => promises_1.unlink(path_1.join(folder, name)).catch(() => {}))
|
|
123
|
-
)
|
|
124
|
-
} catch {}
|
|
125
|
-
|
|
126
|
-
const creds = await readData('creds.json') || auth_utils_1.initAuthCreds()
|
|
69
|
+
const fixFileName = (file) => file?.replace(/\//g, "__")?.replace(/:/g, "-");
|
|
70
|
+
const creds = (await readData("creds.json")) || initAuthCreds();
|
|
127
71
|
return {
|
|
128
72
|
state: {
|
|
129
|
-
creds,
|
|
73
|
+
creds: creds,
|
|
130
74
|
keys: {
|
|
131
75
|
get: async (type, ids) => {
|
|
132
|
-
const data = {}
|
|
133
|
-
await Promise.all(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
76
|
+
const data = {};
|
|
77
|
+
await Promise.all(
|
|
78
|
+
ids.map(async (id) => {
|
|
79
|
+
let value = await readData(`${type}-${id}.json`);
|
|
80
|
+
if (type === "app-state-sync-key" && value) {
|
|
81
|
+
value = proto.Message.AppStateSyncKeyData.fromObject(value);
|
|
82
|
+
}
|
|
83
|
+
data[id] = value;
|
|
84
|
+
})
|
|
85
|
+
);
|
|
86
|
+
return data;
|
|
141
87
|
},
|
|
142
88
|
set: async (data) => {
|
|
143
|
-
const tasks = []
|
|
89
|
+
const tasks = [];
|
|
144
90
|
for (const category in data) {
|
|
145
91
|
for (const id in data[category]) {
|
|
146
|
-
const value = data[category][id]
|
|
147
|
-
const file = `${category}-${id}.json
|
|
148
|
-
tasks.push(value ? writeData(value, file) : removeData(file))
|
|
92
|
+
const value = data[category][id];
|
|
93
|
+
const file = `${category}-${id}.json`;
|
|
94
|
+
tasks.push(value ? writeData(value, file) : removeData(file));
|
|
149
95
|
}
|
|
150
96
|
}
|
|
151
|
-
await Promise.all(tasks)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
// saveCreds sekarang selalu langsung menulis (tidak didebounce). creds.json adalah
|
|
156
|
-
// file paling kritis — kalau proses mati tepat di jendela debounce, sesi bisa hilang
|
|
157
|
-
// atau balik ke state lama sehingga semua pesan gagal didekripsi setelah reconnect.
|
|
158
|
-
saveCreds: async () => {
|
|
159
|
-
return writeData(creds, 'creds.json')
|
|
97
|
+
await Promise.all(tasks);
|
|
98
|
+
},
|
|
99
|
+
},
|
|
160
100
|
},
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
module.exports = {
|
|
170
|
-
useMultiFileAuthState
|
|
171
|
-
}
|
|
101
|
+
saveCreds: async () => writeData(creds, "creds.json"),
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
module.exports = { useMultiFileAuthState: useMultiFileAuthState };
|